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),但是却属于进程上下文,而不属于中断上下文的原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值