wait queue 还可以用于等待某个atomic变量为0,例如下下例中等待cookie->n_active == 0
wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, TASK_UNINTERRUPTIBLE);
其中fscache_wait_atomic_t 仅仅就是通过schedule() 让出cpu.
int fscache_wait_atomic_t(atomic_t *p)
{
schedule();
return 0;
}
和wait_on_atomic_t 对应的wakeup函数如下:
void wake_up_atomic_t(atomic_t *p)
{
__wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR);
}
wake_up_atomic_t 就是简单的调用__wake_up_bit而已。
我们重点看看wait_on_atomic_t的实现
static inline
int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode)
{
might_sleep();
if (atomic_read(val) == 0)
return 0;
return out_of_line_wait_on_atomic_t(val, action, mode);
}
首先判断val 是否为0,如果已经是0了,就不用等待了,否则调用out_of_line_wait_on_atomic_t
__sched int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *),
unsigned mode)
{
wait_queue_head_t *wq = atomic_t_waitqueue(p);
DEFINE_WAIT_ATOMIC_T(wait, p);
return __wait_on_atomic_t(wq, &wait, action, mode);
}
out_of_line_wait_on_atomic_t 首先得到wait_queue_head_t
static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p)
{
if (BITS_PER_LONG == 64) {
unsigned long q = (unsigned long)p;
return bit_waitqueue((void *)(q & ~1), q & 1);
}
return bit_waitqueue(p, 0);
}
这个函数通过bit_waitqueue得到wait_queue_head_t。64 和 32 bit的参数会有点区别.
out_of_line_wait_on_atomic_t 通过 DEFINE_WAIT_ATOMIC_T得到 wait queue
#define DEFINE_WAIT_ATOMIC_T(name, p) \
struct wait_bit_queue name = { \
.key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p), \
.wait = { \
.private = current, \
.func = wake_atomic_t_function, \
.task_list = \
LIST_HEAD_INIT((name).wait.task_list), \
}, \
}
这个和之前非atomic的却别是func不一样wake_atomic_t_function
wake_atomic_t_function 和之前的autoremove_wake_function 相比也就多了key.flags 和 key.bit_nr 的判断.看起来是wakeup的时候
key.flags 和 key.bit_nr和之前注册到wait_queue_head_t 里面的可能会变化.
static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync,
void *arg)
{
struct wait_bit_key *key = arg;
struct wait_bit_queue *wait_bit
= container_of(wait, struct wait_bit_queue, wait);
atomic_t *val = key->flags;
if (wait_bit->key.flags != key->flags ||
wait_bit->key.bit_nr != key->bit_nr ||
atomic_read(val) != 0)
return 0;
return autoremove_wake_function(wait, mode, sync, key);
}
out_of_line_wait_on_atomic_t 最后调用__wait_on_atomic_t
static __sched
int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
int (*action)(atomic_t *), unsigned mode)
{
atomic_t *val;
int ret = 0;
do {
prepare_to_wait(wq, &q->wait, mode);
val = q->key.flags;
if (atomic_read(val) == 0)
break;
ret = (*action)(val);
} while (!ret && atomic_read(val) != 0);
finish_wait(wq, &q->wait);
return ret;
}
这个和之前的___wait_event 相比也就是多了对atomic_read(val) 值的判断.
wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, TASK_UNINTERRUPTIBLE);
其中fscache_wait_atomic_t 仅仅就是通过schedule() 让出cpu.
int fscache_wait_atomic_t(atomic_t *p)
{
schedule();
return 0;
}
和wait_on_atomic_t 对应的wakeup函数如下:
void wake_up_atomic_t(atomic_t *p)
{
__wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR);
}
wake_up_atomic_t 就是简单的调用__wake_up_bit而已。
我们重点看看wait_on_atomic_t的实现
static inline
int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode)
{
might_sleep();
if (atomic_read(val) == 0)
return 0;
return out_of_line_wait_on_atomic_t(val, action, mode);
}
首先判断val 是否为0,如果已经是0了,就不用等待了,否则调用out_of_line_wait_on_atomic_t
__sched int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *),
unsigned mode)
{
wait_queue_head_t *wq = atomic_t_waitqueue(p);
DEFINE_WAIT_ATOMIC_T(wait, p);
return __wait_on_atomic_t(wq, &wait, action, mode);
}
out_of_line_wait_on_atomic_t 首先得到wait_queue_head_t
static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p)
{
if (BITS_PER_LONG == 64) {
unsigned long q = (unsigned long)p;
return bit_waitqueue((void *)(q & ~1), q & 1);
}
return bit_waitqueue(p, 0);
}
这个函数通过bit_waitqueue得到wait_queue_head_t。64 和 32 bit的参数会有点区别.
out_of_line_wait_on_atomic_t 通过 DEFINE_WAIT_ATOMIC_T得到 wait queue
#define DEFINE_WAIT_ATOMIC_T(name, p) \
struct wait_bit_queue name = { \
.key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p), \
.wait = { \
.private = current, \
.func = wake_atomic_t_function, \
.task_list = \
LIST_HEAD_INIT((name).wait.task_list), \
}, \
}
这个和之前非atomic的却别是func不一样wake_atomic_t_function
wake_atomic_t_function 和之前的autoremove_wake_function 相比也就多了key.flags 和 key.bit_nr 的判断.看起来是wakeup的时候
key.flags 和 key.bit_nr和之前注册到wait_queue_head_t 里面的可能会变化.
static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync,
void *arg)
{
struct wait_bit_key *key = arg;
struct wait_bit_queue *wait_bit
= container_of(wait, struct wait_bit_queue, wait);
atomic_t *val = key->flags;
if (wait_bit->key.flags != key->flags ||
wait_bit->key.bit_nr != key->bit_nr ||
atomic_read(val) != 0)
return 0;
return autoremove_wake_function(wait, mode, sync, key);
}
out_of_line_wait_on_atomic_t 最后调用__wait_on_atomic_t
static __sched
int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q,
int (*action)(atomic_t *), unsigned mode)
{
atomic_t *val;
int ret = 0;
do {
prepare_to_wait(wq, &q->wait, mode);
val = q->key.flags;
if (atomic_read(val) == 0)
break;
ret = (*action)(val);
} while (!ret && atomic_read(val) != 0);
finish_wait(wq, &q->wait);
return ret;
}
这个和之前的___wait_event 相比也就是多了对atomic_read(val) 值的判断.