Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22434
  • 博文数量: 18
  • 博客积分: 810
  • 博客等级: 准尉
  • 技术积分: 205
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-10 21:09
文章分类
文章存档

2009年(15)

2008年(3)

我的朋友

分类: LINUX

2009-04-08 14:33:15

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 */
};

调度tasklettasklet_schedule()tasklet_hi_schedule()(接收一个指向tasklet_struct结构的指针作为参数)

已调度的tasklet存放在tasklet_vectasklet_hi_vec中,它们是由tasklet_struct构成的链表。

运用HI_SOFTIRQTASKLET_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)

阅读(362) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~