16

我正在使用epoll 库在 C 中开发服务器,并且我有一个关于如何处理内存的问题struct epoll_event。我在一些在线示例中注意到,在进行epoll_ctl调用时,events参数被分配在堆栈上,然后指针被传递,如下所示:

struct epoll_event ev;
ev.events = EPOLLIN;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

现在我们都知道ev函数返回时会发生什么。我的问题是:epoll 库是在内部复制这些值还是依赖于您传递给堆分配的结构?上面的例子会完全破坏我的反应器实现吗?如果是这样,跟踪我的堆分配epoll_event结构的最佳方法是什么?

谢谢你的时间。

4

4 回答 4

19

一切安好。该epoll_ctl函数是对系统调用的简单包装,当函数返回时,系统调用将完全完成。不需要来自用户空间的更多数据。struct 只是一种打包参数的方法。

于 2012-10-19T21:03:51.490 回答
11

立即丢弃或重用您的 epoll_event 结构绝对没问题。

内核将从 epoll_event 结构体中复制参数。

这与您使用将结构作为参数的 ioctl 或使用 struct sockaddr_in 的套接字操作(例如绑定)完全相同。

内核获取它需要的东西,你可以立即释放它。

您唯一需要担心的是“用户数据”,它只与您相关。内核会存储它,但你需要知道当你得到一个事件时它意味着什么。

于 2012-10-19T21:05:15.687 回答
5

epoll是一组系统调用,而不是库。当您调用epoll系统调用时,您会进入内核,并且内核通常不相信这些用户模式缓冲区一定有效或保留,而是通过copy_from_user等方式复制到内核内存中。所以是的,您可以在堆栈上设置结构,将它们的地址传递给系统调用,然后在它返回后丢弃它们。

于 2012-10-19T21:06:53.260 回答
0

众所周知,参数指向的内存struct epoll_event *可以在 epoll_ctl() 之后释放或重用。

linux/v5.8/source/fs/eventpoll.c#L2288中,我们看到内核复制了 struct epoll_event,这证实了我们的想法。

SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        struct epoll_event __user *, event)
{
    struct epoll_event epds;

    if (ep_op_has_event(op) &&
        copy_from_user(&epds, event, sizeof(struct epoll_event)))
        return -EFAULT;

    return do_epoll_ctl(epfd, op, fd, &epds, false);
}
于 2020-08-18T04:06:09.817 回答