Linux Kernel 调度实现 -----欣赏

通常, 那些最有突破性和最有创新力的解决方案来自于你认识到你对问题的基本观念是错的

                                                                            --- <<大教堂与集市>>

一 : 进程状态

这里写图片描述

7 种状态中,调度器只会调度TASK_RUNNING状态的进程,其余状态的进程靠边站,
专注的关键是敢于舍弃 !

TASK_RUNNING命名不清,除去正在使用cpu的,剩下的是可以运行的,调度器调度的就是这些处于可运行状态的进程
看源码:


void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
{
    unsigned long flags;
    /*
        设置了该进程的状态为 可运行.这样才会被调度器青睐,才有运行的机会呀.
        否则,King 直接略过 都懒得瞅你一眼! 
    */
    __set_current_state(TASK_RUNNING);
    ....
}

#define __wait_event(wq, condition)
{
    do {
            /*
                霸王状态! 致命信号都杀不死,N 13 了!
                如果一直都不满足,你只有重启Linux了,你能奈他何!
                嘿嘿,这里可以做很多事情哦,....... 

                即使 是khungtaskd 检测到 , 也只能打印信息告诉你,也无药可救!
                可以参考下面 图a0 

                那么,问题来了 : 
                    TASK_UNINTERRUPTIBLE 必须存在的意义是什么,是合理的吗 ? 

                    存在即合理?我思故我在? 都是瞎扯!
                    但是 既然存在,那么一定是有原因的,是吧, 即不能被信号打断,什么场景下进程不能被打断,你想想吧
            */
            prepare_to_wait(..,TASK_UNINTERRUPTIBLE)
            {
                ....
                /*
                    别想有机会运行了! 除非有人改变你的状态来救你,比如 等待的xx来了
                    类似被 King 打入冷宫了,哈哈哈 ! 即将从cpu的运行队列中移除.
                */
                set_current_state(state);
            }               
            ....            
    } while (0)
}

看下这个进程的状态

/**
    TASK_KILLABLE.
    这种状态的进程也会睡眠在等待队列上,
    一条等待队列上究竟能有多包容,不同状态的、不同权重比的、不同类型的、不同虚拟运行时间的,还有醒来后不可能在本cpu上运行的.....
    统统都能糅合在一起 ...  我看是作者太自信!

*/
#define wait_event_killable(wq, condition)              
({                                  
    int __ret = 0;                          
    if (!(condition))                       
        __wait_event_killable(wq, condition, __ret);        
    __ret;                              
})

#define __wait_event_killable(wq, condition, ret)
do {                
        /**
            会设置该进程为这种状态 TASK_KILLABLE
        */          
        prepare_to_wait(&wq, &__wait, TASK_KILLABLE);                               
    }                               
    finish_wait(&wq, &__wait);                  
} while (0)
前面说过,有睡眠就有唤醒,好吧,那么下面讨论一下 : 
致命信号是如何将TASK_KILLABLE状态的进程唤醒的

那么你首先要明白 进程是怎么响应信号的,

可以参考下面
http://blog.csdn.net/leesagacious/article/details/50198793

状态这块先放放吧 ….

如果你想要弄一个调度器,那么你首先实现这些函数,对这些调度类函数进行拿来主义!
大教堂与集市说 : 你可以复制一切,但是却复制不了思想,你辛苦偷窃,却永远落后一年半载
青出于蓝的东西 很少 是吧 ?

这里写图片描述

看下面的初始化流程

start_kernel()
{
    ....
    /*
        构建基础设施.资源少,自己动手初始化干吧,哈哈!
        uboot一上来才真叫一穷二白,不初始化DDR,内存都没有!
        搬到内存中,怎么弄,kernel你自己看着办吧.一棵鸡蛋从内部解压打破 开始裂变了
    */
    mm_init();
    sched_init();
    {
        .....
        /**
            看看这个 for循环,里面初始化一个运行队列
            现在看到了什么是每一个cpu都有自己的运行队列了吧,注意,这里只是讨论CFS,
        */
        for_each_possible_cpu(i) {
            /*
                这个nr_running 真的很重要 !
            */
            rq->nr_running = 0;
            ....
            /*
                其实就是初始化一棵 红黑树,
                以后会往这棵树上 添加节点(sched_entriy)、删除节点之类的,
                CFS 就是rb tree的复杂操作!
            */
            init_cfs_rq(&rq->cfs);
            {
                cfs_rq->tasks_timeline = RB_ROOT;
                cfs_rq->min_vruntime = (u64)(-(1LL << 20));
            }
        }
    }
    init_IRQ();
    softirq_init();
}

好吧,就实现一个最简单的调度器吧,嘿嘿,这个真的是 一直要模仿,真的不能超越了,
先别搞这么复杂,先来一个简单的二叉树吧,

先写个空的框架吧,
github:
https://github.com/leesagacious/Spring/blob/master/binary_tree_scheduler.c

猜你喜欢

转载自blog.csdn.net/leesagacious/article/details/73694822