附上linux-0.11内核地址https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/old-versions/
系统进程的运转方式
CPU内部有一个RTC,会在上电的时候调用nktime函数算出从1970年1月1日0时开始到当前开机点所过的秒数给MKTIME函数传来的时间结构体的赋值。
由初始化时从RTC(coms)中读出的参数转化为时间存入全局变量中,并且会为JIFFIES所用。JIFFIES是一个系统的时钟滴答,一个系统滴答是10ms ,定时器10ms一个滴答-->每隔10ms会引发一个定时器中断。中断服务函数,如下,首先会进行JIFFIES的自加
kernel\system_call.s下
_timer_interrupt:
push %ds # save ds,es and put kernel data space
push %es # into them. %fs is used by _system_call
push %fs
pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
pushl %ecx # save those across function calls. %ebx
pushl %ebx # is saved as we use that in ret_sys_call
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
incl _jiffies #jiffies自加
movb $0x20,%al # EOI to interrupt controller #1
outb %al,$0x20
movl CS(%esp),%eax
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
pushl %eax
call _do_timer #调用_do_timer函数
addl $4,%esp # task switching to accounting ...
jmp ret_from_sys_call
上面的jiffies的中断服务函数调用_do_timer 函数
void do_timer(long cpl) { extern int beepcount; extern void sysbeepstop(void); if (beepcount) if (!--beepcount) sysbeepstop(); //cpl表示当前被中断的进程所储存的状态是内核态还是用户态 //0表示被中断的是内核进程,1表示被中断的是用户进程 if (cpl) current->utime++; /*current为宏定义指当前进程*/ else current->stime++; if (next_timer) { next_timer->jiffies--; while (next_timer && next_timer->jiffies <= 0) { void (*fn)(void); fn = next_timer->fn; next_timer->fn = NULL; next_timer = next_timer->next; (fn)(); } } if (current_DOR & 0xf0) do_floppy_timer(); if ((--current->counter)>0) return; current->counter=0; if (!cpl) return; schedule(); }
上述current是一个宏定义全局变量,转到定义处是调用的task_struct结构体。
struct task_struct *current = &(init_task.task);
进程的创建使用等都是在和task_struct这个结构体打交道,进程的创建就是创建一个task_struct对象,然后再对该对象赋值。一个task_struct对应一个进程,所以task_struct[n]
对应一个进程向量表,每一个进程都有一个变量叫counter为时间片。counter在进程调度时会使用。进程的调度就是task_struct[n]链表的检索,去找时间片最大的任务调用(长任务优先算法)。直到counter为0,然后再进行新一轮的调用。当所有进程task_struct[n]的时间片都为0时,则重新为每个进程分配时间片kernel\sched.c下时间片分配方式如下:
(*p)->counter = ((*p)->counter >> 1) + (*p)->priority;
分配时就会涉及优先级,将优先级加到时间片上去,优先级高的时间片就大,时间片大就先调度。所以0.11的内核就是优先级时间片轮转调度算法
上述do_timer函数中next_timer定义如下:
static struct timer_list { long jiffies; void (*fn)(); struct timer_list * next; } timer_list[TIME_REQUESTS], * next_timer = NULL;
这是一个结构体链表,是时间链表的指针。next_timer是嫁接与jiffies变量的所有定时器的事件链表。jiffies就像一个时间轴,你可以选择在时间轴上任意一点触发一个事件。这个时间轴就像定时器链表,可以管理嫁接在这上面的定时器。