annotate win32-mingw/include/kj/async-unix.h @ 83:ae30d91d2ffe

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