linux多进程通过中断实现,关于Linux内核源码中是如何区别进程上下文和中断上下文...
关于进程上下文和中断上下文区别定义什么的,网上一搜一大把,但是我关心的是,内核是如何实现这种区分的。看了半天源码(不是最新的),得出结果如下:
首先在内核初始化的时候,会调用init_IRQ来初始化中断描述符表中,关于中断的部分,部分代码如下:
458 for (i = 0; i < NR_IRQS; i++) {
459 int vector = FIRST_EXTERNAL_VECTOR + i;
460 if (vector != SYSCALL_VECTOR)
461 set_intr_gate(vector, interrupt[i]);
462 }
可见,对于特定中断,中断描述符表中存放的函数指针为interrupt[i].那么该函数指针数组又是哪里定义的呢?
101 #define IRQ(x,y) \
102 IRQ##x##y##_interrupt
103
104 #define IRQLIST_16(x) \
105 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
106 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
107 IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
108 IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
109
110 void (*interrupt[NR_IRQS])(void) = {
111 IRQLIST_16(0x0),
112
113 #ifdef CONFIG_X86_IO_APIC
114 IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
115 IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
116 IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
117 IRQLIST_16(0xc), IRQLIST_16(0xd)
118 #endif
119 };
通过宏IRQLIST_16(nr)来生成对应的函数指针,最终的函数指针形式像这样:IRQ0x00_interrupt,IRQ0x01_interrupt…
那么这些函数又是在哪里定义的呢?
113 #define IRQ_NAME2(nr) nr##_interrupt(void)
114 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
...
175 #define BUILD_IRQ(nr) \
176 asmlinkage void IRQ_NAME(nr); \
177 __asm__( \
178 "\n"__ALIGN_STR"\n" \
179 SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
180 "pushl $"#nr"-256\n\t" \
181 "jmp common_interrupt");
通过BUILD_IRQ(nr)宏来生成对应的函数。
而这些BUILD_IRQ宏在编译阶段静态实现:
141 BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */
142 BUILD_IRQ(3, 0x08)
143 BUILD_IRQ(4, 0x10)
144 BUILD_IRQ(5, 0x20)
145 BUILD_IRQ(6, 0x40)
146 BUILD_IRQ(7, 0x80)
147 BUILD_IRQ(8, 0x100)
148 BUILD_IRQ(9, 0x200)
149 BUILD_IRQ(10, 0x400)
150 BUILD_IRQ(11, 0x800)
151 BUILD_IRQ(12, 0x1000)
152 BUILD_IRQ(13, 0x2000)
153 void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */
154 void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
155 BUILD_IRQ(16, 0x10000)
156 BUILD_IRQ(17, 0x20000)
157 BUILD_IRQ(18, 0x40000)
158 BUILD_IRQ(19, 0x80000)
159 BUILD_IRQ(20, 0x100000)
160 BUILD_IRQ(21, 0x200000)
161 BUILD_IRQ(22, 0x400000)
162 BUILD_IRQ(23, 0x800000)
163 BUILD_IRQ(24, 0x1000000)
164 BUILD_IRQ(25, 0x2000000)
165 /* IRQ 26-30 are reserved */
166 BUILD_IRQ(31, 0x80000000)
而每个IRQ0x**_interrupt最终调用的都是函数do_IRQ。而该函数会调用preempt_count_add(HARDIRQ_OFFSET)来标识当前内核处于中断上下文。
对于系统调用,在trap_init中写入中断描述符表,
986 set_system_gate(SYSCALL_VECTOR,&system_call);
对应的函数指针为system_call,对应的函数定义为:
202 ENTRY(system_call)
203 pushl %eax # save orig_eax
204 SAVE_ALL
205 GET_CURRENT(%ebx)
206 testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
207 jne tracesys
208 cmpl $(NR_syscalls),%eax
209 jae badsys
210 call *SYMBOL_NAME(sys_call_table)(,%eax,4)
211 movl %eax,EAX(%esp) # save the return value
212 ENTRY(ret_from_sys_call)
213 cli # need_resched and signals atomic test
214 cmpl $0,need_resched(%ebx)
215 jne reschedule
216 cmpl $0,sigpending(%ebx)
217 jne signal_return
218 restore_all:
219 RESTORE_ALL
调用特定处理函数的地方为:
210 call *SYMBOL_NAME(sys_call_table)(,%eax,4)
在系统调用表中查找对应系统调用号的处理函数。 而该处理函数集合没有调用preempt_count_add(HARDIRQ_OFFSET),因此当前内核处于进程上下文。 这就是为什么系统调用也属于中断(int 0x80),但是却属于进程上下文,而不属于中断上下文的原因。
linux多进程通过中断实现,关于Linux内核源码中是如何区别进程上下文和中断上下文...相关推荐
- Linux内核源码中使用宏定义的若干技巧
在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...
- 解析Linux内核源码中数据同步问题丨C++后端开发丨Linux服务器开发丨Linux内核开发丨驱动开发丨嵌入式开发丨内核操作系统
剖析Linux内核源码数据同步 1.pdflush机制原理 2.超级块同步/inode同步 3.拥塞及强制回写技术 视频讲解如下,点击观看: 解析Linux内核源码中数据同步问题丨C++后端开发丨Li ...
- 内核源码中版本号详解(KERNEL_VERSION KERNEL_VERSION)
1.内核源码中版本的定义 VERSION = 2 #主版本号 PATCHLEVEL = 6 #主版本号 SUBLEVEL = 35 #更次的版本号 EXTRAVERSION = .7 #更更次的版本号 ...
- 【内核驱动】 在内核源码中添加第一个驱动程序
开发环境: Redhat6.5 开发板: Tiny4412 (ARM Cortex A9) 1. 在内核源码中创建自己的目录 2. 在对应的目录中创建源文件和Makefile文件 3. 对应文件 ...
- linux/usr/src/kernels 目录下没有内核源码 解决方法
有时我们在安装系统后,发现没有安装当前系统的内核源码在/usr/src/kernels目录下,其实我们是少安装了一个rpm包: 当你配置好yum源后,然后安装下面的包就可以了: 针对CentOS系统: ...
- lmx6q开发板android,iTOP-i.MX6Q开发板在内核源码中以modules的方式编译驱动
本文档主要讲解在iTOP-i.MX6Q开发板,设备树内核中以 modules 方式编译驱动. 这里以 imx6q(imx6d 和 plus 的类似)的 qt 系统内核编译为例,Ubuntu16 的内核 ...
- Linux 内核源码中likely()和unlikely()
ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value) if (likely ...
- Linux 内核源码中likely()和unlikely()释疑
为什么80%的码农都做不了架构师?>>> ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likel ...
- 【驱动】在内核源码中添加驱动程序
以wifi驱动(RTL8188EUS驱动)为例 添加源码 将源码rtl8188EUS添加到drivers/net/wireless/rtl818x/目录下 添加Kconfig 在drivers/net ...
- 分析linux启动内核源码
内核的启动时从main.c这个文件里面的start_kernel函数开始的,这个文件在linux源码里面的init文件夹下面 下面我们来看看这个函数 这个函数很长,可以看个大概过去 asmlinkag ...
最新文章
- Property ‘configuration‘ and ‘configLocation‘ can not specified with together
- MaskedTextBox的聚焦和光标位置
- Index of sql server
- Linux 修改用户名的主目录 家目录
- 【Flink】Flink 流处理 Sum操作 Table is not an append-only table. Use the toRetractStream() in order to hand
- 地方旅游产业运行监测与应急指挥平台/旅游资源管理平台/旅游产业监测平台/旅游应急指挥平台/旅游资源统计/旅游线路数据/旅游产业可视化大屏管理系统/餐饮场所数据/游客流量监测/景区数据监测/视频监控
- Ubuntu上安装OpenGL
- Pwn2Own黑客大赛战况:iPhone 20秒被黑
- 列表左右移动 2017-03-23
- 数字证书是什么原理,有什么作用?
- 转运RNA(tRNA)甲基化修饰7-甲基胞嘧啶(m7C)|tRNA-m7G
- ovs-vsctl设置ofport不成功处理
- 论开学第三个月干了点啥
- 什么是区块链?详细介绍区块链。
- 黑帽技术以及百度惩罚网站的原因和方式以及解决方式
- 64位 计算机 最大内存,64位操作系统能支持多大的内存?计算方法是什么?
- 嘉宾介绍 | 2020 PG亚洲大会中文分论坛:潘娟
- Game Engine
- 【Git】制造冲突以及解决冲突的详细方法
- [转]nbsp;有刷、有感和无刷…
热门文章
- Flash上传文件(结合asp.net) (转)
- Atitit 常用的登录认证法 目录 2. 表单验证	1 3. OAuth 认证	1 4. Web票据模式验证	1 4.1. Token验证	1 4.2. Cookie-Session 认证	1
- Atitit lucence 使用总结 目录 1. 基本概念	1 1.1. Index:索引库,文档的集合组成索引。	1 2. 建立索引	2 2.1. Api查询	2 2.2. Dsl查询	3
- Atitit 架构之道 之 可读性可维护性架构之道 提升效率架构之道 attilax著 艾龙 著 1.1. Hybrid架构	1 1.2. 分层架构是使用最多的架构模式 Layers模式 也称Tie
- Atiitt 使用java语言编写sql函数或存储过程
- Atitit 会话层和表示层的异同
- Atitit.自然语言处理--摘要算法---圣经章节旧约39卷概览bible overview v2 qa1.docx
- atitit 短信验证码的源码实现 .docx
- atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect
- java webservice 开发总结