進程上下文和中斷上下文

  進程上下文和中斷上下文是操作系統中很重要的兩個概念,這兩個概念在操作系統課程中不斷被提及,是最經常接觸、看上去很懂但又說不清楚到底怎麼回事。造成這種局面的原因,可能是原來接觸到的操作系統課程的教學總停留在一種淺層次的理論層面上,沒有深入去研究。


處理器總處於以下狀態中的一種:
1、內核態,運行於進程上下文,內核代表進程運行於內核空間;
2、內核態,運行於中斷上下文,內核代表硬件運行於內核空間;
3、用戶態,運行於用戶空間。


  用戶空間的應用程序,通過系統調用,進入內核空間。這個時候用戶空間的進程要傳遞很多變量、參數的值給內核,內核態運行的時候也要保存用戶進程的一些寄存器值、變量等。所謂的“進程上下文”,可以看作是用戶進程傳遞給內核的這些參數以及內核要保存的那一整套的變量和寄存器值和當時的環境等。

  硬件通過觸發信號,導致內核調用中斷處理程序,進入內核空間。這個過程中,硬件的一些變量和參數也要傳遞給內核,內核通過這些參數進行中斷處理。所謂的“中斷上下文”,其實也可以看作就是硬件傳遞過來的這些參數和內核需要保存的一些其他環境(主要是當前被打斷執行的進程環境)。


LINUX完全註釋中的一段話:

  當一個進程在執行時,CPU的所有寄存器中的值、進程的狀態以及堆棧中的內容被稱爲該進程的上下文。當內核需要切換到另一個進程時,它需要保存當前進程的所有狀態,即保存當前進程的上下文,以便在再次執行該進程時,能夠必得到切換時的狀態執行下去。在LINUX中,當前進程上下文均保存在進程的任務數據結構中。在發生中斷時,內核就在被中斷進程的上下文中,在內核態下執行中斷服務例程。但同時會保留所有需要用到的資源,以便中繼服務結束時能恢復被中斷進程的執行。



Interrupt Context
-------------------------------------------
    When executing an interrupt handler or bottom half, the kernel is in interrupt context. Recall that process context is the mode of operation the kernel is in while it is executing on behalf of a process -- for example, executing a system call or running a kernel thread. In process context, the current macro points to the associated task. Furthermore, because a process is coupled to the kernel in process context(因爲進程是以進程上文的形式連接到內核中的), process context can sleep or otherwise invoke the scheduler.

    Interrupt context, on the other hand, is not associated with a process. The current macro is not relevant (although it points to the interrupted process). Without a backing process(由於沒有進程的背景), interrupt context cannot sleep -- how would it ever reschedule?(否則怎麼再對它重新調度?) Therefore, you cannot call certain functions from interrupt context. If a function sleeps, you cannot use it from your interrupt handler -- this limits the functions that one can call from an interrupt handler.(這是對什麼樣的函數可以在中斷處理程序中使用的限制)

    Interrupt context is time critical because the interrupt handler interrupts other code. Code should be quick and simple. Busy looping is discouraged. This is a very important point; always keep in mind that your interrupt handler has interrupted other code (possibly even another interrupt handler on a different line!). Because of this asynchronous nature, it is imperative(必須) that all interrupt handlers be as quick and as simple as possible. As much as possible, work should be pushed out from the interrupt handler and performed in a bottom half, which runs at a more convenient time.

    The setup of an interrupt handler's stacks is a configuration option. Historically, interrupt handlers did not receive(擁有) their own stacks. Instead, they would share the stack of the process that they interrupted[1]. The kernel stack is two pages in size; typically, that is 8KB on 32-bit architectures and 16KB on 64-bit architectures. Because in this setup interrupt handlers share the stack, they must be exceptionally frugal(必須非常節省) with what data they allocate there. Of course, the kernel stack is limited to begin with, so all kernel code should be cautious.

    [1] A process is always running. When nothing else is schedulable, the idle task runs.

    Early in the 2.6 kernel process, an option was added to reduce the stack size from two pages down to one, providing only a 4KB stack on 32-bit systems. This reduced memory pressure because every process on the system previously needed two pages of nonswappable kernel memory. To cope with(應對) the reduced stack size, interrupt handlers were given their own stack, one stack per processor, one page in size. This stack is referred to as the interrupt stack(這個棧就程爲中斷棧). Although the total size of the interrupt stack is half that of the original shared stack, the average stack space available is greater because interrupt handlers get the full page of memory to themselves.

    Your interrupt handler should not care what stack setup is in use or what the size of the kernel stack is. Always use an absolute minimum amount of stack space.


Process Context
-------------------------------------------
    One of the most important parts of a process is the executing program code. This code is read in from an executable file and executed within the program's address space. Normal program execution occurs in user-space. When a program executes a system call or triggers an exception, it enters kernel-space. At this point, the kernel is said to be "executing on behalf of the process" and is in process context. When in process context, the current macro is valid[7]. Upon exiting the kernel, the process resumes execution in user-space, unless a higher-priority process has become runnable in the interim(過渡期), in which case the scheduler is invoked to select the higher priority process.

    [7] Other than process context there is interrupt context, In interrupt context, the system is not running on behalf of a process, but is executing an interrupt handler. There is no process tied to interrupt handlers and consequently no process context.

    System calls and exception handlers are well-defined interfaces into the kernel. A process can begin executing in kernel-space only through one of these interfaces -- all access to the kernel is through these interfaces.

-------------------------------------------
    上下文context: 上下文簡單說來就是一個環境,相對於進程而言,就是進程執行時的環境。具體來說就是各個變量和數據,包括所有的寄存器變量、進程打開的文件、內存信息等。
    一個進程的上下文可以分爲三個部分:用戶級上下文、寄存器上下文以及系統級上下文。
    用戶級上下文: 正文、數據、用戶堆棧以及共享存儲區;
    寄存器上下文: 通用寄存器、程序寄存器(IP)、處理器狀態寄存器(EFLAGS)、棧指針(ESP);
    系統級上下文: 進程控制塊task_struct、內存管理信息(mm_struct、vm_area_struct、pgd、pte)、內核棧。

    當發生進程調度時,進行進程切換就是上下文切換(context switch).操作系統必須對上面提到的全部信息進行切換,新調度的進程才能運行。而系統調用進行的模式切換(mode switch)。模式切換與進程切換比較起來,容易很多,而且節省時間,因爲模式切換最主要的任務只是切換進程寄存器上下文的切換。


轉自:

1.http://hi.baidu.com/jiangguiqing/blog/item/a77f1dec6d40fad52e2e2179.html

2.http://hi.baidu.com/zengzhaonong/blog/item/aba2504a67345e2108f7ef77.html

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章