函数INIT_DELAYED_WORK()/schedule_delayed_work() / cancel_delayed_work_sync()

Delay work 相关的函数

1. 初始化delay work -- INIT_DELAYED_WORK()

2. 调度delay work -- schedule_delayed_work()

3. 取消delay work -- cancel_delayed_work_sync()


1. 函数INIT_DELAYED_WORK()-- 初始化delay work并设置timer

delay work终究是使用timer来调度的。

#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)

#define INIT_WORK(_work, _func)						\
	do {								\
		__INIT_WORK((_work), (_func), 0);			\
	} while (0)


/*
 * initialize all of a work item in one go
 *
 * NOTE! No point in using "atomic_long_set()": using a direct
 * assignment of the work data initializer allows the compiler
 * to generate better code.
 */
#ifdef CONFIG_LOCKDEP
#define __INIT_WORK(_work, _func, _onstack)				\
	do {								\
		static struct lock_class_key __key;			\
									\
		__init_work((_work), _onstack);				\
		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
		lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0); \
		INIT_LIST_HEAD(&(_work)->entry);			\
		PREPARE_WORK((_work), (_func));				\
	} while (0)
#else
#define __INIT_WORK(_work, _func, _onstack)				\
	do {								\
		__init_work((_work), _onstack);				\
		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
		INIT_LIST_HEAD(&(_work)->entry);			\
		PREPARE_WORK((_work), (_func));				\
	} while (0)
#endif

#define __setup_timer(_timer, _fn, _data, _flags)			\
	do {								\
		__init_timer((_timer), (_flags));			\
		(_timer)->function = (_fn);				\
		(_timer)->data = (_data);				\
	} while (0)


2. 函数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);
}


/**
 * queue_delayed_work - queue work on a workqueue after delay
 * @wq: workqueue to use
 * @dwork: delayable work to queue
 * @delay: number of jiffies to wait before queueing
 *
 * Equivalent to queue_delayed_work_on() but tries to use the local CPU.
 */
static inline bool queue_delayed_work(struct workqueue_struct *wq,
				      struct delayed_work *dwork,
				      unsigned long delay)
{
	return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
}


/**
 * queue_delayed_work_on - queue work on specific CPU after delay
 * @cpu: CPU number to execute work on
 * @wq: workqueue to use
 * @dwork: work to queue
 * @delay: number of jiffies to wait before queueing
 *
 * Returns %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.
 */
bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
			   struct delayed_work *dwork, unsigned long delay)
{
	struct work_struct *work = &dwork->work;
	bool ret = false;
	unsigned long flags;

	/* read the comment in __queue_work() */
	local_irq_save(flags);

	if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
		__queue_delayed_work(cpu, wq, dwork, delay);
		ret = true;
	}

	local_irq_restore(flags);
	return ret;
}


3. 函数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.
 *
 * RETURNS:
 * %true if @dwork was pending, %false otherwise.
 */
bool cancel_delayed_work_sync(struct delayed_work *dwork)
{
	return __cancel_work_timer(&dwork->work, true);
}

static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
{
	static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq);
	unsigned long flags;
	int ret;

	do {
		ret = try_to_grab_pending(work, is_dwork, &flags);
		/*
		 * If someone else is already canceling, wait for it to
		 * finish.  flush_work() doesn't work for PREEMPT_NONE
		 * because we may get scheduled between @work's completion
		 * and the other canceling task resuming and clearing
		 * CANCELING - flush_work() will return false immediately
		 * as @work is no longer busy, try_to_grab_pending() will
		 * return -ENOENT as @work is still being canceled and the
		 * other canceling task won't be able to clear CANCELING as
		 * we're hogging the CPU.
		 *
		 * Let's wait for completion using a waitqueue.  As this
		 * may lead to the thundering herd problem, use a custom
		 * wake function which matches @work along with exclusive
		 * wait and wakeup.
		 */
		if (unlikely(ret == -ENOENT)) {
			struct cwt_wait cwait;

			init_wait(&cwait.wait);
			cwait.wait.func = cwt_wakefn;
			cwait.work = work;

			prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait,
						  TASK_UNINTERRUPTIBLE);
			if (work_is_canceling(work))
				schedule();
			finish_wait(&cancel_waitq, &cwait.wait);
		}
	} while (unlikely(ret < 0));

	/* tell other tasks trying to grab @work to back off */
	mark_work_canceling(work);
	local_irq_restore(flags);

	flush_work(work);
	clear_work_data(work);

	/*
	 * Paired with prepare_to_wait() above so that either
	 * waitqueue_active() is visible here or !work_is_canceling() is
	 * visible there.
	 */
	smp_mb();
	if (waitqueue_active(&cancel_waitq))
		__wake_up(&cancel_waitq, TASK_NORMAL, 1, work);

	return ret;
}


