delayed_work实例

#include <linux/ktime.h>
#include <linux/timekeeping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/slab.h>

struct my_demo {
	struct workqueue_struct *demo_workqueue;
	struct delayed_work demo_delay_work;
	u32 delay_ms;
};

static struct my_demo *g_demo;
static int g_count;
static unsigned long long int now_ns, prev_ns;

static void delay_work_handle(struct work_struct *work)
{
	struct delayed_work *delay_work;
	struct my_demo *demo;

	now_ns = ktime_get();
	printk("%s, interval: %llus,%llums\n", __func__,
		(now_ns-prev_ns)/1000000000, ((now_ns-prev_ns)%1000000000)/1000000);
	delay_work = to_delayed_work(work);
	demo = container_of(delay_work, struct my_demo, demo_delay_work);

	queue_delayed_work(demo->demo_workqueue,
			   &(demo->demo_delay_work),
			   msecs_to_jiffies(demo->delay_ms));
}

static int __init my_demo_init(void)
{
	struct my_demo *demo;

	demo = (struct my_demo *)kzalloc(sizeof(*demo), GFP_KERNEL);
	if (!demo) {
		g_demo = NULL;
		return -ENOMEM;
	}

	g_demo = demo;
	demo->demo_workqueue = create_singlethread_workqueue("my_delay_work");
	INIT_DELAYED_WORK(&demo->demo_delay_work, delay_work_handle);

	g_count = 0;
	demo->delay_ms = 2000;

	now_ns = ktime_get();
	prev_ns = now_ns;

	queue_delayed_work(demo->demo_workqueue,
			   &(demo->demo_delay_work),
			   msecs_to_jiffies(0));
	return 0;
}

static void my_demo_exit(void)
{
	bool flag;
	// cancel a delayed work and wait for it to finish
	// cancel_work_sync(&delayed_work->work) must not be used for delayed_work's
	flag = cancel_delayed_work_sync(&(g_demo->demo_delay_work));
	if (flag) {
		printk("%s, demo_delay_work is pending\n", __func__);	
	} else {
		printk("%s, demo_delay_work is not pending\n", __func__);
	}

	// Safely terminate a workqueue
	// All work currently pending will be done first
	destroy_workqueue(g_demo->demo_workqueue);
	return;
}

module_init(my_demo_init);
module_exit(my_demo_exit);

MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("kiss1994");
MODULE_DESCRIPTION ("kernel queue delayed work");
[ 4566.098725] delay_work_handle, interval: 0s,0ms
[ 4568.112612] delay_work_handle, interval: 2s,13ms
[ 4570.128578] delay_work_handle, interval: 4s,29ms
[ 4572.144846] delay_work_handle, interval: 6s,46ms
[ 4574.160830] delay_work_handle, interval: 8s,62ms
[ 4576.176902] delay_work_handle, interval: 10s,78ms
[ 4577.583321] my_demo_exit, demo_delay_work is pending
// 附录:分配连续物理内存并清0
//       对申请的内存大小有限制,不能超过128KB
// static inline void *kzalloc(size_t size, gfp_t flags)
// {
//		return kmalloc(size, flags | __GFP_ZERO);
// }
// 附录:queue_delayed_work原型,注意实参
// Equivalent to queue_delayed_work_on() but tries to use the local CPU
// queue work on specific CPU after delay
// Return: %false if @work was already on a queue, %true otherwise.  
//         If @delay is zero and @dwork is idle, it will be scheduled for immediate execution.
// static inline bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay)
// 附录:cancel_delayed_work_sync原型,注意实参
// cancel a delayed work and wait for it to finish
// Return: 
//		%true if @dwork was pending, %false otherwise.
// bool cancel_delayed_work_sync(struct delayed_work *dwork)

对同一个 delayed_work 的多次添加

