linux 内核队列,linux内核中的等待队列的基本操作

在linux内核中进程的状态主要有几种状态:

1.运行态:即进程正在CPU上进行运行,它此刻正在占有CPU;

2.就绪态:即进程除了CPU之外,已经具备了运行的所有条件,在就绪队列中等待调度器(schedule)的调度;

3.阻塞态:即进程除了缺少CPU外,还缺少其他条件,在等待队列中等待所需要的条件;

介绍linux内核中的等待队列的组织结构以及各种对等待队列的操作:

等待队列由两部分构成:等待队列头 + 等待队列中的等待项;

等待队列头的结构:

struct __wait_queue_head

{

spinlock_t lock;  // 自选锁,用于保护等待队列,防止并发访问

struct list_head task_list;//用于构建等待队列

}

typedef struct __wait_queue_head wait_queue_head_t;

等待队列中的等待项:

struct __wait_queue

{

unsigned int flags;

void *private;

wait_queue_func_t func;

struct list_head task_list;

}

每个字段的介绍:

flags : 用于判断当等待条件满足时,是唤醒等待队列中的等待该条件的所有

等待进程,还是只唤醒一个;

flags 的最后一位为 1  时表示每次只唤醒一个等待队列中的进程;

flags 的最后一位为 0 时表示每次唤醒等待该条件的所有进程;

#define WQ_FLAG_EXCLUSIVE 0x01

private: 用于存放 struct task_struct 的地址;

wait_queue_func_t :等待队列中的进程被唤醒的方式;

typedef int (*wait_queue_func_t)(wait_queue_t *wait,unsigned mode,

int flags, void *key)

等待的队列的结构图:

9a0aaba04a7990c4e8778cb3e0428457.png

对等待队列的各种操作:

1.等待队列头的静态初始化:

#define __WAIT_QUEUE_INITIALIZER(name) {         \

.lock = __SPIN_LOCK_UNLOCK(name.lock),// lock = 1;  \

.task_list = {&(name).task_list, &(name).task_list} }

#define DECLARE WAIT_QUEUE_HEAD(name) \

wait_queue_head_t name = __WAIT_QUEUE_INITIALIZER(name)

所以可以直接通过 : DECLARE_WAIT_QUEUE_HEAD(name) 来完成一个等待队列头的定义以及初始化操作;

2. 等待队列头的动态初始化操作:

void __init_waitqueue_head(wait_queue_head_t *p, struct lock_class_key *key)

{

spin_lock_init(&p->lock); // 初始化spinlock_t lock lock = 1;

INIT_LIST_HEAD(&p->task_list);// 初始化链表头;

}

#define init_waitqueue_head(name) \

do {    \

static struct lock_class_key  __key; \

__init_wait_queue_head((name), &__key);\

} while(0)

所以如果使用 init_waitqueue_head()的用法为:

wait_queue_head_t name;

init_waitqueue_head(&name);

DECLARE_WAIT_QUEUE_HEAD() 与 init_waitqueue_head()的区别:

1.DECLARE_WAIT_QUEUE_HEAD完全时用宏定义实现的,因此程序在编译的时候就完成了变量的定义与初始化。而 init_waitqueue_head()本质上来说是对 __init_waitqueue_head()的一次封装。虽然使用了宏定义,其仍然是一个函数,它对变量的初始化是在程序运行的时候进行的;

3.对等待队列中的等待项进行静态定义与初始化:

#define __WAITQUEUE_INITIALIZER(name, task) {  \

.private   = task, \

.func      = default_wake_function,  \

.task_list = {NULL,NULL} }

#define DECLARE_WAITQUEUE(name,task)     \

wait_queue_t name = __WAITQUQUE_INITIALIZER(name, task)

相当与:

wait_queue_t entry;

struct task_struct task;

entry = {

.private = &task,

.func    = default_wake_function,

.taks_list = {NULL, NULL}

}

4.动态初始化等待队列中的数据项:

static inline void init_waitqueue_entry(wait_queue_t *p, struct task_struct    *task)

{

p->flags   = 0;

p->private = task;

p->func    = default_wake_function;

}

用法:wait_queue_t wait;

struct task_struct task;

init_waitqueue_entry(&wait, &task);

5.使用自定义的函数作为等待队列中的进程唤醒做处理:

static inline void init_waitqueue_func_entry(wait_queue_t *wait,

wait_queue_func_t func)

{

p->flags = 0;

p->private = NULL;

p->func    = func;

}

6.判断一个等待队列是否可用:

static inline int waitqueue_active(wait_queue_head_t *p)

{

return !list_empty(&p->task_list);

}

waitqueue_active()本质上实在判断一个等待队列是否为空。

如果为空的话,等待队列不可用返回 0;

