about summary refs log tree commit diff
path: root/third_party/nix/src/libutil/monitor-fd.hh
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/nix/src/libutil/monitor-fd.hh')
-rw-r--r--third_party/nix/src/libutil/monitor-fd.hh57
1 files changed, 57 insertions, 0 deletions
diff --git a/third_party/nix/src/libutil/monitor-fd.hh b/third_party/nix/src/libutil/monitor-fd.hh
new file mode 100644
index 0000000000..c818c58261
--- /dev/null
+++ b/third_party/nix/src/libutil/monitor-fd.hh
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <atomic>
+#include <cstdlib>
+#include <thread>
+
+#include <poll.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace nix {
+
+class MonitorFdHup {
+ private:
+  std::thread thread;
+
+ public:
+  MonitorFdHup(int fd) {
+    thread = std::thread([fd]() {
+      while (true) {
+        /* Wait indefinitely until a POLLHUP occurs. */
+        struct pollfd fds[1];
+        fds[0].fd = fd;
+        /* This shouldn't be necessary, but macOS doesn't seem to
+           like a zeroed out events field.
+           See rdar://37537852.
+        */
+        fds[0].events = POLLHUP;
+        auto count = poll(fds, 1, -1);
+        if (count == -1) {
+          abort();
+        }  // can't happen
+        /* This shouldn't happen, but can on macOS due to a bug.
+           See rdar://37550628.
+
+           This may eventually need a delay or further
+           coordination with the main thread if spinning proves
+           too harmful.
+         */
+        if (count == 0) {
+          continue;
+        }
+        assert(fds[0].revents & POLLHUP);
+        triggerInterrupt();
+        break;
+      }
+    });
+  };
+
+  ~MonitorFdHup() {
+    pthread_cancel(thread.native_handle());
+    thread.join();
+  }
+};
+
+}  // namespace nix