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