进程的调度
- 之前我们在mykernel中体验了一次进程的调度,调度分为两个过程
- 1/保存当前进程
- 2/装载之前进程
和之前的fork exec 有什么区别呢?
fork 和exec 只是创造和修改了一个task_struct 结构体,exec后的进程是要调度模块调度才能运行的.
而进程的调度就是保存一个结构体,并装载一个结构体.
linux-0.11中的调度
init
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));
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1;i<NR_TASKS;i++) {
task[i] = NULL;
p->a=p->b=0;
p++;
p->a=p->b=0;
p++;
}
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
ltr(0);
lldt(0);
outb_p(0x36,0x43);
outb_p(LATCH & 0xff , 0x40);
outb(LATCH >> 8 , 0x40);
set_intr_gate(0x20,&timer_interrupt);
outb(inb_p(0x21)&~0x01,0x21);
set_system_gate(0x80,&system_call);
}
1/修改任务数组中每个任务的 signal alarm state
2/找出next
2.1/在任务数组中从后往前找,按照counter 的大小, 越大,优先级越高
2.2/找不到,按照 priority 更新counter,回到 2.1
3/switch_to(next)
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
"je 1f\n\t" \
"movw %%dx,%1\n\t" \
"xchgl %%ecx,_current\n\t" \
"ljmp %0\n\t" \
"cmpl %%ecx,_last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n)),"c" ((long) task[n])); \
}
1/中断处理过程 do_timer(timer_interrupt->do_timer)
2/主动调用 release do_exit sys_waitpid sys_pause sleep_on interruptible_sleep_on tty_write
例子:
tty_write(sys_write->rw_char->crw_table->rw_tty->rw_ttyx->tty_write- 写阻塞->schedule)
从中断来说,包括时钟中断、I/O中断、系统调用和异常(linux0.11中只有时钟中断调用了 schedule )
从系统调用来说,有open close mount sync pause 等等,这些系统调用通过 int 80 进入内核,然后产生内核线程调用了 schedule
set_intr_gate
set_intr_gate (0x2E, &hd_interrupt);
set_intr_gate (0x20, &timer_interrupt);
set_intr_gate (0x24, rs1_interrupt);
set_intr_gate (0x23, rs2_interrupt);
set_trap_gate
set_trap_gate (0x21, &keyboard_interrupt);
set_trap_gate (0x26, &floppy_interrupt);
void trap_init(void)
{
int i;
set_trap_gate(0,÷_error);
set_trap_gate(1,&debug);
set_trap_gate(2,&nmi);
set_system_gate(3,&int3);
set_system_gate(4,&overflow);
set_system_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_trap_gate(8,&double_fault);
set_trap_gate(9,&coprocessor_segment_overrun);
set_trap_gate(10,&invalid_TSS);
set_trap_gate(11,&segment_not_present);
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_trap_gate(14,&page_fault);
set_trap_gate(15,&reserved);
set_trap_gate(16,&coprocessor_error);
for (i=17;i<48;i++)
set_trap_gate(i,&reserved);
set_trap_gate(45,&irq13);
outb_p(inb_p(0x21)&0xfb,0x21);
outb(inb_p(0xA1)&0xdf,0xA1);
set_trap_gate(39,¶llel_interrupt);
}
set_system_gate
set_system_gate (0x80, &system_call);
set_system_gate(3,&int3);
set_system_gate(4,&overflow);
set_system_gate(5,&bounds);
下面的说的是glibc-2.25和linux-3.10中的调用路径
asmlinkage void __sched schedule(void)
{
struct task_struct *tsk = current;
sched_submit_work(tsk);
__schedule();
}
1/驱动里面
2/系统调用
3/中断处理函数