博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核分析-8/进程的调度
阅读量:4285 次
发布时间:2019-05-27

本文共 4806 字,大约阅读时间需要 16 分钟。

进程的调度

  • 之前我们在mykernel中体验了一次进程的调度,调度分为两个过程
  • 1/保存当前进程
  • 2/装载之前进程
和之前的fork exec 有什么区别呢?fork 和exec 只是创造和修改了一个task_struct 结构体,exec后的进程是要调度模块调度才能运行的.而进程的调度就是保存一个结构体,并装载一个结构体.

linux-0.11中的调度

//init/main.cinit//kernel/sched.c//这是调度的初始化模块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
a=p->b=0; p++; p->a=p->b=0; p++; }/* Clear NT, so that we won't have troubles with that later on */ __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); ltr(0); lldt(0); outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 *///设置时钟1 outb_p(LATCH & 0xff , 0x40); /* LSB *///设置时钟2 outb(LATCH >> 8 , 0x40); /* MSB *///设置时钟3 set_intr_gate(0x20,&timer_interrupt);//设置时钟中断处理函数 outb(inb_p(0x21)&~0x01,0x21); set_system_gate(0x80,&system_call);}//1/调度函数(kernel/sched.c)//在mykernel中是内核上层的函数在想切换的时候,调用了 my_schedule 函数进行调度//所以我猜这里也是在想要切换进程的时候调用了内核中的函数切换,这里切换函数是 schedule//2/调度时机//但是在什么时候切换呢?在mykernel中,是时钟中断达到了10^7次,才调用了调度函数//在linux-0.11中只有8个地方调用了 schedule 函数
//schedule1/修改任务数组中每个任务的 signal alarm state2/找出next  2.1/在任务数组中从后往前找,按照counter 的大小, 越大,优先级越高  2.2/找不到,按照 priority 更新counter,回到 2.13/switch_to(next)
/** switch_to(n)将切换当前任务到任务nr,即n。首先检测任务n 是不是当前任务,* 如果是则什么也不做退出。如果我们切换到的任务最近(上次运行)使用过数学* 协处理器的话,则还需复位控制寄存器cr0 中的TS 标志。*/// 输入:%0 - 新TSS 的偏移地址(*&__tmp.a); %1 - 存放新TSS 的选择符值(*&__tmp.b);// dx - 新任务n 的选择符;ecx - 新任务指针task[n]。// 其中临时数据结构__tmp 中,a 的值是32 位偏移值,b 为新TSS 的选择符。在任务切换时,a 值// 没有用(忽略)。在判断新任务上次执行是否使用过协处理器时,是通过将新任务状态段的地址与// 保存在last_task_used_math 变量中的使用过协处理器的任务状态段的地址进行比较而作出的。/* *  switch_to(n) should switch tasks to task nr n, first * checking that n isn't the current task, in which case it does nothing. * This also clears the TS-flag if the task we switched to has used * tha math co-processor latest. */#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)//所以说调度时机分为两种//1/中断处理进程//2/主动调用//其实上面两种都是用 set_intr_gate set_trap_gate set_system_gate 来将中断号与中断处理函数绑定//主动调用是从上面的分支 set_system_gate 来的//中断是从上面的分支 set_intr_gate 来的从中断来说,包括时钟中断、I/O中断、系统调用和异常(linux0.11中只有时钟中断调用了 schedule )从系统调用来说,有open close mount sync pause 等等,这些系统调用通过 int 80 进入内核,然后产生内核线程调用了 schedule
//中断set_intr_gate    set_intr_gate (0x2E, &hd_interrupt);//在kernel/system_call.s中    set_intr_gate (0x20, &timer_interrupt);//在kernel/system_call.s中    set_intr_gate (0x24, rs1_interrupt);//在kernel/chr_drv/rs_io.s 中    set_intr_gate (0x23, rs2_interrupt);//在kernel/chr_drv/rs_io.s中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);   /* int3-5 can be called from all *///        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);    // 下面将int17-48 的陷阱门先均设置为reserved,以后每个硬件初始化时会重新设置自己的陷阱门。        for (i=17;i<48;i++)            set_trap_gate(i,&reserved);        set_trap_gate(45,&irq13);// 设置协处理器的陷阱门。        outb_p(inb_p(0x21)&0xfb,0x21);// 允许主8259A 芯片的IRQ2 中断请求。        outb(inb_p(0xA1)&0xdf,0xA1);// 允许从8259A 芯片的IRQ13 中断请求。        set_trap_gate(39,&parallel_interrupt);// 设置并行口的陷阱门。    }set_system_gate    set_system_gate (0x80, &system_call);    set_system_gate(3,&int3);   /* int3-5 can be called from all */    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/中断处理函数

转载地址:http://rtigi.baihongyu.com/

你可能感兴趣的文章
C++打印地址
查看>>
ARM处理器比较:A8/A9
查看>>
ARM处理器工作模式
查看>>
ARM处理器寄存器
查看>>
汇编语言学习
查看>>
ARM寻址方式
查看>>
uboot工作流程分析
查看>>
不錯的技術論壇
查看>>
GDB 常用參數
查看>>
pthread man page
查看>>
Linux 如何修改 root 密碼
查看>>
nc 傳輸
查看>>
vi 與 vim 的指令整理
查看>>
console & telnet判斷
查看>>
sqlite3
查看>>
關於如何快速切換目錄(Linux)
查看>>
Save Time with minicom macros
查看>>
svn : how to set the executable bit on a file?
查看>>
vim 取代指令
查看>>
git 修改過檔案後,如何commit上server
查看>>