码迷,mamicode.com
首页 > 其他好文 > 详细

内核工作队列workqueue

时间:2015-09-07 22:56:25      阅读:561      评论:0      收藏:0      [点我收藏+]

标签:

LDD3: 工作队列是, 表面上看, 类似于 taskets; 它们允许内核代码来请求在将来某个时间调用一个函数. 但是, 有几个显著的不同在这 2 个之间, 包括:

(1) tasklet 在软件中断上下文中运行的结果是所有的 tasklet 代码必须是原子的. 相反, 工作队列函数在一个特殊内核进程上下文运行; 结果, 它们有更多的灵活性. 特别地, 工作队列函数能够睡眠.

(2) tasklet 常常在它们最初被提交的处理器上运行. 工作队列以相同地方式工作, 缺省地.

(3) 内核代码可以请求工作队列函数被延后一个明确的时间间隔.

两者之间关键的不同是 tasklet 执行的很快, 短时期, 并且在原子态, 而工作队列函数可能有高周期但是不需要是原子的. 每个机制有它适合的情形.

使用

       工作队列有一个 struct workqueue_struct 类型, 在 <linux/workqueue.h> 中定义.

创建:
struct workqueue_struct *create_workqueue(const char *name);
struct workqueue_struct *create_singlethread_workqueue(const char *name);

如果你使用create_workqueue, 你得到一个工作队列它有一个专用的线程在系统的每个处理器上. 在很多情况下, 所有这些线程是简单的过度行为; 如果一个单个工作者线程就足够, 使用 create_singlethread_workqueue。

 

声明:

DECLARE_WORK(name, void (*function)(void *), void *data);

 

运行时初始化:

static struct workqueue_struct * workqueue;

 

INIT_WORK(struct work_struct *work, void (*function)(void *), void *data); 
PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data); 


还有一个INIT_DELAYED_WORK:

#define INIT_DELAYED_WORK(_work, _func)                      \

       do{                                           \

              INIT_WORK(&(_work)->work,(_func));         \

              init_timer(&(_work)->timer);                     \

       }while (0)

 

加入队列:

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

如果使用queue_delay_work, 但是, 实际的工作没有进行直到至少delay jiffies 已过去. 从这些函数的返回值是 0 如果工作被成功加入到队列; 一个非零结果意味着这个 work_struct 结构已经在队列中等待, 并且第 2 次没有加入.

 

如果你需要取消一个挂起的工作队列入口, 你可以调用:

int cancel_delayed_work(struct work_struct*work);

返回值是非零如果这个入口在它开始执行前被取消. 内核保证给定入口的执行不会在调用 cancel_delay_work 后被初始化. 如果cancel_delay_work 返回 0, 但是, 这个入口可能已经运行在一个不同的处理器, 并且可能仍然在调用 cancel_delayed_work 后在运行. 要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行, 你必须跟随这个调用来调用:

void flush_workqueue(structworkqueue_struct *queue);

在flush_workqueue 返回后, 没有在这个调用前提交的函数在系统中任何地方运行.

当你用完一个工作队列, 你可以去掉它, 使用:

void destroy_workqueue(structworkqueue_struct *queue);

 

示例:

//全局定义
static struct workqueue_struct *rohm_workqueue;

初始化函数中:
    rohm_workqueue = create_singlethread_workqueue("rohm_workqueue");  //这时队列还没有工作
    if (!rohm_workqueue) {
        return (-ENOMEM);
}

销毁函数中:
destroy_workqueue(rohm_workqueue);


开始:
INIT_WORK(&ps_als->work, ps_als_work_func);  //初始化还没有工作
设定一个定时器:
/* timer process */
        hrtimer_init(&ps_als->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        ps_als->timer.function = ps_als_timer_func;
注意这里并没有启动定时器,这条语句下面有一条代码:
INIT_DELAYED_WORK(&ps_als->input_work, ps_als_work_func); ps_als_work_func会启动定时器。



定时器处理函数:
static enum hrtimer_restart ps_als_timer_func(struct hrtimer *timer)
{
    PS_ALS_DATA *ps_als;
    int         result;

    ps_als = container_of(timer, PS_ALS_DATA, timer);
    result = queue_work(rohm_workqueue, &ps_als->work);
    if (result == 0) {
        printk(KERN_ERR "can‘t register que.\n");
        printk(KERN_ERR "result = 0x%x\n", result);
    }

    return (HRTIMER_NORESTART);
}

static void ps_als_work_func(struct work_struct *work)
{

/* the setting value from application */
        get_timer = ps_als->delay_time;
        /* 125ms(8Hz) at least */
        wait_sec  = (get_timer / SM_TIME_UNIT);
        wait_nsec = ((get_timer - (wait_sec * SM_TIME_UNIT)) * MN_TIME_UNIT);
        result    = hrtimer_start(&ps_als->timer, ktime_set(wait_sec, wait_nsec), HRTIMER_MODE_REL);
        if (result != 0) {
            printk(KERN_ERR "can‘t start timer\n");
            return;
        }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

内核工作队列workqueue

标签:

原文地址:http://blog.csdn.net/xgbing/article/details/48274589

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!