annotate win64-msvc/include/kj/async-unix.h @ 64:eccd51b72864

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