使用的相关结构体

从delayed_work中,可以看到使用了timer相关的结构体。

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 work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};

struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;
	unsigned long expires;
	struct tvec_base *base;

	void (*function)(unsigned long);
	unsigned long data;

	int slack;

#ifdef CONFIG_TIMER_STATS
	int start_pid;
	void *start_site;
	char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};

/*
 * The externally visible workqueue.  It relays the issued work items to
 * the appropriate worker_pool through its pool_workqueues.
 */
struct workqueue_struct {
	struct list_head	pwqs;		/* WR: all pwqs of this wq */
	struct list_head	list;		/* PL: list of all workqueues */

	struct mutex		mutex;		/* protects this wq */
	int			work_color;	/* WQ: current work color */
	int			flush_color;	/* WQ: current flush color */
	atomic_t		nr_pwqs_to_flush; /* flush in progress */
	struct wq_flusher	*first_flusher;	/* WQ: first flusher */
	struct list_head	flusher_queue;	/* WQ: flush waiters */
	struct list_head	flusher_overflow; /* WQ: flush overflow list */

	struct list_head	maydays;	/* MD: pwqs requesting rescue */
	struct worker		*rescuer;	/* I: rescue worker */

	int			nr_drainers;	/* WQ: drain in progress */
	int			saved_max_active; /* WQ: saved pwq max_active */

	struct workqueue_attrs	*unbound_attrs;	/* WQ: only for unbound wqs */
	struct pool_workqueue	*dfl_pwq;	/* WQ: only for unbound wqs */

#ifdef CONFIG_SYSFS
	struct wq_device	*wq_dev;	/* I: for sysfs interface */
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map	lockdep_map;
#endif
	char			name[WQ_NAME_LEN]; /* I: workqueue name */

	/* hot fields used during command issue, aligned to cacheline */
	unsigned int		flags ____cacheline_aligned; /* WQ: WQ_* flags */
	struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
	struct pool_workqueue __rcu *numa_pwq_tbl[]; /* FR: unbound pwqs indexed by node */
};






