cannam@147: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@147: // Licensed under the MIT License: cannam@147: // cannam@147: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@147: // of this software and associated documentation files (the "Software"), to deal cannam@147: // in the Software without restriction, including without limitation the rights cannam@147: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@147: // copies of the Software, and to permit persons to whom the Software is cannam@147: // furnished to do so, subject to the following conditions: cannam@147: // cannam@147: // The above copyright notice and this permission notice shall be included in cannam@147: // all copies or substantial portions of the Software. cannam@147: // cannam@147: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@147: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@147: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@147: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@147: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@147: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@147: // THE SOFTWARE. cannam@147: cannam@147: #ifndef KJ_ASYNC_UNIX_H_ cannam@147: #define KJ_ASYNC_UNIX_H_ cannam@147: cannam@147: #if _WIN32 cannam@147: #error "This file is Unix-specific. On Windows, include async-win32.h instead." cannam@147: #endif cannam@147: cannam@147: #if defined(__GNUC__) && !KJ_HEADER_WARNINGS cannam@147: #pragma GCC system_header cannam@147: #endif cannam@147: cannam@147: #include "async.h" cannam@147: #include "time.h" cannam@147: #include "vector.h" cannam@147: #include "io.h" cannam@147: #include cannam@147: cannam@147: #if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL) cannam@147: // Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h. cannam@147: #define KJ_USE_EPOLL 1 cannam@147: #endif cannam@147: cannam@147: namespace kj { cannam@147: cannam@147: class UnixEventPort: public EventPort { cannam@147: // An EventPort implementation which can wait for events on file descriptors as well as signals. cannam@147: // This API only makes sense on Unix. cannam@147: // cannam@147: // The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue). cannam@147: // To also wait on signals without race conditions, the implementation may block signals until cannam@147: // just before `poll()` while using a signal handler which `siglongjmp()`s back to just before cannam@147: // the signal was unblocked, or it may use a nicer platform-specific API like signalfd. cannam@147: // cannam@147: // The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you cannam@147: // need to use SIGUSR1 for something else, you must offer a different signal by calling cannam@147: // setReservedSignal() at startup. cannam@147: // cannam@147: // WARNING: A UnixEventPort can only be used in the thread and process that created it. In cannam@147: // particular, note that after a fork(), a UnixEventPort created in the parent process will cannam@147: // not work correctly in the child, even if the parent ceases to use its copy. In particular cannam@147: // note that this means that server processes which daemonize themselves at startup must wait cannam@147: // until after daemonization to create a UnixEventPort. cannam@147: cannam@147: public: cannam@147: UnixEventPort(); cannam@147: ~UnixEventPort() noexcept(false); cannam@147: cannam@147: class FdObserver; cannam@147: // Class that watches an fd for readability or writability. See definition below. cannam@147: cannam@147: Promise onSignal(int signum); cannam@147: // When the given signal is delivered to this thread, return the corresponding siginfo_t. cannam@147: // The signal must have been captured using `captureSignal()`. cannam@147: // cannam@147: // If `onSignal()` has not been called, the signal will remain blocked in this thread. cannam@147: // Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the cannam@147: // next call to 'onSignal()' will receive it. Also, you can control which thread receives a cannam@147: // process-wide signal by only calling `onSignal()` on that thread's event loop. cannam@147: // cannam@147: // The result of waiting on the same signal twice at once is undefined. cannam@147: cannam@147: static void captureSignal(int signum); cannam@147: // Arranges for the given signal to be captured and handled via UnixEventPort, so that you may cannam@147: // then pass it to `onSignal()`. This method is static because it registers a signal handler cannam@147: // which applies process-wide. If any other threads exist in the process when `captureSignal()` cannam@147: // is called, you *must* set the signal mask in those threads to block this signal, otherwise cannam@147: // terrible things will happen if the signal happens to be delivered to those threads. If at cannam@147: // all possible, call `captureSignal()` *before* creating threads, so that threads you create in cannam@147: // the future will inherit the proper signal mask. cannam@147: // cannam@147: // To un-capture a signal, simply install a different signal handler and then un-block it from cannam@147: // the signal mask. cannam@147: cannam@147: static void setReservedSignal(int signum); cannam@147: // Sets the signal number which `UnixEventPort` reserves for internal use. If your application cannam@147: // needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before cannam@147: // constructing an `UnixEventPort`) to offer a different signal. cannam@147: cannam@147: Timer& getTimer() { return timerImpl; } cannam@147: cannam@147: // implements EventPort ------------------------------------------------------ cannam@147: bool wait() override; cannam@147: bool poll() override; cannam@147: void wake() const override; cannam@147: cannam@147: private: cannam@147: struct TimerSet; // Defined in source file to avoid STL include. cannam@147: class TimerPromiseAdapter; cannam@147: class SignalPromiseAdapter; cannam@147: cannam@147: TimerImpl timerImpl; cannam@147: cannam@147: SignalPromiseAdapter* signalHead = nullptr; cannam@147: SignalPromiseAdapter** signalTail = &signalHead; cannam@147: cannam@147: TimePoint readClock(); cannam@147: void gotSignal(const siginfo_t& siginfo); cannam@147: cannam@147: friend class TimerPromiseAdapter; cannam@147: cannam@147: #if KJ_USE_EPOLL cannam@147: AutoCloseFd epollFd; cannam@147: AutoCloseFd signalFd; cannam@147: AutoCloseFd eventFd; // Used for cross-thread wakeups. cannam@147: cannam@147: sigset_t signalFdSigset; cannam@147: // Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it cannam@147: // needs updating. cannam@147: cannam@147: bool doEpollWait(int timeout); cannam@147: cannam@147: #else cannam@147: class PollContext; cannam@147: cannam@147: FdObserver* observersHead = nullptr; cannam@147: FdObserver** observersTail = &observersHead; cannam@147: cannam@147: unsigned long long threadId; // actually pthread_t cannam@147: #endif cannam@147: }; cannam@147: cannam@147: class UnixEventPort::FdObserver { cannam@147: // Object which watches a file descriptor to determine when it is readable or writable. cannam@147: // cannam@147: // For listen sockets, "readable" means that there is a connection to accept(). For everything cannam@147: // else, it means that read() (or recv()) will return data. cannam@147: // cannam@147: // The presence of out-of-band data should NOT fire this event. However, the event may cannam@147: // occasionally fire spuriously (when there is actually no data to read), and one thing that can cannam@147: // cause such spurious events is the arrival of OOB data on certain platforms whose event cannam@147: // interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX). cannam@147: // cannam@147: // WARNING: The exact behavior of this class differs across systems, since event interfaces cannam@147: // vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified cannam@147: // behavior. If at all possible, use the higher-level AsyncInputStream interface instead. cannam@147: cannam@147: public: cannam@147: enum Flags { cannam@147: OBSERVE_READ = 1, cannam@147: OBSERVE_WRITE = 2, cannam@147: OBSERVE_URGENT = 4, cannam@147: OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE cannam@147: }; cannam@147: cannam@147: FdObserver(UnixEventPort& eventPort, int fd, uint flags); cannam@147: // Begin watching the given file descriptor for readability. Only one ReadObserver may exist cannam@147: // for a given file descriptor at a time. cannam@147: cannam@147: ~FdObserver() noexcept(false); cannam@147: cannam@147: KJ_DISALLOW_COPY(FdObserver); cannam@147: cannam@147: Promise whenBecomesReadable(); cannam@147: // Resolves the next time the file descriptor transitions from having no data to read to having cannam@147: // some data to read. cannam@147: // cannam@147: // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error cannam@147: // to call this method when there is already data in the read buffer which has been there since cannam@147: // prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is cannam@147: // unspecified whether the promise will ever resolve -- it depends on the underlying event cannam@147: // mechanism being used. cannam@147: // cannam@147: // In order to avoid this problem, make sure that you only call `whenBecomesReadable()` cannam@147: // only at times when you know the buffer is empty. You know this for sure when one of the cannam@147: // following happens: cannam@147: // * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode cannam@147: // enabled on the fd!) cannam@147: // * The file descriptor is a regular byte-oriented object (like a socket or pipe), cannam@147: // read() or recv() returns fewer than the number of bytes requested, and `atEndHint()` cannam@147: // returns false. This can only happen if the buffer is empty but EOF is not reached. (Note, cannam@147: // though, that for record-oriented file descriptors like Linux's inotify interface, this cannam@147: // rule does not hold, because it could simply be that the next record did not fit into the cannam@147: // space available.) cannam@147: // cannam@147: // It is an error to call `whenBecomesReadable()` again when the promise returned previously cannam@147: // has not yet resolved. If you do this, the previous promise may throw an exception. cannam@147: cannam@147: inline Maybe atEndHint() { return atEnd; } cannam@147: // Returns true if the event system has indicated that EOF has been received. There may still cannam@147: // be data in the read buffer, but once that is gone, there's nothing left. cannam@147: // cannam@147: // Returns false if the event system has indicated that EOF had NOT been received as of the cannam@147: // last turn of the event loop. cannam@147: // cannam@147: // Returns nullptr if the event system does not know whether EOF has been reached. In this cannam@147: // case, the only way to know for sure is to call read() or recv() and check if it returns cannam@147: // zero. cannam@147: // cannam@147: // This hint may be useful as an optimization to avoid an unnecessary system call. cannam@147: cannam@147: Promise whenBecomesWritable(); cannam@147: // Resolves the next time the file descriptor transitions from having no space available in the cannam@147: // write buffer to having some space available. cannam@147: // cannam@147: // KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error cannam@147: // to call this method when there is already space in the write buffer which has been there cannam@147: // since prior to the last turn of the event loop or prior to creation FdWatcher. In this case, cannam@147: // it is unspecified whether the promise will ever resolve -- it depends on the underlying cannam@147: // event mechanism being used. cannam@147: // cannam@147: // In order to avoid this problem, make sure that you only call `whenBecomesWritable()` cannam@147: // only at times when you know the buffer is full. You know this for sure when one of the cannam@147: // following happens: cannam@147: // * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode cannam@147: // enabled on the fd!) cannam@147: // * write() or send() succeeds but accepts fewer than the number of bytes provided. This can cannam@147: // only happen if the buffer is full. cannam@147: // cannam@147: // It is an error to call `whenBecomesWritable()` again when the promise returned previously cannam@147: // has not yet resolved. If you do this, the previous promise may throw an exception. cannam@147: cannam@147: Promise whenUrgentDataAvailable(); cannam@147: // Resolves the next time the file descriptor's read buffer contains "urgent" data. cannam@147: // cannam@147: // The conditions for availability of urgent data are specific to the file descriptor's cannam@147: // underlying implementation. cannam@147: // cannam@147: // It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously cannam@147: // has not yet resolved. If you do this, the previous promise may throw an exception. cannam@147: // cannam@147: // WARNING: This has some known weird behavior on macOS. See cannam@147: // https://github.com/sandstorm-io/capnproto/issues/374. cannam@147: cannam@147: private: cannam@147: UnixEventPort& eventPort; cannam@147: int fd; cannam@147: uint flags; cannam@147: cannam@147: kj::Maybe>> readFulfiller; cannam@147: kj::Maybe>> writeFulfiller; cannam@147: kj::Maybe>> urgentFulfiller; cannam@147: // Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to cannam@147: // null every time an event is fired. cannam@147: cannam@147: Maybe atEnd; cannam@147: cannam@147: void fire(short events); cannam@147: cannam@147: #if !KJ_USE_EPOLL cannam@147: FdObserver* next; cannam@147: FdObserver** prev; cannam@147: // Linked list of observers which currently have a non-null readFulfiller or writeFulfiller. cannam@147: // If `prev` is null then the observer is not currently in the list. cannam@147: cannam@147: short getEventMask(); cannam@147: #endif cannam@147: cannam@147: friend class UnixEventPort; cannam@147: }; cannam@147: cannam@147: } // namespace kj cannam@147: cannam@147: #endif // KJ_ASYNC_UNIX_H_