如果不为空,等待队列可用返回 1;

7.向等待队列中添加一个数据项:

static inline void __add_wait_queue(wait_queue_head_t *head,

wait_queue_t *new)

{

list_add(&new->task_list, &head->task_list);

}

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

{

unsigned int flags ;

wait->flags &= ~WQ_FLAG_EXCLUSIVE; // define WQ_FLAG_EXCLUSIVE 0x01

spin_lock_irqsave(&q->lock, flags);

__add_wait_queue(q, wait);

spin_unlock_irqstore(&q->lock, flags);

}

所以 add_wait_queue()是__add_wait_queue()的封装,并且加入了一些保护等待队列防止并发访问的措施, 所以在向等待队列中添加元素时使用 add_wait_queue()会更安全;

8.向等待队列中添加一个每次只能唤醒一个数据项:

static inline void __add_wait_queue_tail(wait_queue_head_t *head,

wait_queue_t *new)

{

list_add_tail(&new->task_list, &head->task_list);

}

void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)

{

unsigned int flags ;

wait->flags |=  WQ_FLAG_EXCLUSIVE;

spin_lock_irqsave(&q->lock, flags);

__add_wait_queue_tail(q,wait);

spin_unlock_irqstore(&q->lock, flags);

}

可以看出 add_wait_queue(wait_queue_head_t *head, wait_queue_t *wait)

每次向等待队列的头后面添加一个非互斥唤醒的等待项;

add_wait_queue_exclusive(wait_queue_head_t *head, wait_queue_t *wait)

每次向等待队列的尾部添加一个互斥唤醒的等待项;

9.将一个等待项从等待队列中删除:

static inline void __remove_wait_queue(wait_queue_head_t *head,

wait_queue_t *wait)

{

list_del(&wait->task_list);

}

void remove_wait_queue(wait_queue_head_t *head, wait_queue_t *wait)

{

unsigned int flags;

spin_lock_irqsave(&head->lock, flags);

__remove_wait_queue(head,wait);

spin_unlock_irqstore(&head->lock, flags);

}

小总结: add_wait_queue();   EXPORT_SYMBOL(add_wait_queue);

add_wait_queue_exclusive();  EXPORT_SYMBOL(add_wait_queue_exclusive);

remove_wait_queue(); EXPORT_SYMBOL(remove_wait_queue);

这三个对等待队列的操作是内核提过的函数,

内核中的等待队列中的进程是需要在一定条件下给唤醒的,然后加入到就绪队列中的。以及正在运行的进程如何将其加入到等待队列之中的。

内核也提供了一些函数,帮助我们将进程正在运行的进程阻塞,让后将其加入到等待队列中。以及在等待队列中唤醒唤醒阻塞进程。

阻塞正在运行的进程,然后将其加入到等待队列中的函数:

1. void prepare_to_wait(wait_queue_head_t *head, wait_queue_t *wait, int state)

state :表示进程的状态

取值 TASK_RUNNING, TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE

void prepare_to_wait(wait_queue_head_t *head, wait_queue_t *wait, int state)

{

unsigned int flags;

wait->flags &= ~WQ_FLAG_EXCLUSIVE; // 非互斥唤醒进程;

spin_lock_irqsave(&head->lock, flags);

if( list_empty(&wait->task_list) ) // 如果为空,说明其之前并不在等待对列中

__add_wait_queue(head, wait);  // 将wait entry 加入到等待队列之中

set_current_state(state);   // 使用 set_current_state()改变进程的运行状态

spin_unlock_irqstore(&head->lock, flags);

}

EXPORT_SYMBOL(prepare_to_wait);

void prepare_to_wait_exclusive(wait_queue_head_t *head,

wait_queue_head *wait, int state)

{

unsigned int flags;

wait->flags |= WQ_FLAG_EXCLUSIVE;  // 互斥唤醒进程;

spin_lock_irqsave(&head->lock, flags);

if(  list_empty(&wait->task_list) )

__add_wait_queue_tail(head, wait); //添加对尾

set_current_state(state);

spin_unlock_irqstore(&head->lock, flags);

}

EXPORT_SYMBOL(prepare_to_wait_exclusive);

从阻塞队列中删除一个等待进程的函数:

void  finish_wait(wait_queue_head_t *head, wait_queue_t *wait)

{

unsigned int flags;

__set_current_state(TASK_RUNNING); //将当前的进程状态改为运行态;

if( !list_empty_careful(&wait->task_list) ) // 确定进程在等待队列之中

{

spin_lock_irqsave(&head->lock, flags);

list_del_init(&wait->task_list);

spin_unlock_irqstore(&head->lock, flags);

}

}

EXPORT_SYMBOL(finish_wait);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值