zoukankan      html  css  js  c++  java
  • 系统调用和中断处理的异同(以Linux MIPS为例)

    在Linux下写一个驱动时候遇到的读操作性能问题,让我想一窥系统调用的处理流程,以查出问题的root cause。很多书把它和中断处理放在一起讲,但是又没有哪本书说清楚了,看来只有代码才能说明一切。以Linux系统下MIPS体系结构为例。

    从开始说起。

    1. 相关代码

    1 trap_init(void) /* 系统初始化:start_kernel中 */
    2     set_handler(0x180, &except_vec3_generic, 0x80);/*          except_vec3_generic 根据cause寄存器跳转到其若干类异常/中断处理函数中*/
    3     set_except_vector(0, rollback ? rollback_handle_int :     handle_int);
    4     set_except_vector(1, handle_tlbm);
    5         ... ...
    6     set_except_vector(8, handle_sys);

    当系统发现异常时,CPU将自动进入内核模式并禁止中断,同时将PC指针指向默认的地址(根据异常的不同将分别进入偏移地址为0x180 or 0x200的地方,这些在函数trap_init都有体现,上述代码没有一一贴出)。

    异常号为8时进入系统调用的处理入口。

    1 /* 进入系统调用异常处理 */
    2 handle_sys
    3     SAVE_SOME
    4     STI                 #  进入内核模式并enable中断
    5     la    t1, sys_call_table
    6          ... ...

    注意这里系统调用入口一开始就会enable中断。

    而异常号为0时进入中断处理的入口。

     1 /* 进入中断异常处理 */
     2 handle_int
     3     SAVE_ALL
     4     CLI                #  进入内核模式并disable中断
     5    plat_irq_dispatch  # 每种类型的CPU都有自己的实现
     6         do_IRQ
     7             generic_handle_irq /*处理用户注册的ISR,关中断进行 */
     8             irq_exit()
     9                 do_softirq   /*进入下半部处理(软中断) */
    10                     local_irq_enable /*仍然在中断上下文中,但是开中断*/
    11                     ... ... /*处理用户注册的下半部,
    12 Note:有可能在softirq内核线程中进行处理,所以下半部的处理并不总是在中断上下文中,但是下半部的思想就是允许中断嵌套*/

    上面的代码描述了中断处理的框架,简要列出了处理中值得注意的地方。这里尤其注意中断处理入口一开始直接disable中断。

    2. 结论

    所以,系统调用和普通中断处理的异同在于:两者都是从同一个异常处理入口开始,但是系统调用会一开始让CPU进入内核模式且使能中断,然后从系统调用表中取得相应的注册函数调用之;而中断处理则让CPU进入内核模式且disable中断,继而调用do_IRQ函数。所以系统调用的真实处理(系统调用表中的注册函数执行)中可以阻塞,而中断处理的上半部不可以。所以在写驱动代码如字符设备驱动,实现读操作时是可以让其sleep的(比如没有数据时候,用户设置读模式是阻塞型的)。另一方面,如果该驱动读操作过于耗时也是不可取的,它在内核态中执行,这个时候只有中断的优先级比它高,其它的高优先级线程将不能得到及时调度执行。

    另外,思考一下为什么在中断的下半部如tasklet中不能做阻塞的操作,而系统调用却可以?

    首先,系统调用过程中阻塞意味着阻塞时(内核模式中)当前上下文放在当前线程栈中,同时系统调用所在线程状态改变(比如调用wait_event),下次改线程再次被调度后就可以从阻塞点继续run,这整个过程和一个普通线程阻塞并再次调度的过程是一样的,唯一的区别在于系统调用的阻塞点是在内核模式下。而下半部则不一样,作为中断处理的一个例程逻辑上不属于某个线程,所以它阻塞时第一不能改变当前线程的状态(而wait_semaphore之类的函数则会),其次它在阻塞的情况下再次run的点是在被中断线程再次被调度后,这也是不合理的,因为它不是该线程的一部分,凭什么让它的运行时间受限于该线程的调度时机?

  • 相关阅读:
    【模板】并查集
    P1063能量项链
    多维动归第一题
    7.14测试
    7.12测试
    7.10测试
    几种display:table-cell的应用
    instanceof和typeof的区别
    右侧悬浮广告
    JavaScript判断浏览器类型及版本
  • 原文地址:https://www.cnblogs.com/RandyQ/p/3522687.html
Copyright © 2011-2022 走看看