Chinaunix首页 | 论坛 | 博客
  • 博客访问: 232901
  • 博文数量: 37
  • 博客积分: 933
  • 博客等级: 军士长
  • 技术积分: 511
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-16 10:15
文章分类
文章存档

2012年(1)

2011年(36)

分类: LINUX

2011-05-23 16:31:18

 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 };
tasklet_hi_vec
cpu1
tasklet_hi_vec
cpu0
tasklet_vec
t
cpu1 tasklet_struct tasklet_struct tasklet_struct
tasklet_vec
next
next
next
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;
静态的定义一个名字为nametruct 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
cpu_wq
lock
name remove_sequeuece
list insert_sequeue work_struct work_struct
worklist
pending pending
more_work
entry
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
list
list
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指针指向这个结构体。
阅读(2730) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~