<think>好的,我现在需要回答用户关于Linux内核中INIT_DELAYED_WORK的用法和工作原理的问题。首先,我得回忆一下之前学过的相关知识,并查看用户提供的引用内容。用户提到了引用[1]和引用[2],里面详细介绍了INIT_DELAYED_WORK和相关的函数,比如schedule_delayed_workcancel_delayed_work等。这些资料应该能帮助我构建答案。 首先,INIT_DELAYED_WORK是用于初始化延迟工作的宏,属于工作队列机制的一部分。工作队列在Linux内核中用于延迟执行任务,尤其是在中断处理或需要进程上下文的情况下。延迟工作(delayed_work)结构体包含一个普通的工作结构(work_struct)和一个定时器(timer_list),这样可以在指定的延迟时间后将工作添加到工作队列中执行。 接下来,我需要解释INIT_DELAYED_WORK的使用方法。根据引用[1]和[2],初始化需要调用这个宏,传入delayed_work结构体指针和对应的处理函数。例如,INIT_DELAYED_WORK(&my_work, my_func); 这样就将处理函数my_func绑定到my_work上。 然后是调度延迟工作,使用schedule_delayed_work函数,参数包括工作结构体和延迟时间(以jiffies为单位)。例如,schedule_delayed_work(&my_work, HZ); 表示延迟1秒后执行。这里需要注意的是,延迟时间是通过jiffies计算的,HZ代表每秒的jiffies数,因此HZ就是1秒。 工作原理方面,delayed_work通过定时器实现延迟。当调用schedule_delayed_work时,会设置定时器,在指定的延迟时间后触发,将工作项添加到工作队列中。工作队列线程随后会执行处理函数。这部分需要结合引用中的结构体定义来解释,delayed_work包含work_struct和timer_list,定时器到期时调用处理函数,将工作加入队列。 另外,可能需要提到取消和刷新工作项的函数,如cancel_delayed_work和flush_scheduled_work,确保任务可以被安全地取消或等待完成。引用[2]中提到了这些函数的作用,所以在回答中也应该涵盖这些内容,以全面解答用户的问题。 用户可能对具体的代码示例感兴趣,所以提供一个简单的示例会更好。例如,定义一个delayed_work结构体,初始化它,然后调度执行。同时,处理函数的结构和注意事项也需要说明,比如不能执行睡眠操作,因为工作队列运行在进程上下文。 最后,需要检查是否符合用户的要求,比如使用中文回答、LaTeX格式的正确应用、生成相关问题等。确保没有使用任何Markdown格式,行内公式用$包围,独立公式用$$。同时,生成的三个问题要相关且有深度,帮助用户进一步学习。 总结一下,回答的结构应该是: 1. 概述INIT_DELAYED_WORK的作用 2. 详细的使用方法,包括初始化和调度 3. 工作原理,结合结构体和定时器机制 4. 示例代码和注意事项 5. 相关问题 现在需要将这些点组织成连贯的段落,并引用提供的资料作为支持,比如在解释结构体时引用[2]中的定义,在说明函数时引用[1]和[2]中的函数列表。同时,确保在引用处添加[^1]或[^2]的标识。</think>### Linux内核中INIT_DELAYED_WORK的用法及解析 #### 1. **基本概念与作用** `INIT_DELAYED_WORK`是Linux内核中用于初始化延迟工作(`delayed_work`)的宏,属于工作队列(workqueue)机制的一部分。工作队列用于将任务延迟到进程上下文中异步执行,常用于中断处理、定时任务等场景[^1]。延迟工作通过结合定时器(`timer_list`)和工作项(`work_struct`),实现指定时间后触发任务的功能。 #### 2. **使用方法** **(1) 初始化延迟工作** 通过`INIT_DELAYED_WORK`宏绑定工作结构体与处理函数: ```c struct delayed_work my_work; INIT_DELAYED_WORK(&my_work, my_work_func); // 初始化 ``` 此处`my_work_func`是任务处理函数,需满足以下原型: ```c void my_work_func(struct work_struct *work); ``` **(2) 调度延迟任务** 使用`schedule_delayed_work`提交任务到全局工作队列,并指定延迟时间(单位为jiffies): ```c schedule_delayed_work(&my_work, HZ); // 延迟1秒后执行[^1] ``` **(3) 取消或等待任务** - **取消未执行的任务**:`cancel_delayed_work(&my_work)` - **强制等待任务完成**:`flush_scheduled_work()` #### 3. **工作原理** - **结构体定义**:`delayed_work`包含两个成员: ```c struct delayed_work { struct work_struct work; // 基础工作项 struct timer_list timer; // 定时器 }; // [^2] ``` - **定时器触发机制**: 调用`schedule_delayed_work`后,内核会设置定时器。当定时器到期时,触发回调函数将`work`加入全局工作队列。工作队列线程(如`kworker`)随后调用`my_work_func`执行任务[^1]。 #### 4. **代码示例** ```c #include <linux/workqueue.h> static void my_work_func(struct work_struct *work) { printk("Delayed work executed!\n"); } struct delayed_work my_work; void init_module(void) { INIT_DELAYED_WORK(&my_work, my_work_func); schedule_delayed_work(&my_work, 2*HZ); // 延迟2秒 } void cleanup_module(void) { cancel_delayed_work(&my_work); flush_scheduled_work(); } ``` #### 5. **注意事项** - **上下文约束**:工作队列运行在进程上下文,允许休眠,但处理函数应避免长时间阻塞。 - **定时器精度**:延迟时间基于jiffies,实际执行可能有毫秒级误差。 - **并发控制**:若任务可能被多次调度,需使用原子操作或锁保护共享数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值