等待队列

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/83447435

在Linux驱动程序中,阻塞进程可以使用等待队列(Wait Queue)来实现。由于等待队列很有用,在Linux 2.0的时代,就已经引入了等待队列机制。等待队列的基本数据结构是一个双向链表,这个链表存储睡眠的进程。等待队列也与进程调度机制紧密结合,能够用于实现内核中异步事件通知机制。等待队列可以用来同步对系统资源的访问。例如,当完成一项工作之后,才允许完成另一项工作。

在内核中,等待队列是有很多用处的,尤其是在中断处理、进程同步、定时等场合。可以使用等待队列实现阻塞进程的唤醒。它以队列为基础数据结构,与进程调度机制紧密结合,能够用于实现内核中的异步事件通知机制,同步对系统资源的访问等。

完成量就是以等待队列为基础

1 结构

等待队列头:

struct __wait_queue_head {
	spinlock_t lock;
	struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

lock:

用来对tasklist链表起保护作用。当要向task list链表中加入或者删除元素时,内核内部就会锁定lock锁,当修改完成后,会释放lock锁。也就是说, lock自旋锁在对task_list与操作的过程中,实现了对等待队列的互斥访问。

task_list:所有等待的队列都挂在这上面

等待队列:

typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key);

struct __wait_queue {
	unsigned int flags;
#define WQ_FLAG_EXCLUSIVE	0x01
	void *private;
	wait_queue_func_t func;
	struct list_head task_list;
};

定义和初始化等待队列头

#define DECLARE_WAIT_QUEUE_HEAD(name) \  //定义
	wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)


#define init_waitqueue_head(q)				\  //初始化
	do {						\
		static struct lock_class_key __key;	\
							\
		__init_waitqueue_head((q), &__key);	\
	} while (0)

定义等待队列:

#define DECLARE_WAITQUEUE(name, tsk)					\
	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)

添加和移除等待队列:

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

等待事件:

#define wait_event(wq, condition) 	
#define wait_event_timeout(wq, condition, timeout)	
#define wait_event_interruptible(wq, condition)		
#define wait_event_interruptible_timeout(wq, condition, timeout)

wait event宏的功能是,在等待队列中睡眠直到condition为真。在等待的期间,进程会被置为TASK UNINTERRUPTIBLE进入睡眠,直到condition变量变为真。每次进程被唤醒的时候都会检查condition的值。

wait event timeont宏与wait event宏类似,不过如果所给的睡眠时间为负数则立即返回。如果在睡眠期间被唤醒,且condition为真则返回剩余的睡眠时间,否则继续睡眠直到到达或超过给定的睡眠时间,然后返回0。

wait event interruptible宏与wait event宏的区别是,调用该宏在等待的过程中当前进程会被设置为TASK INTERRUPTIBLE状态。在每次被唤醒的时候,首先检查condition是否为真,如果为真则返回;否则检查如果进程是被信号唤醒,会返回-ERESTARTSYS错误码。如果是condition为真,则返回0.

wait event interruptible timeout宏与wait event timeout宏类似,不过如果在睡眠期间被信号打断则返回ERESTARTSYS错误码。

唤醒等待队列:

#define wake_up(x)			__wake_up(x, TASK_NORMAL, 1, NULL)
#define wake_up_nr(x, nr)		__wake_up(x, TASK_NORMAL, nr, NULL)
#define wake_up_all(x)			__wake_up(x, TASK_NORMAL, 0, NULL)
#define wake_up_locked(x)		__wake_up_locked((x), TASK_NORMAL)

wake_up宏唤醒等待队列,可唤醒处于TASK_INTERRUPTIBLE和TASK UNINTERUPTIBLE状态的进程,这个宏和wait event/wait event timeout成对使用。

wake up interruptible宏和wake up0)唯一的区别是,它只能唤醒TASK INTERRUPTIBLE状态的进程。这个宏可以唤醒使用wait event interruptible.wait event interruptible timeout宏睡眠的进程。

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/83447435