📄 sched.c.txt
字号:
netxiong@263.net
***************基本的数据结构********************************
(1):struct task_struct * init_tasks[NR_CPUS] = {&init_task, }
所有进程的最初进程。
(2):static LIST_HEAD(runqueue_head);
声明可运行队列的头指针。
**************************************************************
********和/include/linux/sched.h中相对应得唤醒函数***************************
(1):void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr)
锁定等待队列,然后调用__wake_up_common(q, mode, nr, 0)(本文件中)。
(2):static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, const int sync)
这个函数的作用就是从等待队列q中取出第一个等待的进程,试图把他唤醒。
先做一系列的检查,如魔数,列表是否为空等。
然后对等待队列进行遍历。while (tmp != head) {}
在循环中用list_entry从链表中得到等待结构wait_queue_t的结构。拿出结构中的task,调用try_to_wake_up函数唤醒该进程。
在这里注意,如果等待队列没有等待的进程,那么就什么都不做,退出。
所以等待队列和信号量不一样,它的休眠和唤醒不一定是一一对应的。
调用多次wake_up不会产生副作用。在函数内部进行了检查,没有等待的队列就推出。
(3):static inline int try_to_wake_up(struct task_struct * p, int synchronous)
先对可运行进程队列加锁,
将要唤醒的进程p的状态state设置为TASK_RUNNING,
如果这个进程已经在可运行队列中了,就退出,
否则调用add_to_runqueue(p)(本文件中)把进程P加入到可运行队列中去。
解锁。
(4):inline int wake_up_process(struct task_struct * p)
仅仅调用try_to_wake_up把进程p唤醒。
****************************************************************
*****和原来的版本相兼容的一些函数(等待函数)*****************************
参数也有所改变。但他们都可以和wake_up_(interrupitble)构成等待——唤醒对来使用。
(1):void interruptible_sleep_on(wait_queue_head_t *q)
设置了几个宏
把宏展开之后和wait_event_interruptible基本一样,参看等待队列的说明wait_queue.txt
(2):long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
延时等待,指定一个时间。
基本结构和interruptible_sleep_on一样,只是调用了schedule_timeout函数。
(3):signed long schedule_timeout(signed long timeout)
参数以jiffies来计算。
分以下几种情况来处理。
如果current->state=TASK_UNINTERRUPTIBLE,则一定等待jiffies消耗完返回,参数返回0
如果current->state=TASK_INTERRUPTIBLE,则不一定等待jiffies消耗完返回,如果中途返回,例如有信号唤醒了进程,则返回参数返回剩余时间。
(4):void sleep_on(wait_queue_head_t *q)
和interruptible_sleep_on一模一样,只是把进程的当前状态设置为TASK_UNINTERRUPTIBLE
(5):long sleep_on_timeout(wait_queue_head_t *q, long timeout)
和interruptible_sleep_on_timeout一模一样,只是把进程的当前状态设置为TASK_UNINTERRUPTIBLE
****************************************************************************
********可运行进程队列的一些函数*******************************************
注意,可运行队列的一些函数在/include/linux/sched.h中也有定义。
static LIST_HEAD(runqueue_head)
这个结构就是可运行队列的初始结构,所有可运行的进程都连接到它的后面形成可运行队列。
(1):static inline void add_to_runqueue(struct task_struct * p)
调用list_add(&p->run_list, &runqueue_head)将进程p连接到可运行队列中的头部。
然后增加可运行进程的个数nr_running(全局变量)。
(2):static inline void move_last_runqueue(struct task_struct * p)
把进程p加入到可运行队列中的尾部。
list_del(&p->run_list); //先从可运行队列中删除
list_add_tail(&p->run_list, &runqueue_head); //加到可运行队列的尾部
(3):static inline void move_first_runqueue(struct task_struct * p)
把进程p加入到可运行队列中的头部。
list_del(&p->run_list); //先从可运行队列中删除
list_add(&p->run_list, &runqueue_head); //加到可运行队列的头部
***************************************************************
***********进程调度的一些函数和说明*************************
注意:do_bottom_half已经被废止了,取而代之的事do_softirq
这个函数是调度的主函数。
对于一般的内核进程来说,如果想调度的话,只用将当前进程的state字段设置为非TASK_RUNNING,然后调用这个函数就可以了,
#该函数将state标记为非TASK_RUNNING的进程从可运行进程队列&runqueue_head删除掉---->注意
#然后从可运行队列中选择一个进程执行。
asmlinkage void schedule(void)
prepare_to_switch(); //一般来说是空
…… //进行相应的检查
switch_mm(oldmm, mm, next, smp_processor_id()); //将新进程的页目录放到cr3寄存器中
……
switch_to(prev, next, prev); //进行进程切换,核心就是更换SS:ESP,以及TSS中的SS0:ESP0
这个函数负责真正的进程调度,切换,也就是说,经过这个函数,参数中的prev和next已经在cpu上交换了
static inline void context_switch(task_t *prev, task_t *next)
**************************************************************
*************系统初始化的函数**********************************************
void __init sched_init(void)
这个函数需要在main.c中的start_kernel中被调用来初始化。
init_timers;
init_bh(TIMER_BH, run_all_timers)
init_bh(TQUEUE_BH, tqueue_bh);
init_bh(IMMEDIATE_BH, immediate_bh);
*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -