Linux Context , Interrupts 和 Context Switching 说明

 

 

. 进程Context 定义

       当一个进程在执行时, CPU的所有寄存器中的值、进程的状态以及堆栈中的内容,比如各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。这些信息被称为该进程的上下文(Context).

 

       一个进程的Context可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文:

       1)用户级上下文: 正文、数据、用户堆栈以及共享存储区;
       2)寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP)
       3)系统级上下文: 进程控制块task_struct、内存管理信息(mm_structvm_area_structpgdpte)、内核栈。

 

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

 

       Linux Vmstat 命令中的system下,有interrupts context switching 选项。

 

[root@db1 ~]# vmstat 2

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------

 r  b  swpd  free buff cache  si   so  bi   bo  in   cs  us sy id wa st

 0  0 23524 13660 62952 651628  0   0    6   14   45  34 0 1 99 0 0

 1 0 23524 13660 62952 651656  0   0    0    0   93   62  0 0 100 0 0

 

其中的in 表示interrupts cs 表示contxt switching

in: The number of interrupts per second, including the clock.

cs: The number of context switches per second.

 

       Unix vmstat 命令

       http://www.cndba.cn/Dave/article/685

 

 

. Interrupts and Context Switching

       To drastically simplify how computers work, you could say that computers do nothing more that shuffle bits (i.e. 1s and 0s) around. All computer data is based on these binary digits, which are represented in computers as voltages (5 V for a 1 and 0 V for a 0), and these voltages are physically manipulated through transistors, circuits, etc... When you get into the guts of a computer and start looking at how they work, it seems amazing how many operations it takes to do something simple, like addition or multiplication. Of course, computers have gotten a lot smaller and thus a lot faster, to the point where they can perform millions of these operations per second, so it still feels fast. The processor is performing these operations in a serial fashion - basically a single-file line of operations.

 

1.1 what is Context switching

       This single-file line could be quite inefficent and there are times when you want a computer to be processing many different things at once, rather than one thing at a time. For example, most computers rely on peripherals for input, but those peripherals are often much slower than the processor itself. For instance, when a program needs some data, it may have to read that data from the hard drive first. This may only take a few milliseconds, but the CPU would be idle during that time - quite inefficient. To improve efficiency, computers use multitasking. A CPU can still only be running one process at a time, but multitasking gets around that by scheduling which tasks will be running at any given time. The act of switching from one task to another is called Context Switching.

       --CPU 一次只能运行一个进程,在multitasking 下,CPU 处理的进行需要从硬盘读取一些数据时,虽然这个时间也是按miliseconds来计算,但是这个时间还是要比CPU 运算的时间长,所以在CPU 的这个等待的时间里,可以将当前处理的task 切换出去,让CPU 去处理其他的task这个过程就叫作Context switch

 

       Ironically, the act of context switching adds a fair amount of overhead to the computing process. To ensure that the original running program does not lose all its progress, the computer must first save the current state of the CPU in memory before switching to the new program. Later, when switching back to the original, the computer must load the state of the CPU from memory. Fortunately, this overhead is often offset by the efficiency gained with frequent context switches.

       --为了保证之前的程序没有丢失它的进程,电脑必须先在内存中保存当前CPU的状态,然后才能进行task switch

       当要切换到之前的task时,将之前保存在内存中的cpu状态装载到CPU就可以了。

 

1.2  Context switch: steps

       In a switch, the state of the first process must be saved somehow, so that, when the scheduler gets back to the execution of the first process, it can restore this state and continue.

       The state of the process includes all the registers that the process may be using, especially the program counter, plus any other operating system specific data that may be necessary. This data is usually stored in a data structure called a process control block (PCB), or switchframe.

       -- process 中的信息保存在一个叫PCB的数据结构中。

       In order to switch processes, the PCB for the first process must be created and saved. The PCBs are sometimes stored upon a per-process stack in kernel memory (as opposed to the user-mode stack), or there may be some specific operating system defined data structure for this information.

       --在进行switch processes时,必须先创建当前运行processPCB 并将该PCB 保存到kernel memory中。

 

       Since the operating system has effectively suspended the execution of the first process, it can now load the PCB and context of the second process. In doing so, the program counter from the PCB is loaded, and thus execution can continue in the new process. New processes are chosen from a queue or queues. Process and thread priority can influence which process continues execution, with processes of the highest priority checked first for ready threads to execute.

       -- 将根据进程的优先级从队列中选择装载哪个进程去运行。

 

 

1.3 What is Interrupt?

       If you can do context switches frequently enough, the computer appears to be doing many things at once (even though the CPU is only processing a single task at any given time). Signaling the CPU to do a context switch is often accomplished with the use of a command called an Interrupt. For the most part, the computers we're all using are Interrupt driven, meaning that running processes are often interrupted by higher-priority requests, forcing context switches.

       -- 虽然CPU 一次只能处理一个进程,但只要context switch 足够频繁,我们还是可以感觉CPU 同时在处理多个tasks. CPU 根据指令去进行context switch 的过程就叫做Interrupt.

       Interrupt 可以是有高优先级的进程申请,或者是强制的context switches

 

Fromhttp://kaedrin.com/weblog/archive/001657.html

 

 

.  Interrupt Context  Process Context

 

处理器总处于以下三种状态之一:

       1.内核态,运行于Process context,内核代表进程运行于内核空间;
       2.内核态,运行于Interrupt Context,内核代表硬件运行于内核空间;
       3.用户态,运行于用户空间。

 

       用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存 器值、变量等。

       进程上下文: 可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等


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

 

 

