|
|
|
|
|
|
|
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指针指向这个结构体。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|