static int __init my_demo_init(void)
{
	struct my_demo *demo;
	bool flag;
	int i;

	demo = (struct my_demo *)kzalloc(sizeof(*demo), GFP_KERNEL);
	if (!demo) {
		g_demo = NULL;
		return -ENOMEM;
	}

	g_demo = demo;
	demo->demo_workqueue = create_singlethread_workqueue("my_delay_work");
	INIT_DELAYED_WORK(&demo->demo_delay_work, delay_work_handle);

	g_count = 0;
	demo->delay_ms = 2000;

	now_ns = ktime_get();
	prev_ns = now_ns;

	for (i = 0; i < 4; i++) {
		flag = queue_delayed_work(demo->demo_workqueue,
				   &(demo->demo_delay_work),
				   msecs_to_jiffies(1000)*5);
		if (flag) {
			printk("%s, delay_work add workqueue success\n", __func__);
		} else {
			printk("%s, delay_work already in workqueue\n", __func__);
		}
	}

	return 0;
}

可以看到,第一次添加成功,后续添加都失败

[ 5607.407611] my_demo_init, delay_work add workqueue success
[ 5607.407616] my_demo_init, delay_work already in workqueue
[ 5607.407618] my_demo_init, delay_work already in workqueue
[ 5607.407619] my_demo_init, delay_work already in workqueue
[ 5612.493791] delay_work_handle, interval: 5s,86ms
[ 5614.509734] delay_work_handle, interval: 7s,102ms
[ 5616.525820] delay_work_handle, interval: 9s,118ms
[ 5618.545845] delay_work_handle, interval: 11s,138ms

句柄的执行时长和queue_delayed_work中指定的时长不一致

// 两秒后 demo_delay_work 重新入队 demo_workqueue
// 但是当前的句柄执行时间超过2秒,为5秒
static void delay_work_handle(struct work_struct *work)
{
	struct delayed_work *delay_work;
	struct my_demo *demo;
	bool flag;

	now_ns = ktime_get();
	printk("%s, interval: %llus,%llums\n", __func__,
		(now_ns-prev_ns)/1000000000, ((now_ns-prev_ns)%1000000000)/1000000);
	delay_work = to_delayed_work(work);
	demo = container_of(delay_work, struct my_demo, demo_delay_work);

	flag = queue_delayed_work(demo->demo_workqueue,
			   &(demo->demo_delay_work),
			   msecs_to_jiffies(demo->delay_ms));
	if (flag) {
		printk("%s, delay_work add workqueue success\n", __func__);
	} else {
		printk("%s, delay_work already in workqueue\n", __func__);
	}

	mdelay(1000*2);
	printk("%s, cur handle is busy first\n", __func__);
	mdelay(1000*3);
	printk("%s, cur handle is busy second\n", __func__);
}

可以看到,前一个handler不执行完成的话,后一个根本跑不起来,即使 queue_delayed_work 中指定的时间很精确也没有用

[ 6279.363071] my_demo_init, delay_work add workqueue success
[ 6284.492710] delay_work_handle, interval: 5s,129ms
[ 6284.492718] delay_work_handle, delay_work add workqueue success
[ 6286.502742] delay_work_handle, cur handle is busy first
[ 6289.515950] delay_work_handle, cur handle is busy second
[ 6289.516088] delay_work_handle, interval: 10s,153ms
[ 6289.516092] delay_work_handle, delay_work add workqueue success
[ 6291.518687] delay_work_handle, cur handle is busy first
[ 6294.519962] delay_work_handle, cur handle is busy second
[ 6294.520081] delay_work_handle, interval: 15s,157ms
[ 6294.520493] delay_work_handle, delay_work add workqueue success
[ 6296.525910] delay_work_handle, cur handle is busy first
[ 6299.531933] delay_work_handle, cur handle is busy second
[ 6299.532002] delay_work_handle, interval: 20s,168ms
[ 6299.532004] delay_work_handle, delay_work add workqueue success
[ 6301.534915] delay_work_handle, cur handle is busy first
[ 6304.564089] delay_work_handle, cur handle is busy second
[ 6304.565057] delay_work_handle, interval: 25s,202ms
[ 6304.565060] delay_work_handle, delay_work add workqueue success
[ 6306.567208] delay_work_handle, cur handle is busy first
[ 6309.579111] delay_work_handle, cur handle is busy second
... ...

おすすめ

転載: blog.csdn.net/wangkai6666/article/details/121313997