系统的进程的运转方式
- 系统时间:(jiffies 系统滴答)
- CPU内部有一个RTC,会在上电的时候调用mktime函数,算出从1970年1月1日0时开始到当前开机点所过的秒数
- 给mktime函数传过来的时间结构体的赋值是由初始化时从RTC(coms)中读出的参数 转换为时间存入全局变量中,并且会为jiffies所用
- jiffies是一个系统时钟滴答,一个滴答是10ms,这个滴答就像操作系统的脉搏一样。
- 10m一个滴答,每隔10ms会引发一个定时器中断(中断服务函数timer_interrup: t-->call do_timer()中,首先进行了jiffies自加)
源码链接: elixir.bootlin.com/linux/0.10/…
_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
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(long CPL)' does everything from
addl $4,%esp # task switching to accounting ...
jmp ret_from_sys_call
内核态 不可抢占
用户态 可以抢占
void do_timer(long cpl)
{
if (cpl) // CPL变量是内核中用来指示被中断程序的特权, 0表示内核进程 1表示用户进程
current->utime++; // utime用户程序的运行时间
else
current->stime++; // stime内核程序的运行时间
if (next_timer) { // next_timer 是嫁接于jiffies变量的所有定时器的事件链表
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)();
}
}
// current->counter 进程的时间片
if ((--current->counter)>0) return; // 当前进程的时间片还没到则返回
current->counter=0;
if (!cpl) return; // 时间片到了,但是当前进程是内核进程也返回
schedule(); // 当前进程是用户进程,时间片到了,进行下一轮的进程调度
}
进程结构体
struct task_struct {
/* these are hardcoded - don't touch */
long state; /* 进程状态:-1 unrunnable, 0 runnable, >0 stopped */
long counter; /* 时间片 */
long priority; /* 优先级 */
long signal; /* 信号 */
struct sigaction sigaction[32]; /* 信号位图 */
long blocked; /* bitmap of masked signals */
/* various fields */
int exit_code;
unsigned long end_code,end_data,brk,start_stack;
long pid,father,pgrp,session,leader;
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
long alarm;
long utime,stime,cutime,cstime,start_time;
unsigned short used_math;
/* file system info */
int tty; /* -1 if no tty, so it must be signed */
unsigned short umask;
struct m_inode * pwd;
struct m_inode * root;
unsigned long close_on_exec;
struct file * filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
struct desc_struct ldt[3]; /* 局部描述符 */
/* tss for this task */
struct tss_struct tss; /* 进程状态描述符 */
};
进程调度
void main(void) /* This really IS void, no error here. */
{ /* The startup routine assumes (well, ...) this */
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
ROOT_DEV = ORIG_ROOT_DEV;
drive_info = DRIVE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
if (memory_end > 6*1024*1024)
buffer_memory_end = 2*1024*1024;
else
buffer_memory_end = 1*1024*1024;
mem_init(buffer_memory_end,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init(); // 设置开机启动时间。
sched_init(); // 调度程序初始化(加载任务0的tr,ldtr)
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti();
move_to_user_mode(); // 移到用户模式下执行
if (!fork()) { /* we count on this going ok */
init(); // 在新建的子进程(任务1即init进程)中执行。
}
/*
* NOTE!! For any other task 'pause()' would mean we have to get a
* signal to awaken, but task0 is the sole exception (see 'schedule()')
* as task 0 gets activated at every idle moment (when no other tasks
* can run). For task0 'pause()' just means we go check if some other
* task can run, and if not we return here.
*/
for(;;) pause();
}
void sched_init(void)
{
int i;
struct desc_struct * p;
if (sizeof(struct sigaction) != 16)
panic("Struct sigaction MUST be 16 bytes");
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); //把进程的tss copy到gdt
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); //把进程的ldt copy到gdt
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1;i<NR_TASKS;i++) { // 清任务数组和描述符表项(注意i=1开始,所以初始任务的描述符还在)
task[i] = NULL;
p->a=p->b=0;
p++;
p->a=p->b=0;
p++;
}
ltr(0);
lldt(0);
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
set_intr_gate(0x20,&timer_interrupt); // 设置时钟中断处理程序句柄(设置时钟中断门)。
outb(inb_p(0x21)&~0x01,0x21);
set_system_gate(0x80,&system_call); // 然后设置系统调用中断门。
}