3.1  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.

 

3.2  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.

 

3.3  Process Context Interrupt Context 区别

       1. The main difference between process context and interrupt context is that process context can block, while interrupt context can’t.

       2.Interrupt context mean that there will not be scheduling taking place until and unless that task ends while in the process context every task gets the CPU time

 

 

 

 

 

整理自网络

-------------------------------------------------------------------------------------------------------

QQ:492913789

Email:ahdba@qq.com

Blog: http://www.cndba.cn/dave


DBA1 群:62697716();   DBA2 群:62697977()   DBA3 群:62697850()  

DBA 超级群:63306533();  DBA4 群: 83829929  DBA5群: 142216823   

DBA6 群:158654907  聊天 群:40132017   聊天2群:69087192

--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请

<think>嗯,用户想了解Linux如何保存中断号ID并逐一读取。首先,我需要回忆一下Linux内核处理中断的机制。中断号,也就是IRQ号,在内核中是怎么管理的呢? 对了,Linux使用中断描述符表(IDT)来管理中断异常处理程序。每个中断号对应一个条目,里面存了处理函数的地址等信息。那中断号的具体保存读取可能涉及到内核的数据结构,比如数组或者链表。 接下来,中断号的分配。现代系统可能使用动态中断号,比如PCI设备的中断。内核需要维护一个数据结构来跟踪已分配的中断号,防止冲突。可能用了位图或者散列表来管理这些ID。 然后,当硬件触发中断时,CPU会通过中断控制器(如APIC)将中断号传递给内核。内核的中断处理入口,比如do_IRQ()函数,会接收这个中断号,并查找对应的处理函数执行。这里可能需要读取寄存器或者从特定数据结构中获取中断号。 另外,用户提到“逐一读取”,可能是指遍历所有已注册的中断处理程序。内核可能有/proc/interrupts这个虚拟文件,里面记录了每个中断号的发生次数处理函数。读取这个文件就能逐个查看中断信息,这涉及到内核模块在proc文件系统中的实现。 还要考虑中断号的保存,可能是在中断发生时,CPU将中断号保存在某个寄存器或栈中,然后由内核保存到进程上下文或中断处理结构体里。例如,在x86架构中,中断向量号会被压入栈,供后续处理使用。 需要确认的是,不同架构的处理方式可能不同,比如ARMx86在中断处理上的差异。但用户可能更关心通用流程,而不是特定架构的细节。 总结一下,回答应该分步骤说明中断号的保存(注册时分配ID,保存在数据结构中)读取(通过中断处理函数获取,或查看/proc/interrupts)。要确保提到关键的数据结构系统文件,帮助用户理解整体机制。</think>在Linux内核中,中断号(IRQ)的管理读取涉及以下关键机制: 1. **中断号保存机制** - **静态分配**:传统设备(如串口、键盘)使用预定义IRQ号,保存在`arch/xxx/kernel/irq.c`的静态表中 - **动态分配**:现代设备(如PCIe)使用`irq_domain`框架动态分配IRQ,通过`irq_create_mapping()`生成逻辑IRQ号 - **数据结构存储**:内核使用`radix_tree`或`xarray`数据结构管理IRQ描述符,每个IRQ对应一个`irq_desc`结构体: ```c struct irq_desc { struct irq_data irq_data; irq_flow_handler_t handle_irq; struct irqaction *action; // 中断处理程序链表 // ... }; ``` 2. **中断触发处理流程** 当硬件中断发生时: ```text CPU接收中断 → 读取APIC寄存器获取物理IRQ号 → 转换为逻辑IRQ号 → 调用do_IRQ() ``` 关键函数调用路径: ```c do_IRQ(irq) → handle_irq_event(desc) → __handle_irq_event_percpu(desc) → action->handler(irq, action->dev_id) // 执行注册的中断处理程序 ``` 3. **中断信息读取方式** - **系统级查看**: ```bash cat /proc/interrupts # 显示所有IRQ号、触发次数及关联设备 CPU0 CPU1 0: 45 0 IO-APIC 2-edge timer 7: 1 0 IO-APIC 7-fasteoi virtio0 ``` - **内核调试接口**: ```c // 通过GDB调试内核时查看irq_desc数组 (gdb) p irq_desc[16] $1 = {irq_data = {irq = 16, hwirq = 16...}, action = 0xffff888107c8e800...} ``` - **硬件寄存器读取**: ```c // 对于x86架构,直接读取APIC寄存器 unsigned int irq = apic_read(APIC_RRR); ``` 4. **中断遍历机制** 内核通过`for_each_active_irq()`宏遍历已注册IRQ: ```c unsigned int irq; for_each_active_irq(irq) { struct irq_desc *desc = irq_to_desc(irq); if (desc->action) printk("IRQ %d handler: %ps\n", irq, desc->action->handler); } ``` 5. **关键API接口** - 注册中断: ```c request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev); ``` - 释放中断: ```c free_irq(unsigned int irq, void *dev_id); ``` - 获取中断信息: ```c int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool *state); ``` 实际开发中建议优先使用`/proc/interrupts`进行状态检查,直接操作硬件寄存器需要深入理解具体芯片架构。对于动态分配的中断号,应通过`pci_irq_vector()`等设备驱动接口获取,而非硬编码IRQ值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值