linux-0.11内核源码——(一)内核进程调度分析

本文解析了Linux0.11内核中的系统进程运行机制,重点介绍了Jiffies时钟滴答、定时器中断服务函数以及_do_timer函数的工作原理,探讨了task_struct结构在进程创建和调度中的作用,以及基于优先级的时间片轮转调度算法。
摘要由CSDN通过智能技术生成

附上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就像一个时间轴,你可以选择在时间轴上任意一点触发一个事件。这个时间轴就像定时器链表,可以管理嫁接在这上面的定时器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值