nixd
Loading...
Searching...
No Matches
ForkPipedPlatform.h
Go to the documentation of this file.
1#pragma once
2
3#include <fcntl.h>
4#include <mutex>
5#include <unistd.h>
6
7namespace nixd::detail {
8
9// Keep this scope alive from the first pipe creation through fork. Callers own
10// and close all pipe descriptors, including those left by a failed createPipe.
11#if defined(__linux__)
12class PipeForkScope {
13public:
14 int createPipe(int Pipe[2]) const { return pipe2(Pipe, O_CLOEXEC); }
15 pid_t forkProcess() { return fork(); }
16};
17#else
18// macOS has no pipe2. Serialize pipe creation and fork so another caller cannot
19// inherit a descriptor between pipe() and fcntl(). All concurrent process
20// creation must use this scope for that guarantee to hold.
22 static std::mutex &forkMutex() {
23 static std::mutex Mutex;
24 return Mutex;
25 }
26
27 std::unique_lock<std::mutex> Lock{forkMutex()};
28
29public:
30 int createPipe(int Pipe[2]) const {
31 if (pipe(Pipe) == -1)
32 return -1;
33 for (int I = 0; I < 2; ++I)
34 if (fcntl(Pipe[I], F_SETFD, FD_CLOEXEC) == -1)
35 return -1;
36 return 0;
37 }
38
39 pid_t forkProcess() {
40 const pid_t Child = fork();
41 // Only the parent may unlock the mutex. The child must exec or _exit
42 // without creating another PipeForkScope.
43 if (Child == 0)
44 Lock.release();
45 return Child;
46 }
47};
48#endif
49
50} // namespace nixd::detail
int createPipe(int Pipe[2]) const