|
|
|
|
|
|
|
243 struct softirq_action |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 void (*action)(struct softirq_action *); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 void *data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct softirq_action softirq_vec[32]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local_softirq_pending |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
softirq_vec |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0 |
1 |
2 |
…… |
|
30 |
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
遍历softirq_vec数组,依次执行action(data)函数 |
|
|
|
|
|
|
|
|
229 do { |
|
|
|
|
|
其中有两个比较特殊的地方0和6指定的函数为tasklet_hi_action(NULL)和tasklet_action(NULL) |
|
|
|
|
230 if (pending & 1) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 trace_irq_softirq_entry(h, softirq_vec); |
|
|
|
|
|
|
|
|
|
|
|
232 h->action(h); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 trace_irq_softirq_exit(h, softirq_vec); |
|
|
|
|
|
|
|
|
|
|
|
234 rcu_bh_qsctr_inc(cpu); |
|
|
|
|
|
首先找到tasklet_vec每cpu变量链表的头 |
|
|
|
|
235 } |
|
|
|
|
|
|
|
|
然后赋予listwhile循环从list指向的地方开始执行 |
|
|
|
236 h++; |
|
|
|
|
|
|
|
|
同时把count=1的(锁住的)再次放回到tasklet_vec链表中去 |
|
|
|
237 pending >>= 1; |
|
|
|
|
|
|
|
处理完返回; |
|
|
|
|
|
|
|
238 } while (pending); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
遍历软中断数组softirq_vec |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
系统初始化期间start_kernel函数中调用softirq_init对软中断进行初始化。 |
|
|
|
|
|
|
|
|
|
|
|
|
471 void __init softirq_init(void) |
|
|
|
|
|
|
329 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data) |
|
|
|
|
472 { |
|
6 |
|
|
|
|
|
|
330 { |
|
|
|
|
|
|
|
|
|
|
473 open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); |
|
|
|
331 softirq_vec[nr].data = data; |
|
|
|
|
|
|
|
474 open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); |
|
|
|
332 softirq_vec[nr].action = action; |
|
|
|
|
|
|
|
475 } |
|
0 |
|
|
|
|
|
|
333 } |
|
|
|
|
|
|
|
|
|
|
将数组strcut softirq_action softirq_vec[32]对应的[TASKLET_SOFTIRQ]和[HI_SOFTIRQ]设置好; |
|
|
|
|
|
|
|
|
|
|
222 /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high |
|
|
|
|
|
|
|
|
|
|
|
|
|
223 frequency threaded job scheduling. For almost all the purposes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
224 tasklets are more than enough. F.e. all serial device BHs et |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
225 al. should be converted to tasklets, not to softirqs. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
227 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 enum |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
229 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 HI_SOFTIRQ=0, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 TIMER_SOFTIRQ, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 NET_TX_SOFTIRQ, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 NET_RX_SOFTIRQ, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 BLOCK_SOFTIRQ, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 BLOCK_IOPOLL_SOFTIRQ, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 TASKLET_SOFTIRQ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
软中断还有扩展的余地:struct softirq_action softirq_vec[32];数组只用了前6项 |
|
|
|
|
|
|
|
|
|
|
|
处理软中断的时机do_IRQ完成后 也就是说硬中断完成后,立马去执行软中断,在软中断处理函数中遍历10次softirq_vec数组处理激活的软中断。(__softirq_pending相应位为 |
1 |
|
|
320 void fastcall raise_softirq(unsigned int nr) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
321 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 local_irq_save(flags); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 raise_softirq_irqoff(nr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 local_irq_restore(flags); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
激活软中断。所谓的激活什么? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
#define or_softirq_pending(x) (local_softirq_pending() |= (x)) |
//找到本地CPU的per_cpu_irq_stat变量找出其中的成员__softirq_pending|=(1<<(nr)) 设相应位为1; |
|
|
|
|
|
|
|
7 typedef struct { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 } ____cacheline_aligned irq_cpustat_t; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DECLARE_PER_CPU(irq_cpustat_t, irq_stat); |
extern irq_cpustat_t per_cpu_irq_stat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
do_softirq遍历softirq_vec数组 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 void tasklet_init(struct tasklet_struct *t, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
444 void (*func)(unsigned long), unsigned long data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
445 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 t->next = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
447 t->state = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
448 atomic_set(&t->count, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
449 t->func = func; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
450 t->data = data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 struct tasklet_head |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 struct tasklet_struct *list; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NULL }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
277 struct tasklet_struct |
|
|
|
|
|
do_softirq会扫描这个数组 |
|
|
|
|
|
|
|
|
|
278 { |
|
|
|
|
|
|
|
softirq_vec |
|
|
|
|
|
|
|
|
|
|
|
279 struct tasklet_struct *next; |
|
|
|
|
0 |
1 |
2 |
…… |
|
6 |
…… |
30 |
31 |
|
|
|
280 unsigned long state; |
|
|
|
|
|
|
|
|
281 atomic_t count; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
282 void (*func)(unsigned long); |
|
|
|
|
h |
|
|
|
|
|
|
|
283 unsigned long data; |
per-cpu variable |
|
|
|
|
|
|
|
|
|
|
|
284 }; |
|
|
|
|
… |
|
|
|
|
|
|
|
|
|
|
cpu1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
… |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cpu0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cpu1 |
|
tasklet_struct |
tasklet_struct |
tasklet_struct |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NULL |
|
|
|
|
|
|
|
|
|
|
|
cpu0 |
|
state |
|
state |
|
state |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
count |
|
count |
|
count |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func |
|
func |
|
func |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data |
|
data |
|
data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 #define DECLARE_TASKLET(name, func, data) \ |
|
443 void tasklet_init(struct tasklet_struct *t, |
|
|
|
|
|
|
|
|
|
|
287 struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } |
/* |
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
|
|
|
|
|
Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap
|
|
Bitmap Bitmap |
|
|
|
|
|
|
|
|
|
|
|
289 #define DECLARE_TASKLET_DISABLED(name, func, data) \ |
444 void (*func)(unsigned long), unsigned long data) |
|
|
|
|
|
|
|
|
|
|
|
290 struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data } |
445 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 t->next = NULL; |
|
|
|
|
|
|
|
|
|
|
|
静态的定义一个名字为name的truct tasklet_struct |
|
447 t->state = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
448 atomic_set(&t->count, 0); |
|
|
|
|
|
|
|
|
|
|
|
323 static inline void tasklet_schedule(struct tasklet_struct *t) |
|
449 t->func = func; |
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
450 t->data = data; |
|
|
|
|
|
|
|
|
|
|
|
Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap
|
|
|
|
|
|
451 } |
动态的初始化一个tasklet_struct结构体,现在还有插入到taslet_vec或者tasklet_hi_let链表中 所以还没有机会执行 |
|
|
|
|
324 { |
|
|
|
|
|
|
那么在哪里插入到tasklet_struct链表中的呢?tasklet_schedule()函数中 |
|
|
|
|
|
|
|
325 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) |
//测试t指向的tasklet_struct是否已经在per-cpu链表中 |
|
|
|
|
|
|
|
|
|
326 __tasklet_schedule(t); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 static void tasklet_action(struct softirq_action *a) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap Bitmap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
374 struct tasklet_struct *list; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
377 list = __get_cpu_var(tasklet_vec).list; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
378 __get_cpu_var(tasklet_vec).list = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 struct tasklet_struct *t = list; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 list = list->next; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
386 if (tasklet_trylock(t)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 if (!atomic_read(&t->count)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
388 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
391 t->func(t->data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
393 tasklet_unlock(t); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
395 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
396 tasklet_unlock(t); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
397 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
398 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
400 t->next = __get_cpu_var(tasklet_vec).list; |
|
//将count=1锁住的tasklet继续留在softirq_vec per-cpu变量中。 |
|
|
|
|
|
|
|
|
|
401 __get_cpu_var(tasklet_vec).list = t; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 __raise_softirq_irqoff(TASKLET_SOFTIRQ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
404 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
405 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
455 void tasklet_kill(struct tasklet_struct *t) |
|
|
|
|
|
|
346 void fastcall __tasklet_schedule(struct tasklet_struct *t) |
|
|
|
|
|
/* [previous][next][first][last][top][bottom][index][help] */ |
|
|
|
|
|
/* [previous][next][first][last][top][bottom][index][help] */ |
|
|
|
|
|
456 { |
|
|
|
|
|
|
|
|
|
347 { |
|
|
|
|
|
|
|
|
|
457 if (in_interrupt()) |
|
|
|
|
|
|
|
348 unsigned long flags; |
|
|
|
|
|
|
|
458 printk("Attempt to kill tasklet from interrupt\n"); |
|
|
|
|
349 |
|
|
|
|
|
|
|
|
|
459 |
|
|
|
|
|
|
|
|
|
350 local_irq_save(flags); |
|
|
|
|
|
|
|
460 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { |
|
|
|
351 t->next = __get_cpu_var(tasklet_vec).list; |
|
|
|
|
|
|
461 do |
|
|
|
|
|
|
|
|
352 __get_cpu_var(tasklet_vec).list = t; |
|
|
|
|
|
|
462 yield(); |
|
|
|
|
|
|
|
353 raise_softirq_irqoff(TASKLET_SOFTIRQ); |
|
|
|
|
|
463 while (test_bit(TASKLET_STATE_SCHED, &t->state)); |
|
|
|
|
354 local_irq_restore(flags); |
|
|
|
|
|
|
|
464 } |
|
|
|
|
|
|
|
|
355 } |
|
|
|
|
|
|
|
|
|
465 tasklet_unlock_wait(t); |
|
|
|
|
|
|
|
//将tasklet_struct插入到softirq_vec链表的第一个位置 |
|
|
|
|
|
466 clear_bit(TASKLET_STATE_SCHED, &t->state); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
467 } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//自杀不是他杀~ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static LIST_HEAD(workqueues); |
|
|
|
63 struct workqueue_struct { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 struct cpu_workqueue_struct *cpu_wq; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 const char *name; |
|
|
|
|
|
|
|
|
|
|
|
#define create_workqueue(name) __create_workqueue((name), 0) |
|
66 struct list_head list; /* Empty if single thread */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct workqueue_struct *wq |
|
alloc_percpu分配 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct cpu_workqueue_struct |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lock |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name |
|
remove_sequeuece |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
list |
|
insert_sequeue |
|
work_struct |
|
work_struct |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pending |
|
pending |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
more_work |
|
|
|
entry |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
work_done |
|
func |
|
func |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wq |
|
data |
|
data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
thread |
|
wq_data |
|
wq_data |
|
|
|
struct workqueue_struct *wq |
|
|
|
|
|
|
|
|
|
|
run_depth |
|
timer |
|
timer |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct list_head workqueues; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prev |
|
cpu_wq |
|
cpu_wq |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next |
|
name |
|
name |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NULL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
346 if (is_single_threaded(wq)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 p = kthread_create(worker_thread, cwq, "%s", wq->name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 else |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
进程描述符中的thread_info字段中有一个32位的preempt_counter字段,0-7位为抢占计数器,用于记录显式禁用内核抢占的次数;8-15位为软中断计数器,记录可延迟函数被禁用的次数;16-27为硬中断计数器,表示中断处理程序的嵌套数(irq_enter()递增它,irq_exit()递减它);28位为PREEMPT_ACTIVE标志。只要内核检测到preempt_counter整体不为0,就不会进行内核抢占,这个简单的探测一下子保证了对众多不能抢占的情况的检测。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IRQ handler type mismatch for IRQ 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] setup_irq+0x176/0x18a |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] irq_handle+0x0/0xc [per_cpu_3_1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] request_irq+0x7c/0x98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] hello_init+0x63f/0x64c [per_cpu_3_1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
[] sys_init_module+0x1aed/0x1caa |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] audit_syscall_entry+0x15a/0x18c |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[] syscall_call+0x7/0xb |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
======================= |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
调用setup_irq进行中断初始化时,需要手动的分配一个irqaction的结构体空间,并把irq_desc |
|
|
|
|
|
|
|
|
|
|
|
中的action指针指向这个结构体。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|