Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/async-unix.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
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 #ifndef KJ_ASYNC_UNIX_H_ | |
23 #define KJ_ASYNC_UNIX_H_ | |
24 | |
25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS | |
26 #pragma GCC system_header | |
27 #endif | |
28 | |
29 #include "async.h" | |
30 #include "time.h" | |
31 #include "vector.h" | |
32 #include "io.h" | |
33 #include <signal.h> | |
34 | |
35 #if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL) | |
36 // Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h. | |
37 #define KJ_USE_EPOLL 1 | |
38 #endif | |
39 | |
40 namespace kj { | |
41 | |
42 class UnixEventPort: public EventPort { | |
43 // An EventPort implementation which can wait for events on file descriptors as well as signals. | |
44 // This API only makes sense on Unix. | |
45 // | |
46 // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue). | |
47 // To also wait on signals without race conditions, the implementation may block signals until | |
48 // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before | |
49 // the signal was unblocked, or it may use a nicer platform-specific API like signalfd. | |
50 // | |
51 // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you | |
52 // need to use SIGUSR1 for something else, you must offer a different signal by calling | |
53 // setReservedSignal() at startup. | |
54 // | |
55 // WARNING: A UnixEventPort can only be used in the thread and process that created it. In | |
56 // particular, note that after a fork(), a UnixEventPort created in the parent process will | |
57 // not work correctly in the child, even if the parent ceases to use its copy. In particular | |
58 // note that this means that server processes which daemonize themselves at startup must wait | |
59 // until after daemonization to create a UnixEventPort. | |
60 | |
61 public: | |
62 UnixEventPort(); | |
63 ~UnixEventPort() noexcept(false); | |
64 | |
65 class FdObserver; | |
66 // Class that watches an fd for readability or writability. See definition below. | |
67 | |
68 Promise<siginfo_t> onSignal(int signum); | |
69 // When the given signal is delivered to this thread, return the corresponding siginfo_t. | |
70 // The signal must have been captured using `captureSignal()`. | |
71 // | |
72 // If `onSignal()` has not been called, the signal will remain blocked in this thread. | |
73 // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the | |
74 // next call to 'onSignal()' will receive it. Also, you can control which thread receives a | |
75 // process-wide signal by only calling `onSignal()` on that thread's event loop. | |
76 // | |
77 // The result of waiting on the same signal twice at once is undefined. | |
78 | |
79 static void captureSignal(int signum); | |
80 // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may | |
81 // then pass it to `onSignal()`. This method is static because it registers a signal handler | |
82 // which applies process-wide. If any other threads exist in the process when `captureSignal()` | |
83 // is called, you *must* set the signal mask in those threads to block this signal, otherwise | |
84 // terrible things will happen if the signal happens to be delivered to those threads. If at | |
85 // all possible, call `captureSignal()` *before* creating threads, so that threads you create in | |
86 // the future will inherit the proper signal mask. | |
87 // | |
88 // To un-capture a signal, simply install a different signal handler and then un-block it from | |
89 // the signal mask. | |
90 | |
91 static void setReservedSignal(int signum); | |
92 // Sets the signal number which `UnixEventPort` reserves for internal use. If your application | |
93 // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before | |
94 // constructing an `UnixEventPort`) to offer a different signal. | |
95 | |
96 TimePoint steadyTime() { return frozenSteadyTime; } | |
97 Promise<void> atSteadyTime(TimePoint time); | |
98 | |
99 // implements EventPort ------------------------------------------------------ | |
100 bool wait() override; | |
101 bool poll() override; | |
102 void wake() const override; | |
103 | |
104 private: | |
105 struct TimerSet; // Defined in source file to avoid STL include. | |
106 class TimerPromiseAdapter; | |
107 class SignalPromiseAdapter; | |
108 | |
109 Own<TimerSet> timers; | |
110 TimePoint frozenSteadyTime; | |
111 | |
112 SignalPromiseAdapter* signalHead = nullptr; | |
113 SignalPromiseAdapter** signalTail = &signalHead; | |
114 | |
115 TimePoint currentSteadyTime(); | |
116 void processTimers(); | |
117 void gotSignal(const siginfo_t& siginfo); | |
118 | |
119 friend class TimerPromiseAdapter; | |
120 | |
121 #if KJ_USE_EPOLL | |
122 AutoCloseFd epollFd; | |
123 AutoCloseFd signalFd; | |
124 AutoCloseFd eventFd; // Used for cross-thread wakeups. | |
125 | |
126 sigset_t signalFdSigset; | |
127 // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it | |
128 // needs updating. | |
129 | |
130 bool doEpollWait(int timeout); | |
131 | |
132 #else | |
133 class PollContext; | |
134 | |
135 FdObserver* observersHead = nullptr; | |
136 FdObserver** observersTail = &observersHead; | |
137 | |
138 unsigned long long threadId; // actually pthread_t | |
139 #endif | |
140 }; | |
141 | |
142 class UnixEventPort::FdObserver { | |
143 // Object which watches a file descriptor to determine when it is readable or writable. | |
144 // | |
145 // For listen sockets, "readable" means that there is a connection to accept(). For everything | |
146 // else, it means that read() (or recv()) will return data. | |
147 // | |
148 // The presence of out-of-band data should NOT fire this event. However, the event may | |
149 // occasionally fire spuriously (when there is actually no data to read), and one thing that can | |
150 // cause such spurious events is the arrival of OOB data on certain platforms whose event | |
151 // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX). | |
152 // | |
153 // WARNING: The exact behavior of this class differs across systems, since event interfaces | |
154 // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified | |
155 // behavior. If at all possible, use the higher-level AsyncInputStream interface instead. | |
156 | |
157 public: | |
158 enum Flags { | |
159 OBSERVE_READ = 1, | |
160 OBSERVE_WRITE = 2, | |
161 OBSERVE_URGENT = 4, | |
162 OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE | |
163 }; | |
164 | |
165 FdObserver(UnixEventPort& eventPort, int fd, uint flags); | |
166 // Begin watching the given file descriptor for readability. Only one ReadObserver may exist | |
167 // for a given file descriptor at a time. | |
168 | |
169 ~FdObserver() noexcept(false); | |
170 | |
171 KJ_DISALLOW_COPY(FdObserver); | |
172 | |
173 Promise<void> whenBecomesReadable(); | |
174 // Resolves the next time the file descriptor transitions from having no data to read to having | |
175 // some data to read. | |
176 // | |
177 // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error | |
178 // to call this method when there is already data in the read buffer which has been there since | |
179 // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is | |
180 // unspecified whether the promise will ever resolve -- it depends on the underlying event | |
181 // mechanism being used. | |
182 // | |
183 // In order to avoid this problem, make sure that you only call `whenBecomesReadable()` | |
184 // only at times when you know the buffer is empty. You know this for sure when one of the | |
185 // following happens: | |
186 // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode | |
187 // enabled on the fd!) | |
188 // * The file descriptor is a regular byte-oriented object (like a socket or pipe), | |
189 // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()` | |
190 // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note, | |
191 // though, that for record-oriented file descriptors like Linux's inotify interface, this | |
192 // rule does not hold, because it could simply be that the next record did not fit into the | |
193 // space available.) | |
194 // | |
195 // It is an error to call `whenBecomesReadable()` again when the promise returned previously | |
196 // has not yet resolved. If you do this, the previous promise may throw an exception. | |
197 | |
198 inline Maybe<bool> atEndHint() { return atEnd; } | |
199 // Returns true if the event system has indicated that EOF has been received. There may still | |
200 // be data in the read buffer, but once that is gone, there's nothing left. | |
201 // | |
202 // Returns false if the event system has indicated that EOF had NOT been received as of the | |
203 // last turn of the event loop. | |
204 // | |
205 // Returns nullptr if the event system does not know whether EOF has been reached. In this | |
206 // case, the only way to know for sure is to call read() or recv() and check if it returns | |
207 // zero. | |
208 // | |
209 // This hint may be useful as an optimization to avoid an unnecessary system call. | |
210 | |
211 Promise<void> whenBecomesWritable(); | |
212 // Resolves the next time the file descriptor transitions from having no space available in the | |
213 // write buffer to having some space available. | |
214 // | |
215 // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error | |
216 // to call this method when there is already space in the write buffer which has been there | |
217 // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case, | |
218 // it is unspecified whether the promise will ever resolve -- it depends on the underlying | |
219 // event mechanism being used. | |
220 // | |
221 // In order to avoid this problem, make sure that you only call `whenBecomesWritable()` | |
222 // only at times when you know the buffer is full. You know this for sure when one of the | |
223 // following happens: | |
224 // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode | |
225 // enabled on the fd!) | |
226 // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can | |
227 // only happen if the buffer is full. | |
228 // | |
229 // It is an error to call `whenBecomesWritable()` again when the promise returned previously | |
230 // has not yet resolved. If you do this, the previous promise may throw an exception. | |
231 | |
232 Promise<void> whenUrgentDataAvailable(); | |
233 // Resolves the next time the file descriptor's read buffer contains "urgent" data. | |
234 // | |
235 // The conditions for availability of urgent data are specific to the file descriptor's | |
236 // underlying implementation. | |
237 // | |
238 // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously | |
239 // has not yet resolved. If you do this, the previous promise may throw an exception. | |
240 // | |
241 // WARNING: This has some known weird behavior on macOS. See | |
242 // https://github.com/sandstorm-io/capnproto/issues/374. | |
243 | |
244 private: | |
245 UnixEventPort& eventPort; | |
246 int fd; | |
247 uint flags; | |
248 | |
249 kj::Maybe<Own<PromiseFulfiller<void>>> readFulfiller; | |
250 kj::Maybe<Own<PromiseFulfiller<void>>> writeFulfiller; | |
251 kj::Maybe<Own<PromiseFulfiller<void>>> urgentFulfiller; | |
252 // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to | |
253 // null every time an event is fired. | |
254 | |
255 Maybe<bool> atEnd; | |
256 | |
257 void fire(short events); | |
258 | |
259 #if !KJ_USE_EPOLL | |
260 FdObserver* next; | |
261 FdObserver** prev; | |
262 // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller. | |
263 // If `prev` is null then the observer is not currently in the list. | |
264 | |
265 short getEventMask(); | |
266 #endif | |
267 | |
268 friend class UnixEventPort; | |
269 }; | |
270 | |
271 } // namespace kj | |
272 | |
273 #endif // KJ_ASYNC_UNIX_H_ |