comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/async-unix.h @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
comparison
equal deleted inserted replaced
67:0e9998148a16 69:33d812a61356
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2 // Licensed under the MIT License:
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21
22 #pragma once
23
24 #if _WIN32
25 #error "This file is Unix-specific. On Windows, include async-win32.h instead."
26 #endif
27
28 #include "async.h"
29 #include "timer.h"
30 #include <kj/vector.h>
31 #include <kj/io.h>
32 #include <signal.h>
33
34 KJ_BEGIN_HEADER
35
36 #if !defined(KJ_USE_EPOLL) && !defined(KJ_USE_KQUEUE)
37 #if __linux__
38 // Default to epoll on Linux.
39 #define KJ_USE_EPOLL 1
40 #elif __APPLE__ || __FreeBSD__ || __OpenBSD__ || __NetBSD__ || __DragonFly__
41 // MacOS and BSDs prefer kqueue() for event notification.
42 #define KJ_USE_KQUEUE 1
43 #endif
44 #endif
45
46 #if KJ_USE_EPOLL && KJ_USE_KQUEUE
47 #error "Both KJ_USE_EPOLL and KJ_USE_KQUEUE are set. Please choose only one of these."
48 #endif
49
50 #if __CYGWIN__ && !defined(KJ_USE_PIPE_FOR_WAKEUP)
51 // Cygwin has serious issues with the intersection of signals and threads, reported here:
52 // https://cygwin.com/ml/cygwin/2019-07/msg00052.html
53 // On Cygwin, therefore, we do not use signals to wake threads. Instead, each thread allocates a
54 // pipe, and we write a byte to the pipe to wake the thread... ick.
55 #define KJ_USE_PIPE_FOR_WAKEUP 1
56 #endif
57
58 #if KJ_USE_EPOLL
59 struct epoll_event;
60 #elif KJ_USE_KQUEUE
61 struct kevent;
62 struct timespec;
63 #endif
64
65 namespace kj {
66
67 class UnixEventPort: public EventPort {
68 // An EventPort implementation which can wait for events on file descriptors as well as signals.
69 // This API only makes sense on Unix.
70 //
71 // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue).
72 // To also wait on signals without race conditions, the implementation may block signals until
73 // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before
74 // the signal was unblocked, or it may use a nicer platform-specific API.
75 //
76 // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you
77 // need to use SIGUSR1 for something else, you must offer a different signal by calling
78 // setReservedSignal() at startup. (On Linux, no signal is reserved; eventfd is used instead.)
79 //
80 // WARNING: A UnixEventPort can only be used in the thread and process that created it. In
81 // particular, note that after a fork(), a UnixEventPort created in the parent process will
82 // not work correctly in the child, even if the parent ceases to use its copy. In particular
83 // note that this means that server processes which daemonize themselves at startup must wait
84 // until after daemonization to create a UnixEventPort.
85 //
86 // TODO(cleanup): The above warning is no longer accurate -- daemonizing after creating a
87 // UnixEventPort should now work since we no longer use signalfd. But do we want to commit to
88 // keeping it that way? Note it's still unsafe to fork() and then use UnixEventPort from both
89 // processes!
90
91 public:
92 UnixEventPort();
93
94 ~UnixEventPort() noexcept(false);
95
96 class FdObserver;
97 // Class that watches an fd for readability or writability. See definition below.
98
99 Promise<siginfo_t> onSignal(int signum);
100 // When the given signal is delivered to this thread, return the corresponding siginfo_t.
101 // The signal must have been captured using `captureSignal()`.
102 //
103 // If `onSignal()` has not been called, the signal will remain blocked in this thread.
104 // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the
105 // next call to 'onSignal()' will receive it. Also, you can control which thread receives a
106 // process-wide signal by only calling `onSignal()` on that thread's event loop.
107 //
108 // The result of waiting on the same signal twice at once is undefined.
109 //
110 // WARNING: On MacOS and iOS, `onSignal()` will only see process-level signals, NOT
111 // thread-specific signals (i.e. not those sent with pthread_kill()). This is a limitation of
112 // Apple's implemnetation of kqueue() introduced in MacOS 10.14 which Apple says is not a bug.
113 // See: https://github.com/libevent/libevent/issues/765 Consider using kj::Executor or
114 // kj::newPromiseAndCrossThreadFulfiller() for cross-thread communications instead of signals.
115 // If you must have signals, build KJ and your app with `-DKJ_USE_KQUEUE=0`, which will cause
116 // KJ to fall back to a generic poll()-based implementation that is less efficient but handles
117 // thread-specific signals.
118
119 static void captureSignal(int signum);
120 // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may
121 // then pass it to `onSignal()`. This method is static because it registers a signal handler
122 // which applies process-wide. If any other threads exist in the process when `captureSignal()`
123 // is called, you *must* set the signal mask in those threads to block this signal, otherwise
124 // terrible things will happen if the signal happens to be delivered to those threads. If at
125 // all possible, call `captureSignal()` *before* creating threads, so that threads you create in
126 // the future will inherit the proper signal mask.
127 //
128 // To un-capture a signal, simply install a different signal handler and then un-block it from
129 // the signal mask.
130
131 static void setReservedSignal(int signum);
132 // Sets the signal number which `UnixEventPort` reserves for internal use. If your application
133 // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before
134 // constructing an `UnixEventPort`) to offer a different signal.
135
136 Timer& getTimer() { return timerImpl; }
137
138 Promise<int> onChildExit(Maybe<pid_t>& pid);
139 // When the given child process exits, resolves to its wait status, as returned by wait(2). You
140 // will need to use the WIFEXITED() etc. macros to interpret the status code.
141 //
142 // You must call onChildExit() immediately after the child is created, before returning to the
143 // event loop. Otherwise, you may miss the child exit event.
144 //
145 // `pid` is a reference to a Maybe<pid_t> which must be non-null at the time of the call. When
146 // wait() is invoked (and indicates this pid has finished), `pid` will be nulled out. This is
147 // necessary to avoid a race condition: as soon as the child has been wait()ed, the PID table
148 // entry is freed and can then be reused. So, if you ever want safely to call `kill()` on the
149 // PID, it's necessary to know whether it has been wait()ed already. Since the promise's
150 // .then() continuation may not run immediately, we need a more precise way, hence we null out
151 // the Maybe.
152 //
153 // The caller must NOT null out `pid` on its own unless it cancels the Promise first. If the
154 // caller decides to cancel the Promise, and `pid` is still non-null after this cancellation,
155 // then the caller is expected to `waitpid()` on it BEFORE returning to the event loop again.
156 // Probably, the caller should kill() the child before waiting to avoid a hang. If the caller
157 // fails to do its own waitpid() before returning to the event loop, the child may become a
158 // zombie, or may be reaped automatically, depending on the platform -- since the caller does not
159 // know, the caller cannot try to reap the zombie later.
160 //
161 // You must call `kj::UnixEventPort::captureChildExit()` early in your program if you want to use
162 // `onChildExit()`.
163 //
164 // WARNING: Only one UnixEventPort per process is allowed to use onChildExit(). This is because
165 // child exit is signaled to the process via SIGCHLD, and Unix does not allow the program to
166 // control which thread receives the signal. (We may fix this in the future by automatically
167 // coordinating between threads when multiple threads are expecting child exits.)
168 // WARNING 2: If any UnixEventPort in the process is currently waiting for onChildExit(), then
169 // *only* that port's thread can safely wait on child processes, even synchronously. This is
170 // because the thread which used onChildExit() uses wait() to reap children, without specifying
171 // which child, and therefore it may inadvertently reap children created by other threads.
172
173 static void captureChildExit();
174 // Arranges for child process exit to be captured and handled via UnixEventPort, so that you may
175 // call `onChildExit()`. Much like `captureSignal()`, this static method must be called early on
176 // in program startup.
177 //
178 // This method may capture the `SIGCHLD` signal. You must not use `captureSignal(SIGCHLD)` nor
179 // `onSignal(SIGCHLD)` in your own code if you use `captureChildExit()`.
180
181 // implements EventPort ------------------------------------------------------
182 bool wait() override;
183 bool poll() override;
184 void wake() const override;
185
186 private:
187 class SignalPromiseAdapter;
188 class ChildExitPromiseAdapter;
189
190 const MonotonicClock& clock;
191 TimerImpl timerImpl;
192
193 #if !KJ_USE_KQUEUE
194 SignalPromiseAdapter* signalHead = nullptr;
195 SignalPromiseAdapter** signalTail = &signalHead;
196
197 void gotSignal(const siginfo_t& siginfo);
198 #endif
199
200 friend class TimerPromiseAdapter;
201
202 #if KJ_USE_EPOLL
203 sigset_t originalMask;
204 AutoCloseFd epollFd;
205 AutoCloseFd eventFd; // Used for cross-thread wakeups.
206
207 bool processEpollEvents(struct epoll_event events[], int n);
208 #elif KJ_USE_KQUEUE
209 AutoCloseFd kqueueFd;
210
211 bool doKqueueWait(struct timespec* timeout);
212 #else
213 class PollContext;
214
215 FdObserver* observersHead = nullptr;
216 FdObserver** observersTail = &observersHead;
217
218 #if KJ_USE_PIPE_FOR_WAKEUP
219 AutoCloseFd wakePipeIn;
220 AutoCloseFd wakePipeOut;
221 #else
222 unsigned long long threadId; // actually pthread_t
223 #endif
224 #endif
225
226 #if !KJ_USE_KQUEUE
227 struct ChildSet;
228 Maybe<Own<ChildSet>> childSet;
229 #endif
230
231 static void signalHandler(int, siginfo_t* siginfo, void*) noexcept;
232 static void registerSignalHandler(int signum);
233 #if !KJ_USE_EPOLL && !KJ_USE_KQUEUE && !KJ_USE_PIPE_FOR_WAKEUP
234 static void registerReservedSignal();
235 #endif
236 static void ignoreSigpipe();
237 };
238
239 class UnixEventPort::FdObserver: private AsyncObject {
240 // Object which watches a file descriptor to determine when it is readable or writable.
241 //
242 // For listen sockets, "readable" means that there is a connection to accept(). For everything
243 // else, it means that read() (or recv()) will return data.
244 //
245 // The presence of out-of-band data should NOT fire this event. However, the event may
246 // occasionally fire spuriously (when there is actually no data to read), and one thing that can
247 // cause such spurious events is the arrival of OOB data on certain platforms whose event
248 // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX).
249 //
250 // WARNING: The exact behavior of this class differs across systems, since event interfaces
251 // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified
252 // behavior. If at all possible, use the higher-level AsyncInputStream interface instead.
253
254 public:
255 enum Flags {
256 OBSERVE_READ = 1,
257 OBSERVE_WRITE = 2,
258 OBSERVE_URGENT = 4,
259 OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE
260 };
261
262 FdObserver(UnixEventPort& eventPort, int fd, uint flags);
263 // Begin watching the given file descriptor for readability. Only one ReadObserver may exist
264 // for a given file descriptor at a time.
265
266 ~FdObserver() noexcept(false);
267
268 KJ_DISALLOW_COPY_AND_MOVE(FdObserver);
269
270 Promise<void> whenBecomesReadable();
271 // Resolves the next time the file descriptor transitions from having no data to read to having
272 // some data to read.
273 //
274 // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
275 // to call this method when there is already data in the read buffer which has been there since
276 // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is
277 // unspecified whether the promise will ever resolve -- it depends on the underlying event
278 // mechanism being used.
279 //
280 // In order to avoid this problem, make sure that you only call `whenBecomesReadable()`
281 // only at times when you know the buffer is empty. You know this for sure when one of the
282 // following happens:
283 // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
284 // enabled on the fd!)
285 // * The file descriptor is a regular byte-oriented object (like a socket or pipe),
286 // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()`
287 // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note,
288 // though, that for record-oriented file descriptors like Linux's inotify interface, this
289 // rule does not hold, because it could simply be that the next record did not fit into the
290 // space available.)
291 //
292 // It is an error to call `whenBecomesReadable()` again when the promise returned previously
293 // has not yet resolved. If you do this, the previous promise may throw an exception.
294
295 inline Maybe<bool> atEndHint() { return atEnd; }
296 // Returns true if the event system has indicated that EOF has been received. There may still
297 // be data in the read buffer, but once that is gone, there's nothing left.
298 //
299 // Returns false if the event system has indicated that EOF had NOT been received as of the
300 // last turn of the event loop.
301 //
302 // Returns nullptr if the event system does not know whether EOF has been reached. In this
303 // case, the only way to know for sure is to call read() or recv() and check if it returns
304 // zero.
305 //
306 // This hint may be useful as an optimization to avoid an unnecessary system call.
307
308 Promise<void> whenBecomesWritable();
309 // Resolves the next time the file descriptor transitions from having no space available in the
310 // write buffer to having some space available.
311 //
312 // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
313 // to call this method when there is already space in the write buffer which has been there
314 // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case,
315 // it is unspecified whether the promise will ever resolve -- it depends on the underlying
316 // event mechanism being used.
317 //
318 // In order to avoid this problem, make sure that you only call `whenBecomesWritable()`
319 // only at times when you know the buffer is full. You know this for sure when one of the
320 // following happens:
321 // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
322 // enabled on the fd!)
323 // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can
324 // only happen if the buffer is full.
325 //
326 // It is an error to call `whenBecomesWritable()` again when the promise returned previously
327 // has not yet resolved. If you do this, the previous promise may throw an exception.
328
329 Promise<void> whenUrgentDataAvailable();
330 // Resolves the next time the file descriptor's read buffer contains "urgent" data.
331 //
332 // The conditions for availability of urgent data are specific to the file descriptor's
333 // underlying implementation.
334 //
335 // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously
336 // has not yet resolved. If you do this, the previous promise may throw an exception.
337 //
338 // WARNING: This has some known weird behavior on macOS. See
339 // https://github.com/capnproto/capnproto/issues/374.
340
341 Promise<void> whenWriteDisconnected();
342 // Resolves when poll() on the file descriptor reports POLLHUP or POLLERR.
343
344 private:
345 UnixEventPort& eventPort;
346 int fd;
347 uint flags;
348
349 kj::Maybe<Own<PromiseFulfiller<void>>> readFulfiller;
350 kj::Maybe<Own<PromiseFulfiller<void>>> writeFulfiller;
351 kj::Maybe<Own<PromiseFulfiller<void>>> urgentFulfiller;
352 kj::Maybe<Own<PromiseFulfiller<void>>> hupFulfiller;
353 // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to
354 // null every time an event is fired.
355
356 Maybe<bool> atEnd;
357
358 #if KJ_USE_KQUEUE
359 void fire(struct kevent event);
360 #else
361 void fire(short events);
362 #endif
363
364 #if !KJ_USE_EPOLL
365 FdObserver* next;
366 FdObserver** prev;
367 // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller.
368 // If `prev` is null then the observer is not currently in the list.
369
370 short getEventMask();
371 #endif
372
373 friend class UnixEventPort;
374 };
375
376 } // namespace kj
377
378 KJ_END_HEADER