linux内核中延迟的工作delayed_work

前言

        本次实验逻辑依然很简单,count数到5。如果发现代码不能执行,那是不可能的。如果真的不能执行,也让我学习学习。

        对于周期性的任务,除了定时器以外,在Linux内核中还可以利用一套封装得很好的快捷机制,其本质是利用工作队列和定时器实现,这套快捷机制就是delayed_work,delayed_work结构体的定义如下所示。

        它的成员里有工作队列和定时器。这就是定时器的封装应用啊。为了以后读内核代码的时候,看到这个东西不心虚,决定还是再最后做一个小实验,我坚信大部分人都可以自己使用定时器实现这么一个东西出来。

#include <linux/workqueue.h>
struct delayed_work {
	struct work_struct work;
	struct timer_list timer;

	/* target workqueue and CPU ->timer uses to queue ->work */
	struct workqueue_struct *wq;
	int cpu;
};

一 struct delayed_work 

        我们可以通过如下函数调度一个delayed_work在指定的延时后执行:

int schedule_delayed_work(struct delayed_work *work, unsigned long delay);

        当指定的delay到来时,delayed_work结构体中的work成员work_func_t类型成员func()会被执行。work_func_t类型定义为:

typedef void (*work_func_t)(struct work_struct *work);

其中,delay参数的单位是jiffies,因此一种常见的用法如下:

schedule_delayed_work(&work, msecs_to_jiffies(poll_interval));

msecs_to_jiffies()用于将毫秒转化为jiffies。如果要周期性地执行任务,通常会在delayed_work的工作函数中再次调用schedule_delayed_work(),周而复始。如下函数用来取消delayed_work:

int cancel_delayed_work(struct delayed_work *work);
int cancel_delayed_work_sync(struct delayed_work *work);

二 相关宏和函数介绍

INIT_DELAYED_WORK

这个宏里做了很多事情,所以不要自己给struct delayed_work变量赋值。

#define INIT_DELAYED_WORK(_work, _func)					\
	__INIT_DELAYED_WORK(_work, _func, 0)
#define __INIT_DELAYED_WORK(_work, _func, _tflags)			\
	do {								\
		INIT_WORK(&(_work)->work, (_func));			\
		__setup_timer(&(_work)->timer, delayed_work_timer_fn,	\
			      (unsigned long)(_work),			\
			      (_tflags) | TIMER_IRQSAFE);		\
	} while (0)

schedule_delayed_work

/**
 * schedule_delayed_work - put work task in global workqueue after delay
 * @dwork: job to be done
 * @delay: number of jiffies to wait or 0 for immediate execution
 *
 * After waiting for a given time this puts a job in the kernel-global
 * workqueue.
 */
static inline bool schedule_delayed_work(struct delayed_work *dwork,
					 unsigned long delay)
{
	return queue_delayed_work(system_wq, dwork, delay);
}

cancel_delayed_work

/**
 * cancel_delayed_work - cancel a delayed work
 * @dwork: delayed_work to cancel
 *
 * Kill off a pending delayed_work.
 *
 * Return: %true if @dwork was pending and canceled; %false if it wasn't
 * pending.
 *
 * Note:
 * The work callback function may still be running on return, unless
 * it returns %true and the work doesn't re-arm itself.  Explicitly flush or
 * use cancel_delayed_work_sync() to wait on it.
 *
 * This function is safe to call from any context including IRQ handler.
 */
bool cancel_delayed_work(struct delayed_work *dwork)
{
	unsigned long flags;
	int ret;

	do {
		ret = try_to_grab_pending(&dwork->work, true, &flags);
	} while (unlikely(ret == -EAGAIN));

	if (unlikely(ret < 0))
		return false;

	set_work_pool_and_clear_pending(&dwork->work,
					get_work_pool_id(&dwork->work));
	local_irq_restore(flags);
	return ret;
}
EXPORT_SYMBOL(cancel_delayed_work);

cancel_delayed_work_sync 

/**
 * cancel_delayed_work_sync - cancel a delayed work and wait for it to finish
 * @dwork: the delayed work cancel
 *
 * This is cancel_work_sync() for delayed works.
 *
 * Return:
 * %true if @dwork was pending, %false otherwise.
 */
bool cancel_delayed_work_sync(struct delayed_work *dwork)
{
	return __cancel_work_timer(&dwork->work, true);
}
EXPORT_SYMBOL(cancel_delayed_work_sync);

三 测试例程

源码:csi_timer.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/workqueue.h>

#define DEBUG_CT(format,...)\
	printk("%s:%s:%d: "format"\n",\
	__FILE__,__func__,__LINE__,\
	##__VA_ARGS__)
	
struct ct_dev_{
	int count;
	struct delayed_work my_delayed_work;
};
struct ct_dev_ *ct_dev;

static void ct_work_func_t(struct work_struct *pwork)
{
	struct delayed_work *pd = (struct delayed_work*)
		container_of(pwork,struct delayed_work,work);

	struct ct_dev_ *p = (struct ct_dev_*)
		container_of(pd,struct ct_dev_,my_delayed_work);
	DEBUG_CT("p->count = %d",p->count++);
	if(p->count < 5){
		schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000));
	}
}

static int __init ct_init(void)
{
	struct ct_dev_ *p = NULL;
	ct_dev = (struct ct_dev_ *)kmalloc(sizeof(struct ct_dev_),GFP_KERNEL);
	if(IS_ERR(ct_dev)){
		DEBUG_CT("kmalloc error");
		return -ENOMEM;
	}
	p = ct_dev;
	DEBUG_CT("");
	p->count = 0;
	DEBUG_CT("");
	INIT_DELAYED_WORK(&p->my_delayed_work, ct_work_func_t);
	schedule_delayed_work(&p->my_delayed_work, msecs_to_jiffies(1000));
	
	DEBUG_CT("init ok");
	return 0;
}
static void __exit ct_exit(void)
{
	struct ct_dev_ *p = ct_dev;
	if(IS_ERR(p)){
		return;
	}
	DEBUG_CT("p->count = %d",p->count++);
	cancel_delayed_work_sync(&p->my_delayed_work);
	kfree(p);
	DEBUG_CT("exit ok");
}
module_init(ct_init);
module_exit(ct_exit);
MODULE_LICENSE("GPL");


Makefile

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

KERNELDIR := /home/lkmao/imx/linux/linux-imx
CURRENT_PATH := $(shell pwd)
FILE_NAME=csi_timer
obj-m := $(FILE_NAME).o

build: kernel_modules

kernel_modules:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
        sudo cp $(FILE_NAME).ko /big/nfsroot/jiaocheng_rootfs/home/root/
clean:
        $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

测试结果:

root@hehe:~# insmod csi_timer.ko
[   22.024402] /big/csi_driver/csi_timer/csi_timer.c:ct_init:41:
[   22.030262] /big/csi_driver/csi_timer/csi_timer.c:ct_init:43:
[   22.036256] /big/csi_driver/csi_timer/csi_timer.c:ct_init:47: init ok
root@hehe:~# [   23.033240] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 0
[   24.033238] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 1
[   25.033249] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 2
[   26.033240] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 3
[   27.033235] /big/csi_driver/csi_timer/csi_timer.c:ct_work_func_t:26: p->count = 4

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千册

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值