diff osx/include/kj/async-unix.h @ 147:45360b968bf4

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