免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 916 | 回复: 0
打印 上一主题 下一主题

Chap7 下半部和退后执行的工作 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-08 14:33 |只看该作者 |倒序浏览

7.1 下半部
     任务:执行与中断处理密切相关而中断处理程序本身不执行的工作。
     => 减少中断处理程序的运行时间;
           下半部通常在中断处理程序返回时就会执行,且允许所有中断。
    三种下半部实现机制:
                       软中断、tasklet、工作队列
7.2 软中断
7.2.1 软中断的实现

/*
* structure representing a single softirq entry 软中断结构
*/
struct softirq_action {
        void (*action)(struct softirq_action *); /* function to run */
        void *data; /* data to pass to function */
};
static struct softirq_action softirq_vec[32];最多有32个软中断
软中断处理程序:void softirq_handler(struct softirq_action *)
执行软中断(do_softirq()):
       软中断不会抢占另一个软中断,一个注册的软中断在标记后才会执行(触发软中断);
       其他软中断,甚至是相同类型软中断,可以在其他处理器上同时执行;
       中断处理程序返回前 => 标记它的软中断
   => 软中断被检查和执行(条件:从一个硬件中断代码返回;
                                                                      在ksoftirqd内核线程中;
                                                                      在显式检查和执行待处理的软中断的代码中)

u32 pending = softirq_pending(cpu);//softirq_pending()返回的是待处理软中断的32位位图
if (pending) {
    struct softirq_action *h = softirq_vec;
    softirq_pending(cpu) = 0;
    do {
        if (pending & 1)
            h->action(h);
        h++;
        pending >>= 1;
    } while (pending); //这个循环最多执行32次
}
7.2.2 使用软中断
       (1) 分配索引
Tasklet
Priority
Softirq Description
HI_SOFTIRQ
0
High-priority tasklets       优先级高的tasklet
TIMER_SOFTIRQ
1
Timer bottom half                  定时器的下半部
NET_TX_SOFTIRQ
2
Send network packets           发送网络数据包
NET_RX_SOFTIRQ
3
Receive network packets     接收网络数据包
SCSI_SOFTIRQ
4
SCSI bottom half                     SCSI的下半部
TASKLET_SOFTIRQ
5
Tasklets                                      
说明:      
         定义在中
         建立一个新的软中断必须在此枚举类型中加入新项;
         HI_SOFTIRQ为第一项,TASKLET_SOFTIRQ为最后一项,新项可插在网络项之后,TASKLET_SOFTIRQ之前;
       (2) 注册软中断处理程序
         open_softirq()
         参数:软中断索引号、处理函数、data域存放的数值
       (3) 触发软中断
          raise_softirq()或raise_softirq_irqoff()
          参数:软中断索引号
总结:
          中断处理程序执行硬件相关的操作,然后触发相应的软中断,并退出;
          内核执行完中断处理程序,调用do_softirq()函数,软中断执行中断处理程序的剩余任务(下半部);
          软中断很少使用,用于执行频率和连续性都很高的情况;
          通常用tasklet。

7.3 tasklet
tasklet结构体:

struct tasklet_struct {
        struct tasklet_struct *next; /* next tasklet in the list */
        unsigned long state; /* state of the tasklet :
                                           0;TASKLET_STATE_SCHED(tasklet已被调度,准备运行);TASKLET_STATE_RUN(正在运行)*/
        atomic_t count; /* reference counter为0时tasklet才被激活 */
        void (*func)(unsigned long); /* tasklet handler function */
        unsigned long data; /* argument to the tasklet function */
};
调度tasklet:tasklet_schedule()和tasklet_hi_schedule()(接收一个指向tasklet_struct结构的指针作为参数)
已调度的tasklet存放在tasklet_vec和tasklet_hi_vec中,它们是由tasklet_struct构成的链表。
运用HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断。
使用tasklet:(1) 声明tasklet——静态:DECLARE_TASKLET(name, func, data)或DECLARE_TASKLET_DISABLED(name, func, data);
                                    动态:tasklet_init(t, tasklet_handler, dev)
(2) 编写tasklet处理程序——void tasklet_handler(unsigned long data)
(3) 调度tasklet——tasklet_schedule(&my_tasklet)
ksoftirqd:用于辅助处理软中断的内核线程;只要有待处理的软中断,ksoftirqd就会调用do_softirq去处理它们

7.4 工作队列
推后执行的任务可以睡眠;
工作队列允许重新调度;
可以中内核线程替换。
工作队列的实现:
内核线程-工作者线程(worker thread)
默认的工作者线程叫events/n,n是处理器的编号;
1 表示线程的数据结构-workqueue_struct

    struct workqueue_struct {
        struct cpu_workqueue_struct cpu_wq[NR_CPUS];
        const char *name;
        struct list_head list;
};
    struct cpu_workqueue_struct {
        spinlock_t lock; /* lock protecting this structure */
        long remove_sequence; /* least-recently added (next to run) */
        long insert_sequence; /* next to add */
        struct list_head worklist; /* list of work */
        wait_queue_head_t more_work;
        wait_queue_head_t work_done;
        struct workqueue_struct *wq; /* associated workqueue_struct */
        task_t *thread; /* associated thread */
        int run_depth; /* run_workqueue() recursion depth */
};
     2 表示工作的数据结构-work_struct

    struct work_struct {
        unsigned long pending; /* is this work pending? */
        struct list_head entry; /* link list of all work */
        void (*func)(void *); /* handler function */
        void *data; /* argument to handler */
        void *wq_data; /* used internally */
        struct timer_list timer; /* timer used by delayed work queues */
};
这些结构体连接成链表;
工作者线程用普通的内核线程实现的,执行worker_thread()函数;
     3 run_workqueue()

使用工作队列:
(1) 创建推后的工作
静态:DECLARE_WORK(name, void (*func)(void *), void *data);
动态:INIT_WORK(struct work_struct *work, void(* func)(void *), void *data);
(2) 工作队列处理函数
void work_handler(void *data)
(3) 对工作进行调度
schedule_work(&work);
schedule_delayed_work(&work, delay);
(4) 刷新操作
void flush_scheduled_work(void);
(5) 创建新的工作队列
默认的队列不能满足需要的情况下
srruct workqueue_struct *create_workqueue(const char *name)
                        调度自己创建的工作队列:

int queue_work(struct workqueue_struct *wq, struct work_struct *work)
int queue_delayed_work(struct workqueue_struct *wq,
                       struct work_struct *work,
                       unsigned long delay)

7.5 下半部机制的选择
Bottom Half
Context
Inherent Serialization
Softirq
Interrupt
None
Tasklet
Interrupt
Against the same tasklet
Work queues
Process
None (scheduled as process context)


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/85048/showart_1893908.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP