Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epoll触发机制分析 #64

Open
taikulawo opened this issue Nov 7, 2023 · 2 comments
Open

epoll触发机制分析 #64

taikulawo opened this issue Nov 7, 2023 · 2 comments
Labels

Comments

@taikulawo
Copy link
Collaborator

taikulawo commented Nov 7, 2023

目标:

分析 kernel 驱动收到后skb

1. 如何唤醒epoll callback?
2. accpet syscall 如何从listener socket spawn 子 socket?

一个极简epoll server程序(无法编译,只说明流程)

// 创建listener socket
int listener_fd = socket();
bind(listener_fd);
listen(listener_fd);
set_socket_non_blocking(listener_fd);

// 创建socket
ep = epoll_create1(0);
struct epoll_event event;
event.data.fd = listener_fd;
event.events = EPOLLIN | EPOLLET;
// 将listener socket注册进epoll
s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event);
for ( ;; ) {
    // eventloop
    int n = epoll_wait(ep, &events, 1024, -1);
    for (itn i = 0; i < n ; i ++) {
        if(events[i].data.fd == listener_fd) {
            // new incoming connection
            int child = accept(listener_fd, &addr, &addr_len);
            // 将子连接socket加入epoll eventloop
            make_socket_non_blocking(infd);
            struct epoll_event;
            event.data.fd = infd;
            event.events = EPOLLIN | EPOLLET;
            s = epoll_ctl(ep, EPOLL_CTL_ADD, child, &event);
        }
    }
}

epoll 注册 wake callback

直接看追踪的call stack

  1. epoll_ctl(ep, EPOLL_CTL_ADD, child, &event): called from epoll_ctl syscall
  2. ep_insert:
// ep_insert
epq.epi = epi;
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);

ep_ptable_queue_proc 放入 _qproc,在接下来的 poll_wait 调用

static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
{
   pt->_qproc = qproc;
   pt->_key   = ~(__poll_t)0; /* all events enabled */
}
  1. ep_item_poll
    1. 如果fd不是file epoll,那么通过vfs定向给具体实现
  2. vfs_poll: virtual fs poll,call file->f_op->poll(file, pt);
    1. sock poll: 文件底层对应的是sock
    2. unix_poll: address family unix poll
  3. sock_poll: socket 文件类型的poll
  4. tcp_poll: tcp socket poll 实现
  5. sock_poll_wait
  6. poll_wait
  7. ep_ptable_queue_proc
    1. ep_poll_callback 添加到 wait queue

struct file 转换成 struct sock

struct sock 有最核心弄明白的点在于skb buff 如何转换成 struct socket 结构

static __poll_t sock_poll(struct file *file, poll_table *wait)
{
    // 关键点
	struct socket *sock = file->private_data;
	const struct proto_ops *ops = READ_ONCE(sock->ops);
	__poll_t events = poll_requested_events(wait), flag = 0;

	if (!ops->poll)
		return 0;

	if (sk_can_busy_loop(sock->sk)) {
		/* poll once if requested by the syscall */
		if (events & POLL_BUSY_LOOP)
			sk_busy_loop(sock->sk, 1);

		/* if this socket can poll_ll, tell the system call */
		flag = POLL_BUSY_LOOP;
	}

	return ops->poll(file, sock, wait) | flag;
}

sock_poll将 file->private_data 转换成 struct sock,从而调用到epoll的socket实现

Why does the Linux kernel have `struct sock` and `struct socket`? - Stack Overflow

sock wake epoll callback

唤醒ep->wqep_poll_callback

@iugo
Copy link

iugo commented Nov 15, 2023

是在尝试实现一个 epoll 吗?

@taikulawo
Copy link
Collaborator Author

是在尝试实现一个 epoll 吗?

调试kernel协议栈时分析的。这是分析TCP/IP skb rcv最后一环(wake waiter)的文章

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants