schedule调用相关整理

来源:互联网 发布:用js排序数组中的数字 编辑:程序博客网 时间:2024/04/30 20:07

1 schedule的调用时机
×××正常情况下进程上下文中的直接调用schedule(),就会尝试着进行上下文切换。比如:

  • int down_interruptible(struct semaphore *sem)
  • copy_from_user(to, from, n)--------只能在用户上下文中调用.
×××抢占式的调用schedule()。比如:
  • 在中断里面返回时候,即in_irq() != 0(当前处于中断上下文),检查当前进程的TIF_NEED_RESCHED标志位,看是否需要进行preempt_schedule_irq()进行preempt的调度。当然如果准备这个时候进入in_irq()进行调度的话,要设置当前进程的PREEMPT_ACTIVE位,代表这个schedule的调用是因为抢占发生的。让shcedule有相应的准备。
  • schedule_tick()会做一些跟调度算法有关的计算和更新,如果当前进程需要被schedule了,就置位TIF_NEED_RESCHED,注意这里面并不调用schedule。
  • preempt_check_resched(),一般在进程上下文中被间接调用。比如在preempt_enable当中在重新设置了可以被抢占的标志位之后,就调用preempt_check_resched(),如果需要被抢占那就调用shcedule抢占之。
补充:preempt_schedule_irq()和preempt_check_resched都会调用preempt_schedule。
 
2 Performing the Process Switch
  在switch_to(prev, next, last)函数中,直接汇编不罗嗦

从上面可以看出通用寄存器中,在进程切换到时候并不太需要保存什么寄存器。这是由进程切换到时机造成的,要么直接在内核代码中调用schedule,要么就在中断返回时候调用schedule。不保存寄存器确实无关大雅。

__switch_to中的任务包括:

  1. _ _unlazy_fpu( ) --- 存储fpu,mmx,xmm寄存器。
  2. Loads next_p->thread.esp0 in the esp0 field of the TSS relative to the local CPU.
  3. 修改GDT,LDT中一些选择子。
  4. 存储fs, gs
  5. 有必要的话,存储调试寄存器
  6. 更新IO BITMAP in TSS.
  7. movl %edi,%eax   //返回地址,为刚刚压栈的threadinfo->EIP
    ret

cpu接着跑,但不是在prev进程的上下文中跑了,而是在next进程的上下文中接着跑。
上下文很重要!

3 Hardware context storage in User pace and Kernel space

问:Userspace程序因为发生interrupt或者sys_call进入kernel时候, Userspace程序context存储在哪?
答:可以在copy_process->copy_thread函数中看到,TSS中存储的esp0就是thread_union所在的stack。所以在interrupt的时候,context是存储在esp0中的。并且凭经验,sys_call也是存储在esp0的。

问:Kernel程序运行时候发生中断,上下文存储在哪?
答:存储在当前current运行所使用的当前esp堆栈中。

问:在interrupt return或者kernel程序“主动调用schedule”时候,可能会进行schedule进行preempt,被schedule的函数的上下文又是存储在哪?
答:在进入中断的时候,上下文已经存储了,然后调用schedule 。

问:在schedule中你如何判断当前发生在上方的哪几种情况之中?从而做出相应的处理。
答:

4 HardwareIRQ and Exception Handling

×××Hardware Handling of Interrupts and Exceptions

  1. After executing an instruction,the control unit checks whether an interrupt or an exception occurred while the control unit executed the previous instruction. If one occurred,handle the IRQ。
  2. 根据idtr, gdtr得到gdt,ldt等等乱七八糟的,检查是否进行优先级(是在Userspace还是在Kernel中发生的中断),如果是用户态还要进行一系列的寄存器的切换(保护模式相关),这关心的是如果是用户态发生中断esp从TSS中取出,也换成内核态stack,在内核态发生中断就不用切换esp了。
  3. Cpu自动将ss, esp, eflags, cs, eip存储到stack中(是内核态堆栈)。

×××Saving the registers for the interrupt handler

  1. Saving registers is the first task of the interrupt handler.
  2. 就这样讲寄存器都存储在当前堆栈esp中了

5 Softirqs and Tasklets

l  Tasklets run in software interrupt context with the result that all tasklet code must be atomic.

l  Actually, atasklet, just like a kernel timer, is executed (in atomic mode) in the context of a “soft interrupt,”(different from intel’s programmable exception mechanism , soft interrupt) a kernel mechanism that executes asynchronous tasks with hardware interrupts enabled.­

l  interrupt context : it specifies that the kernel is currently executing either an interrupt handler or a deferrable function.

l  一般会在之后的某个时刻检查当前系统中是否有被pending的softirq,如果有就去执行,Linux内核中检查是否有softirq挂起的检查点主要有以下三类:

  1. 硬件中断代码返回的时候,void irq_exit(void)
  2. ksoftirqd内核服务线程运行的时候

l  软中断的执行时机,即do_softirq()的运行时机 有两种选择:

  1. 中断返回时马上调用执行.这样能对软中断即时处理.但是这样一直频繁执行软中断了(因为有的软中断本身可能还会重复触发).用户进程很可能会处于饥饿状态.
  2. 如果不马上执行.比如延后到下一次执行时机再执行(一般是下一次中断返回).但是这样当系统空闲时,也必须得等一段时间.这样利用率又不高.同时也可能有大量软中断得不到执行. 现在内核采用第二种方法,但通过一个ksoftirqd线程来解决这一问题.这个线程就是循环调用do_softirq(),每个处理器有一个这样的线程.当有大量软中断时该线程被唤醒.(do_softirq()中通过判断是否有重复触发,来决定唤醒ksoftirqd线程). ksoftirqd的优先级最低,所以不会抢占用户进程,但当系统空闲时就会调用,从而解决了空闲时也得等一段时间才能处理软中断的问题.

l  最关键的是The do_softirq() function(查看understanding the linux kernel)

6 Multiple Kernel Mode stacks

l  If the size of the tHRead_union structure is 8 KB, the Kernel Mode stack of the current process is used for every type of kernel control path: exceptions, interrupts, and deferrable functions.

l  Conversely, if the size of the thread_union structure is 4 KB, the kernel makes use of three types of Kernel Mode stacks:

  1. The exception stack is used when handling exceptions (including system calls). This is the stack contained in the per-process thread_union data structure, thus the kernel makes use of a different exception stack for each process in the system.
  2. The hard IRQ stack is used when handling interrupts. There is one hard IRQ stack for each CPU in the system, and each stack is contained in a single page frame.
  3. The soft IRQ stack is used when handling deferrable functions .There is one soft IRQ stack for each CPU in the system, and each stack is contained in a single page frame.

All hard IRQ stacks are contained in the hardirq_stack array, while all soft IRQ stacks are contained in the softirq_stack array. Each array element is a union of type irq_ctx that span a single page. At the bottom of this page is stored a thread_info structure, while the spare memory locations are used for the stack; remember that each stack grows towards lower addresses. Thus, hard IRQ stacks and soft IRQ stacks are very similar to the exception stacks described in the section "Identifying a Process" in Chapter 3; the only difference is that the tHRead_info structure coupled with each stack is associated with a CPU rather than a process.

7 一个经典的内核比喻

we will look at the kernel as a waiter who must satisfy two types of requests: those issued by customers and those issued by a limited number of different bosses. The policy adopted by the waiter is the following:

  1. If a boss calls while the waiter is idle, the waiter starts servicing the boss.
  2. If a boss calls while the waiter is servicing a customer, the waiter stops servicing the customer and starts servicing the boss.
  3. If a boss calls while the waiter is servicing another boss, the waiter stops servicing the first boss and starts servicing the second one. When he finishes servicing the new boss, he resumes servicing the former one.
  4. One of the bosses may induce the waiter to leave the customer being currently serviced. After servicing the last request of the bosses, the waiter may decide to drop temporarily his customer and to pick up a new one.

The services performed by the waiter correspond to the code executed when the CPU is in Kernel Mode. If the CPU is executing in User Mode, the waiter is considered idle.

Boss requests correspond to interrupts, while customer requests correspond to system calls or exceptions raised by User Mode processes.

The careful reader has already associated the first three rules with the nesting of kernel control paths The fourth rule corresponds to one of the most interesting new features included in the Linux 2.6 kernel, namely kernel preemption .

原创粉丝点击