关于进程上下文和中断上下文区别定义什么的,网上一搜一大把,但是我关心的是,内核是如何实现这种区分的。看了半天源码(不是最新的),得出结果如下:

首先在内核初始化的时候,会调用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内核源码中是如何区别进程上下文和中断上下文...相关推荐

  1. Linux内核源码中使用宏定义的若干技巧

    在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...

  2. 解析Linux内核源码中数据同步问题丨C++后端开发丨Linux服务器开发丨Linux内核开发丨驱动开发丨嵌入式开发丨内核操作系统

    剖析Linux内核源码数据同步 1.pdflush机制原理 2.超级块同步/inode同步 3.拥塞及强制回写技术 视频讲解如下,点击观看: 解析Linux内核源码中数据同步问题丨C++后端开发丨Li ...

  3. 内核源码中版本号详解(KERNEL_VERSION KERNEL_VERSION)

    1.内核源码中版本的定义 VERSION = 2 #主版本号 PATCHLEVEL = 6 #主版本号 SUBLEVEL = 35 #更次的版本号 EXTRAVERSION = .7 #更更次的版本号 ...

  4. 【内核驱动】 在内核源码中添加第一个驱动程序

    开发环境: Redhat6.5 开发板: Tiny4412 (ARM Cortex A9) 1.  在内核源码中创建自己的目录 2. 在对应的目录中创建源文件和Makefile文件   3. 对应文件 ...

  5. linux/usr/src/kernels 目录下没有内核源码 解决方法

    有时我们在安装系统后,发现没有安装当前系统的内核源码在/usr/src/kernels目录下,其实我们是少安装了一个rpm包: 当你配置好yum源后,然后安装下面的包就可以了: 针对CentOS系统: ...

  6. lmx6q开发板android,iTOP-i.MX6Q开发板在内核源码中以modules的方式编译驱动

    本文档主要讲解在iTOP-i.MX6Q开发板,设备树内核中以 modules 方式编译驱动. 这里以 imx6q(imx6d 和 plus 的类似)的 qt 系统内核编译为例,Ubuntu16 的内核 ...

  7. Linux 内核源码中likely()和unlikely()

    ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value) if (likely ...

  8. Linux 内核源码中likely()和unlikely()释疑

    为什么80%的码农都做不了架构师?>>>    ikely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likel ...

  9. 【驱动】在内核源码中添加驱动程序

    以wifi驱动(RTL8188EUS驱动)为例 添加源码 将源码rtl8188EUS添加到drivers/net/wireless/rtl818x/目录下 添加Kconfig 在drivers/net ...

  10. 分析linux启动内核源码

    内核的启动时从main.c这个文件里面的start_kernel函数开始的,这个文件在linux源码里面的init文件夹下面 下面我们来看看这个函数 这个函数很长,可以看个大概过去 asmlinkag ...

最新文章

  1. Property ‘configuration‘ and ‘configLocation‘ can not specified with together
  2. MaskedTextBox的聚焦和光标位置
  3. Index of sql server
  4. Linux 修改用户名的主目录 家目录
  5. 【Flink】Flink 流处理 Sum操作 Table is not an append-only table. Use the toRetractStream() in order to hand
  6. 地方旅游产业运行监测与应急指挥平台/旅游资源管理平台/旅游产业监测平台/旅游应急指挥平台/旅游资源统计/旅游线路数据/旅游产业可视化大屏管理系统/餐饮场所数据/游客流量监测/景区数据监测/视频监控
  7. Ubuntu上安装OpenGL
  8. Pwn2Own黑客大赛战况:iPhone 20秒被黑
  9. 列表左右移动 2017-03-23
  10. 数字证书是什么原理,有什么作用?
  11. 转运RNA(tRNA)甲基化修饰7-甲基胞嘧啶(m7C)|tRNA-m7G
  12. ovs-vsctl设置ofport不成功处理
  13. 论开学第三个月干了点啥
  14. 什么是区块链?详细介绍区块链。
  15. 黑帽技术以及百度惩罚网站的原因和方式以及解决方式
  16. 64位 计算机 最大内存,64位操作系统能支持多大的内存?计算方法是什么?
  17. 嘉宾介绍 | 2020 PG亚洲大会中文分论坛:潘娟
  18. Game Engine
  19. 【Git】制造冲突以及解决冲突的详细方法
  20. [转]nbsp;有刷、有感和无刷…

热门文章

  1. Flash上传文件(结合asp.net) (转)
  2. Atitit 常用的登录认证法 目录 2. 表单验证 1 3. OAuth 认证 1 4. Web票据模式验证 1 4.1. Token验证 1 4.2. Cookie-Session 认证 1
  3. Atitit lucence 使用总结 目录 1. 基本概念 1 1.1.   Index:索引库,文档的集合组成索引。 1 2. 建立索引 2 2.1. Api查询 2 2.2. Dsl查询 3
  4. Atitit 架构之道 之 可读性可维护性架构之道 提升效率架构之道 attilax著 艾龙 著 1.1. Hybrid架构 1 1.2. 分层架构是使用最多的架构模式 Layers模式 也称Tie
  5. Atiitt 使用java语言编写sql函数或存储过程
  6. Atitit 会话层和表示层的异同
  7. Atitit.自然语言处理--摘要算法---圣经章节旧约39卷概览bible overview v2 qa1.docx
  8. atitit 短信验证码的源码实现  .docx
  9. atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect
  10. java webservice 开发总结