深入理解eventfd_signal
Overview
1 | eventfd_signal |
1 | static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode, |
由__wake_up_common
的实现可知,最终eventfd_signal
调用了wait_queue_entry
的func
回调。1
2
3
4
5
6
7
8
9/*
* A single wait-queue entry structure:
*/
struct wait_queue_entry {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head entry;
};
vhost_poll_wakeup
源码解析:vhost ioeventfd与irqfd中提到过vhost_poll_wakeup
,那么这个函数又是如何与eventfd_signal
关联起来的呢?
1 | void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, |
由上述代码片段可知,vhost_poll_wakeup
被设置为了wait_queue_entry
的func
回调。
由此可知,eventfd_signal
最终调用了vhost_poll_wakeup
函数;因此,vhost_poll_wakeup
函数运行上下文是vCPU线程(kvm调用了eventfd_signal
,而kvm的运行上下文是vCPU线程)。
1 | ioeventfd_write |
select/poll/epoll wait_queue_entry
的func
回调
1 | // for select and poll |
对于select
和poll
,wait_queue_entry
的func
回调是pollwake
。
1 | // for epoll |
对于epoll
,wait_queue_entry
的func
回调是ep_poll_callback
。
为了方便起见,本文只详细介绍下pollwake
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// 在等待队列(wait_queue_t)上回调函数(func)
// 文件就绪后被调用,唤醒调用进程,其中key是文件提供的当前状态掩码
static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
struct poll_table_entry *entry;
// 取得文件对应的poll_table_entry
entry = container_of(wait, struct poll_table_entry, wait);
// 过滤不关注的事件
if (key && !((unsigned long)key & entry->key)) {
return 0;
}
// 唤醒
return __pollwake(wait, mode, sync, key);
}
static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
struct poll_wqueues *pwq = wait->private;
// 将调用进程 pwq->polling_task 关联到 dummy_wait
DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);
smp_wmb();
pwq->triggered = 1;// 标记为已触发
// 唤醒调用进程
return default_wake_function(&dummy_wait, mode, sync, key);
}
// 默认的唤醒函数,poll/select 设置的回调函数会调用此函数唤醒
// 直接唤醒等待队列上的线程,即将线程移到运行队列(rq)
int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
void *key)
{
// 这个函数比较复杂, 这里就不具体分析了
return try_to_wake_up(curr->private, mode, wake_flags);
}
参考资料: