解析Linux内核的同步与互斥机制(四)

释放双眼,带上耳机,听听看~!

2.3.3 prepare_to_wait和finish_wait

/*

* Used to distinguish between sync and async io wait context:

* sync i/o typically specifies a NULL wait queue entry or a wait

* queue entry bound to a task (current task) to wake up.

* aio specifies a wait queue entry with an async notification

* callback routine, not associated with any task.

*/

#define is_sync_wait(wait) (!(wait) || ((wait)->private))

同步io等待将唤醒当前进程,异步io等待和当前进程无关,时间到后执行安装的回调函数

void fastcall

prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)

{

unsigned long flags;

wait->flags &= ~WQ_FLAG_EXCLUSIVE; //非排它性的等待将都被唤醒

spin_lock_irqsave(&q->lock, flags);

//等待节点尚未添加到任何等待队列中,防止重复加入

if (list_empty(&wait->task_list))

__add_wait_queue(q, wait);

if (is_sync_wait(wait))

set_current_state(state);

spin_unlock_irqrestore(&q->lock, flags);

}

prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)

wait->flags |= WQ_FLAG_EXCLUSIVE;

排他性等待,其余和prepare_to_wait一样

void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)

{

unsigned long flags;

__set_current_state(TASK_RUNNING); //确保进程状态为running

//若有等待进程,则将其从等待队列中删除

if (!list_empty_careful(&wait->task_list)) {

spin_lock_irqsave(&q->lock, flags);

list_del_init(&wait->task_list);

spin_unlock_irqrestore(&q->lock, flags);

}

}

3 等待事件event

Linux 内核中最简单的休眠方式是称为 wait_event的宏(及其变种),它实现了休眠和进程等待的条件的检查。形式如下:

wait_event(queue, condition)/*不可中断休眠,不推荐*/ wait_event_interruptible(queue, condition)/*推荐,返回非零值意味着休眠被中断,且驱动应返回 -ERESTARTSYS*/ wait_event_timeout(queue, condition, timeout) wait_event_interruptible_timeout(queue, condition, timeout) /*有限的时间的休眠;若超时,则不管条件为何值返回0,*/

上述四个宏函数为内核对外的接口,其他的休眠函数应避免使用。因为宏并不是函数,参数所做的任何修改对调用环境仍然有效,所以queue都是“值传递”,在宏内部会调用底层函数,采用的指针传递。Linux内核中存在大部分这样的宏,其都在接口上都是值传递。

3.1 wait_event

认真地看简单休眠中的 wait_event(queue, condition) 和 wait_event_interruptible(queue, condition) 底层源码会发现,其实他们只是手工休眠中的函数的组合。因此在驱动程序中应避免使用手动休眠代码,而应该采用内核已经封装好的四个wait_event系列函数。

\include\linux\wait.h

#define __wait_event(wq,condition) \

do { \

DEFINE_WAIT(__wait); \

\

for(;;) { \

prepare_to_wait(&wq,&__wait,TASK_UNINTERRUPTIBLE); \

/// 添加到等待队列中,同时更改进程状态;若已经加入则不会重复添加

if (condition) \

break; \

schedule(); //何时返回呢??? \

} \

finish_wait(&wq,&__wait); \

} while (0)

// “__”表示内部函数,默认为condition不满足,添加至等待队列,调度

注意prepare_to_wait和finish_wait的匹配关系

#define wait_event(wq,condition) \

do { \

if(condition) \

break; \

__wait_event(wq,condition); \

}while (0)

// 对外的接口函数,需要判断condition,若假则等待;若真则直接退出


等待系列函数架构设计:

3.2 wait_event_timeout

#define __wait_event_timeout(wq, condition, ret) \

do { \

DEFINE_WAIT(__wait); \

\

for (;;) { \

prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \

if (condition) \

break; \

ret = schedule_timeout(ret); \

if (!ret) \

break; //延时到,退出 \

} \

finish_wait(&wq, &__wait); \

} while (0)

#define wait_event_timeout(wq,condition,timeout) \

({ \

long __ret=timeout; \

if( !(condition) ) \

__wait_event_timeout( wq,condition,__ret); \

__ret; \

})

3.3 wait_event_interruptible

#define __wait_event_interruptible(wq, condition, ret) \

do { \

DEFINE_WAIT(__wait); \

\

for (;;) { \

prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \

if (condition) \

break; \

if (!signal_pending(current)) { \

schedule(); \

continue; \

} \

ret = -ERESTARTSYS; \

break; \

} \

finish_wait(&wq, &__wait); \

} while (0)

给TA打赏
共{{data.count}}人
人已打赏
安全运维

WordPress网站专用docker容器环境带Waf

2020-7-18 20:04:44

安全运维

运维安全-Gitlab管理员权限安全思考

2021-9-19 9:16:14

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索