现在的位置: 首页 > 综合 > 正文

进程上下文与中断上下文

2017年08月25日 ⁄ 综合 ⁄ 共 6665字 ⁄ 字号 评论关闭

进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不断被提及,是最经常接触、看上去很懂但又说不清楚到底怎么回事。造成这种局面的原因,可能是原来接触到的操作系统课程的教学总停留在一种浅层次的理论层面上,没有深入去研究。

 


处理器总处于以下状态中的一种:
1、内核态,运行于进程上下文,内核代表进程运行于内核空间;
2、内核态,运行于中断上下文,内核代表硬件运行于内核空间;
3、用户态,运行于用户空间。

 


 
用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存器值、变量等。所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。

 硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)。

 


LINUX完全注释中的一段话:

 当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程的执行。

 

 

 

Interrupt Context
-------------------------------------------
 
   Whenexecuting an interrupt handler or bottom half, the kernel is ininterrupt context. Recall that process context is the mode ofoperation
the kernel is in while it is executing on behalf of aprocess -- for example, executing a system call or running a kernelthread. In process context, the current macro points to theassociated task. Furthermore, because a process is coupled to thekernel in process
context(因为进程是以进程上文的形式连接到内核中的), process contextcan sleep or otherwise invoke the scheduler.

    Interruptcontext, on the other hand, is not associated with a process. Thecurrent macro is not relevant
(although it points to theinterrupted process). Without a backing process(由于没有进程的背景),interrupt context cannot sleep -- how would it everreschedule?(否则怎么再对它重新调度?) Therefore, you cannot call certainfunctions from interrupt context. If a function sleeps, you
cannotuse it from your interrupt handler -- this limits the functionsthat one can call from an interrupthandler.(这是对什么样的函数可以在中断处理程序中使用的限制)

    Interruptcontext is time critical because the interrupt handler interruptsother code. Code should
be quick and simple. Busy looping isdiscouraged. This is a very important point; always keep in mindthat your interrupt handler has interrupted other code (possiblyeven another interrupt handler on a different line!). Because ofthis asynchronous nature, it
is imperative(必须) that all interrupthandlers be as quick and as simple as possible. As much aspossible, work should be pushed out from the interrupt handler andperformed in a bottom half, which runs at a more convenienttime.

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

    [1] Aprocess is always running. When nothing else is schedulable, theidle task runs.

    Early inthe 2.6 kernel process, an option was added to reduce the stacksize from two pages down to
one, providing only a 4KB stack on32-bit systems. This reduced memory pressure because every processon the system previously needed two pages of nonswappable kernelmemory. To cope with(应对) the reduced stack size, interrupt handlerswere given their own stack,
one stack per processor, one page insize. This stack is referred to as the interrupt stack(这个栈就程为中断栈).Although the total size of the interrupt stack is half that of theoriginal shared stack, the average stack space available is greaterbecause interrupt handlers
get the full page of memory tothemselves.

    Yourinterrupt handler should not care what stack setup is in use orwhat the size of the kernel stack
is. Always use an absoluteminimum amount of stack space.


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

    [7] Otherthan process context there is interrupt context, In interruptcontext, the system is not running
on behalf of a process, but isexecuting an interrupt handler. There is no process tied tointerrupt handlers and consequently no process context.

    Systemcalls and exception handlers are well-defined interfaces into thekernel. A process can begin
executing in kernel-space only throughone of these interfaces -- all access to the kernel is throughthese interfaces.

-------------------------------------------
 
   上下文context:上下文简单说来就是一个环境,相对于进程而言,就是进程执行时的环境。具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。
 
  一个进程的上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文。
 
   用户级上下文:正文、数据、用户堆栈以及共享存储区;
 
   寄存器上下文:通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
 
   系统级上下文:进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。

   当发生进程调度时,进行进程切换就是上下文切换(contextswitch).操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用进行的模式切换(modeswitch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。

 

转自:

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

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

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhiyu520/archive/2008/07/27/2719827.aspx

进程上下文和中断上下文的区别

  内核空间和用户空间是现代操作系统的两种工作模式,内核模块运行在内核空间,而用户态应用程序运行在用户空间。它们代表不同的级别,而对系统资源具有不同的访问权限。内核模块运行在最高级别(内核态),这个级下所有的操作都受系统信任,而应用程序运行在较低级别(用户态)。在这个级别,处理器控制着对硬件的直接访问以及对内存的非授权访问。内核态和用户态有自己的内存映射,即自己的地址空间。

  系统的两种不同于行状态,才有了上下文的概念。用户空间的应用程序,如果想请求系统服务,比如操作某个物理设备,映射设备的地址到用户空间,必须通过系统调用来实现。(系统调用是操作系统提供给用户空间的接口函数)。如下图所示:


 

  通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换,用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行,所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈上的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

  同理,硬件通过触发信号,向CPU发送中断信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,中断上下文就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。

  Linux内核工作在进程上下文或者中断上下文。提供系统调用服务的内核代码代表发起系统调用的应用程序运行在进程上下文;另一方面,中断处理程序,异步运行在中断上下文。中断上下文和特定进程无关。

  运行在进程上下文的内核代码是可以被抢占的(Linux2.6支持抢占)。但是一个中断上下文,通常都会始终占有CPU(当然中断可以嵌套,但我们一般不这样做),不可以被打断。正因为如此,运行在中断上下文的代码就要受一些限制,不能做下面的事情:

1. 睡眠或者放弃CPU。

  由于中断上下文不属于任何进程,它与current没有任何关系(尽管此时current指向被中断的进程),所以中断上下文一旦睡眠或者放弃CPU,将无法被唤醒。所以也叫原子上下文(atomic context)。

2. 尝试获得信号量

  为了保护中断句柄临界区资源,不能使用mutexes。如果获得不到信号量,代码就会睡眠,会产生和上面相同的情况,如果必须使用锁,则使用spinlock。

3. 执行耗时的任务

  中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。在中断处理例程中执行耗时任务时,应该交由中断处理例程底半部来处理。

4. 访问用户空间的虚拟地址

  因为中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在终端上下文无法访问用户空间的虚拟地址

5. 中断处理例程不应该设置成reentrant(可被并行或递归调用的例程)。因为中断发生时,preempt和irq都被disable,直到中断返回。所以中断上下文和进程上下文不一样,中断处理例程的不同实例,是不允许在SMP上并发运行的。

6. 中断处理例程可以被更高级别的IRQ中断。如果想禁止这种中断,可以将中断处理例程定义成快速处理例程,相当于告诉CPU,该例程运行时,禁止本地CPU上所有中断请求。这直接导致的结果是,由于其他中断被延迟响应,系统性能下降。

抱歉!评论已关闭.