Mercurial > repos > rliterman > csp2
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 |