我正在使用epoll library在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
结构的最佳方法是什么?
感谢您的时间。
答案 0 :(得分:12)
一切都很好。 epoll_ctl
函数是一个简单的系统调用包装器,当函数返回时它将完全完成。不需要来自用户空间的更多数据。结构只是一种打包参数的方法。
答案 1 :(得分:8)
立即丢弃或重复使用epoll_event结构是绝对正确的。
内核会将参数复制出epoll_event结构。
这与使用带有struct作为参数的ioctl或带有struct sockaddr_in的套接字操作(例如bind)完全相同。
内核可以满足它的需要,你可以立即释放它。
您唯一需要担心的是“用户数据”,它只与您相关。内核将存储它,但是当你得到一个事件时你需要知道它意味着什么。
答案 2 :(得分:4)
epoll
是一组系统调用,而不是库。当您调用epoll
系统调用时,您进入内核,并且内核通常不信任这些用户模式缓冲区必须有效或坚持,而是通过copy_from_user
等复制到内核内存中。所以是的,你可以在堆栈上设置结构,将它们的地址传递给系统调用,然后在它返回后丢弃它们。
答案 3 :(得分:0)
众所周知,struct epoll_event *
参数指向的内存可以在epoll_ctl()之后释放或重用。
在linux/v5.8/source/fs/eventpoll.c#L2288中,我们看到内核复制了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);
}