static DECLARE_TASK_QUEUE(tq_serial); 此时就需要自行调用run_task_queue(&tq_serial)来启动其中的函数了,因此并不常用。 3.tasklet 这是比task queue和bottom half更加强大的一套软中断机制,使用上也相对简单,见下面代码段: 1: void foo_tasklet_action(unsigned long t);2: unsigned long stop_tasklet;3: DECLARE_TASKLET(foo_tasklet, foo_tasklet_action, 0);4: void foo_tasklet_action(unsigned long t)5: {6: //do something7:8: //reschedule9: if(!stop_tasklet)10: tasklet_schedule(&foo_tasklet);11: }12: void foo_init(void)13: {14: stop_tasklet=0;15: tasklet_schedule(&foo_tasklet);16: }17: void foo_clean(void)18: {19: stop_tasklet=1;20: tasklet_kill(&foo_tasklet);21: } 这个比较完整的代码段利用一个反复执行的tasklet来完成一定的工作,首先在第3行定义foo_tasklet,与相应的动作函数foo_tasklet_action相关联,并指定foo_tasklet_action()的参数为0。虽然此处以0为参数,但也同样可以指定有意义的其他参数值,但需要注意的是,这个参数值在定义的时候必须是有固定值的变量或常数(如上例),也就是说可以定义一个全局变量,将其地址作为参数传给foo_tasklet_action(),例如: int flags;DECLARE_TASKLET(foo_tasklet,foo_tasklet_action,&flags);void foo_tasklet_action(unsigned long t){ int flags=*(int *)t;...} 这样就可以通过改变flags的值将信息带入tasklet中。直接在DECLARE_TASKLET处填写flags,gcc会报"initializer element is not constant"错。 第9、10行是一种RESCHEDULE的技术。我们知道,一个tasklet执行结束后,它就从执行队列里删除了,要想重新让它转入运行,必须重新调用tasklet_schedule(),调用的时机可以是某个事件发生的时候,也可以是像这样在tasklet动作中。而这种reschedule技术将导致tasklet永远运行,因此在子系统退出时,应该有办法停止tasklet。stop_tasklet变量和tasklet_kill()就是干这个的。 | | |