capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

async-unix.h (15007B)


      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 #pragma once
     23 
     24 #if _WIN32
     25 #error "This file is Unix-specific. On Windows, include async-win32.h instead."
     26 #endif
     27 
     28 #include "async.h"
     29 #include "timer.h"
     30 #include "vector.h"
     31 #include "io.h"
     32 #include <signal.h>
     33 
     34 KJ_BEGIN_HEADER
     35 
     36 #if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL)
     37 // Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h.
     38 #define KJ_USE_EPOLL 1
     39 #endif
     40 
     41 #if __CYGWIN__ && !defined(KJ_USE_PIPE_FOR_WAKEUP)
     42 // Cygwin has serious issues with the intersection of signals and threads, reported here:
     43 //     https://cygwin.com/ml/cygwin/2019-07/msg00052.html
     44 // On Cygwin, therefore, we do not use signals to wake threads. Instead, each thread allocates a
     45 // pipe, and we write a byte to the pipe to wake the thread... ick.
     46 #define KJ_USE_PIPE_FOR_WAKEUP 1
     47 #endif
     48 
     49 namespace kj {
     50 
     51 class UnixEventPort: public EventPort {
     52   // An EventPort implementation which can wait for events on file descriptors as well as signals.
     53   // This API only makes sense on Unix.
     54   //
     55   // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue).
     56   // To also wait on signals without race conditions, the implementation may block signals until
     57   // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before
     58   // the signal was unblocked, or it may use a nicer platform-specific API like signalfd.
     59   //
     60   // The implementation reserves a signal for internal use.  By default, it uses SIGUSR1.  If you
     61   // need to use SIGUSR1 for something else, you must offer a different signal by calling
     62   // setReservedSignal() at startup.
     63   //
     64   // WARNING: A UnixEventPort can only be used in the thread and process that created it. In
     65   //   particular, note that after a fork(), a UnixEventPort created in the parent process will
     66   //   not work correctly in the child, even if the parent ceases to use its copy. In particular
     67   //   note that this means that server processes which daemonize themselves at startup must wait
     68   //   until after daemonization to create a UnixEventPort.
     69 
     70 public:
     71   UnixEventPort();
     72   ~UnixEventPort() noexcept(false);
     73 
     74   class FdObserver;
     75   // Class that watches an fd for readability or writability. See definition below.
     76 
     77   Promise<siginfo_t> onSignal(int signum);
     78   // When the given signal is delivered to this thread, return the corresponding siginfo_t.
     79   // The signal must have been captured using `captureSignal()`.
     80   //
     81   // If `onSignal()` has not been called, the signal will remain blocked in this thread.
     82   // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the
     83   // next call to 'onSignal()' will receive it.  Also, you can control which thread receives a
     84   // process-wide signal by only calling `onSignal()` on that thread's event loop.
     85   //
     86   // The result of waiting on the same signal twice at once is undefined.
     87 
     88   static void captureSignal(int signum);
     89   // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may
     90   // then pass it to `onSignal()`.  This method is static because it registers a signal handler
     91   // which applies process-wide.  If any other threads exist in the process when `captureSignal()`
     92   // is called, you *must* set the signal mask in those threads to block this signal, otherwise
     93   // terrible things will happen if the signal happens to be delivered to those threads.  If at
     94   // all possible, call `captureSignal()` *before* creating threads, so that threads you create in
     95   // the future will inherit the proper signal mask.
     96   //
     97   // To un-capture a signal, simply install a different signal handler and then un-block it from
     98   // the signal mask.
     99 
    100   static void setReservedSignal(int signum);
    101   // Sets the signal number which `UnixEventPort` reserves for internal use.  If your application
    102   // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before
    103   // constructing an `UnixEventPort`) to offer a different signal.
    104 
    105   Timer& getTimer() { return timerImpl; }
    106 
    107   Promise<int> onChildExit(Maybe<pid_t>& pid);
    108   // When the given child process exits, resolves to its wait status, as returned by wait(2). You
    109   // will need to use the WIFEXITED() etc. macros to interpret the status code.
    110   //
    111   // You must call onChildExit() immediately after the child is created, before returning to the
    112   // event loop. Otherwise, you may miss the child exit event.
    113   //
    114   // `pid` is a reference to a Maybe<pid_t> which must be non-null at the time of the call. When
    115   // wait() is invoked (and indicates this pid has finished), `pid` will be nulled out. This is
    116   // necessary to avoid a race condition: as soon as the child has been wait()ed, the PID table
    117   // entry is freed and can then be reused. So, if you ever want safely to call `kill()` on the
    118   // PID, it's necessary to know whether it has been wait()ed already. Since the promise's
    119   // .then() continuation may not run immediately, we need a more precise way, hence we null out
    120   // the Maybe.
    121   //
    122   // You must call `kj::UnixEventPort::captureChildExit()` early in your program if you want to use
    123   // `onChildExit()`.
    124   //
    125   // WARNING: Only one UnixEventPort per process is allowed to use onChildExit(). This is because
    126   //   child exit is signaled to the process via SIGCHLD, and Unix does not allow the program to
    127   //   control which thread receives the signal. (We may fix this in the future by automatically
    128   //   coordinating between threads when multiple threads are expecting child exits.)
    129   // WARNING 2: If any UnixEventPort in the process is currently waiting for onChildExit(), then
    130   //   *only* that port's thread can safely wait on child processes, even synchronously. This is
    131   //   because the thread which used onChildExit() uses wait() to reap children, without specifying
    132   //   which child, and therefore it may inadvertently reap children created by other threads.
    133 
    134   static void captureChildExit();
    135   // Arranges for child process exit to be captured and handled via UnixEventPort, so that you may
    136   // call `onChildExit()`. Much like `captureSignal()`, this static method must be called early on
    137   // in program startup.
    138   //
    139   // This method may capture the `SIGCHLD` signal. You must not use `captureSignal(SIGCHLD)` nor
    140   // `onSignal(SIGCHLD)` in your own code if you use `captureChildExit()`.
    141 
    142   // implements EventPort ------------------------------------------------------
    143   bool wait() override;
    144   bool poll() override;
    145   void wake() const override;
    146 
    147 private:
    148   class SignalPromiseAdapter;
    149   class ChildExitPromiseAdapter;
    150 
    151   const MonotonicClock& clock;
    152   TimerImpl timerImpl;
    153 
    154   SignalPromiseAdapter* signalHead = nullptr;
    155   SignalPromiseAdapter** signalTail = &signalHead;
    156 
    157   void gotSignal(const siginfo_t& siginfo);
    158 
    159   friend class TimerPromiseAdapter;
    160 
    161 #if KJ_USE_EPOLL
    162   AutoCloseFd epollFd;
    163   AutoCloseFd signalFd;
    164   AutoCloseFd eventFd;   // Used for cross-thread wakeups.
    165 
    166   sigset_t signalFdSigset;
    167   // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it
    168   // needs updating.
    169 
    170   bool doEpollWait(int timeout);
    171 
    172 #else
    173   class PollContext;
    174 
    175   FdObserver* observersHead = nullptr;
    176   FdObserver** observersTail = &observersHead;
    177 
    178 #if KJ_USE_PIPE_FOR_WAKEUP
    179   AutoCloseFd wakePipeIn;
    180   AutoCloseFd wakePipeOut;
    181 #else
    182   unsigned long long threadId;  // actually pthread_t
    183 #endif
    184 #endif
    185 
    186   struct ChildSet;
    187   Maybe<Own<ChildSet>> childSet;
    188 };
    189 
    190 class UnixEventPort::FdObserver {
    191   // Object which watches a file descriptor to determine when it is readable or writable.
    192   //
    193   // For listen sockets, "readable" means that there is a connection to accept(). For everything
    194   // else, it means that read() (or recv()) will return data.
    195   //
    196   // The presence of out-of-band data should NOT fire this event. However, the event may
    197   // occasionally fire spuriously (when there is actually no data to read), and one thing that can
    198   // cause such spurious events is the arrival of OOB data on certain platforms whose event
    199   // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX).
    200   //
    201   // WARNING: The exact behavior of this class differs across systems, since event interfaces
    202   //   vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified
    203   //   behavior. If at all possible, use the higher-level AsyncInputStream interface instead.
    204 
    205 public:
    206   enum Flags {
    207     OBSERVE_READ = 1,
    208     OBSERVE_WRITE = 2,
    209     OBSERVE_URGENT = 4,
    210     OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE
    211   };
    212 
    213   FdObserver(UnixEventPort& eventPort, int fd, uint flags);
    214   // Begin watching the given file descriptor for readability. Only one ReadObserver may exist
    215   // for a given file descriptor at a time.
    216 
    217   ~FdObserver() noexcept(false);
    218 
    219   KJ_DISALLOW_COPY(FdObserver);
    220 
    221   Promise<void> whenBecomesReadable();
    222   // Resolves the next time the file descriptor transitions from having no data to read to having
    223   // some data to read.
    224   //
    225   // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
    226   // to call this method when there is already data in the read buffer which has been there since
    227   // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is
    228   // unspecified whether the promise will ever resolve -- it depends on the underlying event
    229   // mechanism being used.
    230   //
    231   // In order to avoid this problem, make sure that you only call `whenBecomesReadable()`
    232   // only at times when you know the buffer is empty. You know this for sure when one of the
    233   // following happens:
    234   // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
    235   //   enabled on the fd!)
    236   // * The file descriptor is a regular byte-oriented object (like a socket or pipe),
    237   //   read() or recv() returns fewer than the number of bytes requested, and `atEndHint()`
    238   //   returns false. This can only happen if the buffer is empty but EOF is not reached. (Note,
    239   //   though, that for record-oriented file descriptors like Linux's inotify interface, this
    240   //   rule does not hold, because it could simply be that the next record did not fit into the
    241   //   space available.)
    242   //
    243   // It is an error to call `whenBecomesReadable()` again when the promise returned previously
    244   // has not yet resolved. If you do this, the previous promise may throw an exception.
    245 
    246   inline Maybe<bool> atEndHint() { return atEnd; }
    247   // Returns true if the event system has indicated that EOF has been received. There may still
    248   // be data in the read buffer, but once that is gone, there's nothing left.
    249   //
    250   // Returns false if the event system has indicated that EOF had NOT been received as of the
    251   // last turn of the event loop.
    252   //
    253   // Returns nullptr if the event system does not know whether EOF has been reached. In this
    254   // case, the only way to know for sure is to call read() or recv() and check if it returns
    255   // zero.
    256   //
    257   // This hint may be useful as an optimization to avoid an unnecessary system call.
    258 
    259   Promise<void> whenBecomesWritable();
    260   // Resolves the next time the file descriptor transitions from having no space available in the
    261   // write buffer to having some space available.
    262   //
    263   // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
    264   // to call this method when there is already space in the write buffer which has been there
    265   // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case,
    266   // it is unspecified whether the promise will ever resolve -- it depends on the underlying
    267   // event mechanism being used.
    268   //
    269   // In order to avoid this problem, make sure that you only call `whenBecomesWritable()`
    270   // only at times when you know the buffer is full. You know this for sure when one of the
    271   // following happens:
    272   // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
    273   //   enabled on the fd!)
    274   // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can
    275   //   only happen if the buffer is full.
    276   //
    277   // It is an error to call `whenBecomesWritable()` again when the promise returned previously
    278   // has not yet resolved. If you do this, the previous promise may throw an exception.
    279 
    280   Promise<void> whenUrgentDataAvailable();
    281   // Resolves the next time the file descriptor's read buffer contains "urgent" data.
    282   //
    283   // The conditions for availability of urgent data are specific to the file descriptor's
    284   // underlying implementation.
    285   //
    286   // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously
    287   // has not yet resolved. If you do this, the previous promise may throw an exception.
    288   //
    289   // WARNING: This has some known weird behavior on macOS. See
    290   //   https://github.com/sandstorm-io/capnproto/issues/374.
    291 
    292   Promise<void> whenWriteDisconnected();
    293   // Resolves when poll() on the file descriptor reports POLLHUP or POLLERR.
    294 
    295 private:
    296   UnixEventPort& eventPort;
    297   int fd;
    298   uint flags;
    299 
    300   kj::Maybe<Own<PromiseFulfiller<void>>> readFulfiller;
    301   kj::Maybe<Own<PromiseFulfiller<void>>> writeFulfiller;
    302   kj::Maybe<Own<PromiseFulfiller<void>>> urgentFulfiller;
    303   kj::Maybe<Own<PromiseFulfiller<void>>> hupFulfiller;
    304   // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to
    305   // null every time an event is fired.
    306 
    307   Maybe<bool> atEnd;
    308 
    309   void fire(short events);
    310 
    311 #if !KJ_USE_EPOLL
    312   FdObserver* next;
    313   FdObserver** prev;
    314   // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller.
    315   // If `prev` is null then the observer is not currently in the list.
    316 
    317   short getEventMask();
    318 #endif
    319 
    320   friend class UnixEventPort;
    321 };
    322 
    323 }  // namespace kj
    324 
    325 KJ_END_HEADER