有没有办法在文件描述符关闭时执行回调(在Linux上)

时间:2018-02-08 22:49:23

标签: c linux file epoll kevent

我正在为Linux的kevent/kqueue emulation库工作。我是这个项目的新维护者,不幸的是,之前的维护者不再参与其中了(因此我无法回答他们的大脑)。

当您close() kqeueue()提供文件描述符时,在FreeBSD和macOS下,您可以释放与之关联的任何资源和事件。

现有代码似乎没有提供类似的界面。在我向API添加一个函数(或恢复旧函数)以显式释放kqueue资源之前,我想知道是否有任何方法可以将触发器与linux中的文件描述符相关联,这样当它关闭时我们可以清理任何与之相关的内容。 FD。

文件描述符本身可以是任何类型,即由eventfd提供的类型,或epoll或其他任何创建文件描述符的类型。

2 个答案:

答案 0 :(得分:1)

当关闭来自pipe()调用的最后一个写文件描述符epoll()/ poll()时,服务器将在仍然打开的任何读取文件描述符上看到[E] POLLHUP事件。据推测,任何表示连接而不是状态的fd都是如此。

答案 1 :(得分:0)

解决方案非常简单,如果实施起来有点烦人。它依靠称为fcntl的{​​{1}}来指定用于传达FD状态变化的信号,并依靠称为F_SETSIG的{​​{1}}来指定将信号传递到哪个线程

应用程序启动时会产生separate monitoring thread。该线程用于接收FD生成的信号。

在我们的特定用例中,必须在第一次创建被监视的FD时隐式启动监视线程,并在没有显式联接的情况下将其破坏。这是因为我们正在仿真FreeBSD API(kqueue),该API没有显式的init和deinit函数。

监视线程:

  1. Listens on a the signal我们传递给了fcntl
  2. Gets its thread ID,并将其存储在全局文件中。
  3. Informs the application使用F_SETOWN_EX启动了监视线程(并且填充了全局变量)。
  4. Calls pthread_detach,以确保正确清理它,而无需另一个线程进行显式F_SETSIG
  5. Calls sigwaitinfo等待信号传递。

应用程序线程:

  1. Uses pthread_once在首次创建FD时启动监视线程,然后等待监视线程完全启动。
  2. Uses F_SETSIG指定在打开/关闭FD时发送的信号,and F_SETOWN_EX将这些信号定向到监视线程。

关闭受监视的FD后,监视线程中的sigwaitinfo调用返回。在我们的例子中,我们使用管道来表示kqueue,因此我们需要map接收到信号的FD,到与需要释放的资源(kqueues)相关联的FD。映射完成后,我们可以(有关更多信息,请参见下文)清理与FD对相关的资源,然后再次调用pthread_cond_broadcast以等待更多信号。

该策略的其他关键要素之一是与FD相关的资源被引用计数。这是因为信号没有同步传递,因此可以关闭FD,并且可以在指示原始FD关闭的信号传递并起作用之前,使用相同的编号创建新FD。显然,这将导致释放活动资源的大问题。

为解决此问题,我们维护了一个互斥体同步FD到资源映射数组。此数组中的每个元素都包含特定FD的引用计数。

如果在创建新的管道/资源对时未重用FD之前传送信号,则该特定FD的引用计数将>0。发生这种情况时,我们立即释放资源并重新初始化它,增加参考数量。 传递指示FD已关闭的信号时,参考计数将减少(但不为零),并且资源不会释放。

或者,如果在重用FD之前发送信号,则监视线程将减少reference count to zero, and immediately free的相关资源。

如果这个描述有点令人困惑,您可以使用上面的任何链接查看我们在现实世界中的实现。

注意:我们的实现与上面描述的不完全相同(值得注意的是,在创建新的FD /资源映射时,我们不检查FD的引用计数)。我认为这是因为我们依赖于以下事实:关闭一个管道并不一定会导致另一端被关闭,因此开放端的FD无法立即重用。不幸的是,编写代码的开发人员无法查询。