《深入理解Linux内核》--第四章 中断和异常:读书笔记

      同步中断:只有在一条指令终止执行后CPU才会发出中断; 
      异步中断:由其它硬件设备依照CPU时钟信号随机产生的中断。
      一般中断是指 异步中断。异常: 同步中断。

     中断处理与进程切换的区别:中断或异常处理程序执行的代码不是一个进程,它是一个内核控制内经,代表中断发生时正在运行的进程执行。作为一个内核控制路径,中断处理程序比一个进程要“轻”。(没有进程要求那么多资源)

一、中断
      分为:1)可屏蔽中断(maskable Interrupt);2)非屏蔽中断(nonmaskable Interrupt)
    1)IRQ
      IRQ线(即 外部中断 线):每个能够发出中断请求的硬件设备都有一条IRQ输出线,所有IRQ Line都和PIC硬件电路的输入引脚相连。PIC主要是用来监控IRQ线的信号。如果有信号产生则把信号向量发送到处理器的INTR引脚,产生一个中断。
     IRQ分配给I/O时,一个IRQ的序号对应一个INT序号,INT序号即为CPU的INTR引脚序号。
     IRQ从0开始编号,IRQn一般对应于Intel的缺省向量n+32。(注意LInux的128号向量用于系统调用的可编程的异常,32~127,129~238都用于IRQ)
     中断请求在多处理器系统中分发方式:静态分发,动态分发。
     数据结构式:irq_desc_t[NR_CPU],每个CPU对应一个irp_desc_t描述符
     
     在多处理器系统中,kirqd()内核线程周期性执行do_irq_balance()函数,追踪最近时间间隔内每个CPU接收的中断次数。如果负荷不均匀,要么把一个IRQ从一个CPU转移到另一个CPU,要么让所有的IRQ在所有CPU之间“轮转”。

     thread_info进程描述符:
   union thread_union{
          struct thread_info thread_info;
          unsigned long stack[2048]; /*对4k的栈数组下表是1024 ,long是4byte */
    }
     如果为thread_union为8kB,则进程的内核栈被用于所有的内核控制路径:异常、中断和可延迟函数。(总共<=8K)
     如果thread_union为4KB,则内核有三种类型的内核:异常栈、硬件请求栈(中断)、软中断请求栈(可延迟),它们是4KB对齐的,但是如果8KB的又都可以容下。

      do_IRQ()函数执行与一个中断相关的所有中断服务例程,_ _do_IRQ()函数用于禁止本地中断运行。

     I/O中断处理,两种不同方式:IRQ共享,IRQ动态分配
   2)IDT
    中断描述符表是一个系统表,内核在允许中断前必须初始化IDT,用lidt汇编指令初始化idtr。idtr CPU寄存器使 IDT可以位于内存的任何地方,idtr指定IDT的线性基地址及其限制(最大长度)。
   描述符类型:task gate(任务门)、Interrupt gate、Trap gate
   在初始化中断描述符表时,需要防止用户(用户态) int  指令(软件中断)模拟非法的中断和异常,通过吧中断或陷阱门描述符的DPL字段设置成0来实现。控制单元通过检查CPL 与 DPL的字段,如果不都为0(内核态)则有冲突,产生异常。

二、异常 (Divide error,Overflow,Double fault之类)
     分为:1)故障(fault); 2)陷阱(trap);3)abort(异常中止);4)programmed exception(编程异常)
   fault 和 trap 的区别:fault只要处理程序能纠正引起异常的反常条件,重新执行同一指令时必要的
                                    trap只有当没有必要重新执行已终止的指令时,才触发trap。

三、中断和异常的硬件处理
      注意的地方:
      1)需要比较CPL和DPL,如果CPL(0,内核态)小于DPL(3,用户态),则发生异常
      2)在处理完后,相应的处理程序需要产生一条iret指令(非ret指令,ret用于用户程序)
         在返回后,需要检查ds、es、fs和gs段寄存器的内容,如果其中一个包含的选择符是一个段描述符,并且DPL(0)值小于CPL(3)(也就是说当前的为用户态),需要清除相应的段寄存器。为了禁止用户态程序利用以前所用的段寄存器(DPL=0),恶意利用它们来访问内核地址空间。
      3)内核控制路径嵌套执行。中断处理程序运行期间不允许进程切换。
         异常处理程序引发 相关的 至多两个内核控制路径(第一个由系统调用引起,第二个由(缺页)异常)。

四、软中断(softirq) 和 tasklet
      软中断可以并发地运行在多个CPU上。是可重入函数,必须明确地使用自旋锁保护其数据结构。
      tasklet:同类型的tasklet总是被串行地执行,不能再两个CPU上同时运行相同类型的tasklet(类型不同的tasklet可以,分为普通的TASTKLET_SOFTIQT和HI_SOFTIRQ两种,即普通的和高级的)。是可重入的函数。
      1)软中断
      软中断对应的处理函数是:do_softirq(),使用的数据结构:softirq_vec[n].
      preempt_count的字段中各位意思:抢占计数器(0~7)、软中断计数器(8~15)、硬中断计数器(16~27)、PREEMPT_ACTIVE标志(28)
      in_interrupt()检查current_thread_info()->preempt_count字段的硬中断计数器和软中断计数器,只要这两个计数器中的一个值为正数,该宏就产生一个非零值。
      raise_softirq()激活软中断,wakeup_softiqrd()唤醒本地CPU的ksoftirqd内核线程,do_softirq()来处理检测到的被挂起的软中断,_ _do_softirq()读取本地CPU的 软中断掩码 并执行与每个设置位相关的可延迟函数。
     ksoftirq内核线程 解决了软中断的连续高流量(如网络中断)可能产生的问题。其代码如下:
           for(::){
                set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                while(local_softirq_pending()){
                      preempt_disable();
                      do_softirq();
                      preempt_enable();
                      cond_resched();
                }
           }

     
      2)tasklet
     TASKLET_SOFTIRQ软中断类型对应的处理函数是:tasklet_action(),数据结构:tasklet_vec[n]
      HI_SOFTIRQ软中断对应的处理函数:tasklet_hi_action(),数据结构:tasklet_hi_vec[n]
      I/O驱动程序实现可延迟函数的首选方法:tasklet。
      在tasklet_vec[n]或tasklet_hi_vec[n]指向的链表起始处增加taskl描述符(n表示本地CPU的逻辑号)
      调用raise_softirq_irqoff()激活TASKLET_SOFTIRQ或HI_SOFTIRQ类型的软中断。

五、工作队列
      描述符:workqueue_struct,数组元素个数:NR_CPUS
      工作队列和可延迟函数(软中断)的区别:可延迟函数运行在中断上下文中,工作队列中的函数运行在进程上下文中。
        相同:他们都不能访问进程的用户态地址空间。
       工作队列的函数是有内核线程来执行的。

六、从中断和异常返回
     1) ret_from_intr() 和 ret_from_exception() 入口点相当于:
      ret_from_exception:
          cli; missing if kernel preemption is not supported
     ret_from_intr:
          movl $-8192, %ebp ;  -4096 if multiple Kernel Mode Stacks are used;8192(8K)
          andl %esp,  %ebp
          movl 0x30(%esp), %eax
          movb 0x2c(%esp), %a1
          test1 $0x00020003, %eax
         jnz     resume_userspace
         jpm    resume_kernel
    如果被恢复的程序在内核态,就需要resum_kernel,检查thread_info描述符的preempt_count字段,若为0则内核跳到need_resched检查内核抢占,所有没有执行完的内核控制路径都不是中断处理程序,否则preempt_count字段的值就会大于0。若preempt_count为不为0,则被中断的程序重新开始执行(直接restore_all)
     在need_resched中,如果current->thread_info的flags字段中的TIF_NEED_RESCHED标志为0,说明没有需要切换进程,直接跳到restore_all恢复用户态程序。如果TIF_NEED_RESCHED不为0,则调用preempt_schedule_irq(),设置preempt_count字段的PREEMPT_ACTIVE标志,把大内核锁计数器暂时设置为-1,打开本地中断调用schedule()选择另一个进程运行;当前面的进程要恢复是,preempt_schedule_irq()使大内核计数器的值恢复为以前的值,清除PREEMPT_ACTIVE标志并且禁用本地中断。
    resume_userspace,检查cureent->thread_info的flags字段的值,如果只设置了TIF_SYSCALL_TRACE、TIF_SYSCALL_AUDIT或TIF_SINGLESTEP标志,就不做任何其他事情,直接跳到restore_all,恢复用户程序。

七、附录
    
常见缩写:
IRQ(Interrupt ReQuest)中断请求
PIC(Programmable Interrupt Controller)可编程中断控制器
cli(clear Interrupt)、sti(set Interrupt)汇编指令分别清除和设置eflags寄存器的IF(Interrupt Flag)标志。
APIC(I/O Advanced Programmable Interrupt Controller)I/O高级可编程控制器
IRT(Interrupt Redirection Table)中断重定向表
IDT (Interrupt Descriptor Table)中断描述符表
DPL (Descriptor Priviledge Level) 描述符特权等级

内核中比较重要的函数、宏及变量
local_irq_save()用来保存IF标志的状态并禁用本地中断
local_irq_restore()恢复IF标志的状态
do_IRQ()
_ _do_IRQ()
set_task_gate(8,31);表示存放IDT的第8想中的任务门描述符,指向存放在GDT表中第32项的TSS段描述符。
preempt_count抢占计数字段,preempt中文意思:抢占
do_softirq(),检测到挂起的软件中断,内核调用该函数来处理它们。
_ _do_softirq()
ksoftirq/n内核线程(n为CPU的逻辑号)

 

注:这书里面挺侧重分析 多处理器 架构,Linux内核对多处理器的支持做了很多工作。
PS:这一章后面一些看的比较快,比较草率~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Preface The Audience for This Book Organization of the Material Level of Description Overview of the Book Background Information Conventions in This Book How to Contact Us Safari? Enabled Acknowledgments Chapter 1. Introduction Section 1.1. Linux Versus Other Unix-Like Kernels Section 1.2. Hardware Dependency Section 1.3. Linux Versions Section 1.4. Basic Operating System Concepts Section 1.5. An Overview of the Unix Filesystem Section 1.6. An Overview of Unix Kernels Chapter 2. Memory Addressing Section 2.1. Memory Addresses Section 2.2. Segmentation in Hardware Section 2.3. Segmentation in Linux Section 2.4. Paging in Hardware Section 2.5. Paging in Linux Chapter 3. Processes Section 3.1. Processes, Lightweight Processes, and Threads Section 3.2. Process Descriptor Section 3.3. Process Switch Section 3.4. Creating Processes Section 3.5. Destroying Processes Chapter 4. Interrupts and Exceptions Section 4.1. The Role of Interrupt Signals Section 4.2. Interrupts and Exceptions Section 4.3. Nested Execution of Exception and Interrupt Handlers Section 4.4. Initializing the Interrupt Descriptor Table Section 4.5. Exception Handling Section 4.6. Interrupt Handling Section 4.7. Softirqs and Tasklets Section 4.8. Work Queues Section 4.9. Returning from Interrupts and Exceptions Chapter 5. Kernel Synchronization Section 5.1. How the Kernel Services Requests Section 5.2. Synchronization Primitives Section 5.3. Synchronizing Accesses to Kernel Data Structures Section 5.4. Examples of Race Condition Prevention Chapter 6. Timing Measurements Section 6.1. Clock and Timer Circuits Section 6.2. The Linux Timekeeping Architecture Section 6.3. Updating the Time and Date Section 6.4. Updating System Statistics Section 6.5. Software Timers and Delay Functions Section 6.6. System Calls Related to Timing Measurements Chapter 7. Process Scheduling Section 7.1. Scheduling Policy Section 7.2. The Scheduling Algorithm Section 7.3. Data Structures Used by the Scheduler Section 7.4. Functions Used by the Scheduler Section 7.5. Runqueue Balancing in Multiprocessor Systems Section 7.6. System Calls Related to Scheduling Chapter 8. Memory Management Section 8.1. Page Frame Management Section 8.2. Memory Area Management Section 8.3. Noncontiguous Memory Area Management Chapter 9. Process Address Space Section 9.1. The Processs Address Space Section 9.2. The Memory Descriptor Section 9.3. Memory Regions Section 9.4. Page Fault Exception Handler Section 9.5. Creating and Deleting a Process Address Space Section 9.6. Managing the Heap Chapter 10. System Calls Section 10.1. POSIX APIs and System Calls Section 10.2. System Call Handler and Service Routines Section 10.3. Entering and Exiting a System Call Section 10.4. Parameter Passing Section 10.5. Kernel Wrapper Routines Chapter 11. Signals Section 11.1. The Role of Signals Section 11.2. Generating a Signal Section 11.3. Delivering a Signal Section 11.4. System Calls Related to Signal Handling Chapter 12. The Virtual Filesystem Section 12.1. The Role of the Virtual Filesystem (VFS) Section 12.2. VFS Data Structures Section 12.3. Filesystem Types Section 12.4. Filesystem Handling Section 12.5. Pathname Lookup Section 12.6. Implementations of VFS System Calls Section 12.7. File Locking Chapter 13. I/O Architecture and Device Drivers Section 13.1. I/O Architecture Section 13.2. The Device Driver Model Section 13.3. Device Files Section 13.4. Device Drivers Section 13.5. Character Device Drivers Chapter 14. Block Device Drivers Section 14.1. Block Devices Handling Section 14.2. The Generic Block Layer Section 14.3. The I/O Scheduler Section 14.4. Block Device Drivers Section 14.5. Opening a Block Device File Chapter 15. The Page Cache Section 15.1. The Page Cache Section 15.2. Storing Blocks in the Page Cache Section 15.3. Writing Dirty Pages to Disk Section 15.4. The sync( ), fsync( ), and fdatasync( ) System Calls Chapter 16. Accessing Files Section 16.1. Reading and Writing a File Section 16.2. Memory Mapping Section 16.3. Direct I/O Transfers Section 16.4. Asynchronous I/O Chapter 17. Page Frame Reclaiming Section 17.1. The Page Frame Reclaiming Algorithm Section 17.2. Reverse Mapping Section 17.3. Implementing the PFRA Section 17.4. Swapping Chapter 18. The Ext2 and Ext3 Filesystems Section 18.1. General Characteristics of Ext2 Section 18.2. Ext2 Disk Data Structures Section 18.3. Ext2 Memory Data Structures Section 18.4. Creating the Ext2 Filesystem Section 18.5. Ext2 Methods Section 18.6. Managing Ext2 Disk Space Section 18.7. The Ext3 Filesystem Chapter 19. Process Communication Section 19.1. Pipes Section 19.2. FIFOs Section 19.3. System V IPC Section 19.4. POSIX Message Queues Chapter 20. Program ExZecution Section 20.1. Executable Files Section 20.2. Executable Formats Section 20.3. Execution Domains Section 20.4. The exec Functions Appendix A. System Startup Section A.1. Prehistoric Age: the BIOS Section A.2. Ancient Age: the Boot Loader Section A.3. Middle Ages: the setup( ) Function Section A.4. Renaissance: the startup_32( ) Functions Section A.5. Modern Age: the start_kernel( ) Function Appendix B. Modules Section B.1. To Be (a Module) or Not to Be? Section B.2. Module Implementation Section B.3. Linking and Unlinking Modules Section B.4. Linking Modules on Demand Bibliography Books on Unix Kernels Books on the Linux Kernel Books on PC Architecture and Technical Manuals on Intel Microprocessors Other Online Documentation Sources Research Papers Related to Linux Development About the Authors Colophon Index

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值