linux系统的进程运转方式
Posted Linux bsping
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux系统的进程运转方式相关的知识,希望对你有一定的参考价值。
一、系统时间:(jiffies 系统滴答)
CPU内部有一个RTC,会在上电的时候调用mktime函数计算出1970年1.1日0时开始到当前开机点所过的秒数,给mktime函数传来的时间结构体的赋值是由初始化时从RTC中读出的参数,转化为时间存入全局变量中,并且会为jiffies所用。
jiffies是一个系统的时钟滴答,一个系统滴答是10ms。
每10ms发生一个定时器的中断,中断首先会将jiffies自加一,之后获取任务的特权级,将其作为参数调用do_timer函数。
### int32 - (int 0x20)时钟中断处理程序。中断频率被设置为100Hz。
# 定时芯片8253/8254是在kernel/sched.c中初始化的。因此这里jiffies每10 ms加1.
# 这段代码将jiffies增1,发送结束中断指令给8259控制器,然后用当前特权级作为
# 参数调用C函数do_timer(long CPL).当调用返回时转去检测并处理信号。
.align 2
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
# 由于初始化中断控制芯片时没有采用自动EOI,所以这里需要发指令结束该硬件中断。
movb $0x20,%al # EOI to interrupt controller #1
outb %al,$0x20 # 操作命令字OCW2送0x20端口
# 下面从堆栈镇南关取出执行系统调用代码的选择符(CS段寄存器值)中的当前特权级别(0或3)
# 并压入堆栈,作为do_timer的参数。do_timer函数执行任务切换、计时等工作。
movl CS(%esp),%eax
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
pushl %eax
call do_timer # 'do_timer(long CPL)' does everything from
addl $4,%esp # task switching to accounting ...
jmp ret_from_sys_call
/// 时钟中断C函数处理程序,在system_call.s中timer_interrupt被调用。
// 参数cpl是当前特权级0或3,是时钟中断发生时正在被执行的代码选择符中的特权级。
// cpl=0时表示中断发生时正在执行内核代码;cpl=3表示中断发生时正在执行用户代码。
// 对于一个进程由于执行时间片用完时,则进城任务切换。并执行一个计时更新工作。
void do_timer(long cpl)
// 如果当前特权级(cpl)为0,则将内核代码运行时间stime递增;
if (cpl)
current->utime++;
else
current->stime++;
// 如果有定时器存在,则将链表第1个定时器的值减1.如果已等于0,则调用相应的
// 处理程序,并将该处理程序指针置空。然后去掉该项定时器。next_timer是定时器
// 链表的头指针。
if (next_timer)
next_timer->jiffies--;
while (next_timer && next_timer->jiffies <= 0)
void (*fn)(void); // 这里插入了一个函数指针定义!!!! o(︶︿︶)o
fn = next_timer->fn;
next_timer->fn = NULL;
next_timer = next_timer->next;
(fn)(); // 调用处理函数
// 如果进程运行时间还没完,则退出。否则置当前任务计数值为0.并且若发生时钟中断
// 正在内核代码中运行则返回,否则调用执行调度函数。
if ((--current->counter)>0) return;
current->counter=0;
if (!cpl) return; // 内核态程序不依赖counter值进行调度
schedule();
cpl变量是内核中用来表示被时钟中断中断的程序的特权级,0为内核态、1为用户态。根据这个来给内核态或者用户态的时间自加一。next_timer是jiffies变量的所有定时器的事件链表的头指针,
current->counter是指当前任务剩余的时间片。后面代码的意思是如果存在定时器链表,则将首个定时器jiffies自减一,当减为0之后将指针函数替换为下一个定时器的指针函数,并将链表后移,时触发fn指针函数。大体意思就是到时间了触发fn函数。后面判断当前任务的时间片是否用完,不为零就返回继续执行,为零的话,判断特权级,内核程序不依赖时间片调度,若为用户进程,则进行一次调度。
#task_struct代表一个进程,task_struct[]是进程向量表。
进程的调度就是task_struct[]进程链表的检索,找到时间片最大的那个进程对象(task_struct),然后进行调用,直到时间片为零退出并调用新的任务,全部为零之后在新一轮的调用中重新赋值。
总结:因为有了系统滴答,10ms进一次中断,引起jiffies自加一,从而引发do_timer函数,里面可以定时的触发一些函数,并且里面提出了时间片,进而引发了进程调度,这就是进程的工作方式。
以上是关于linux系统的进程运转方式的主要内容,如果未能解决你的问题,请参考以下文章