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