annotate win32-mingw/include/kj/async-io.h @ 142:75bf92aa2d1f

Fixes and updates for 32-bit Windows build
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 09 Jan 2017 11:53:06 +0000
parents 38d1c0e7850b
children eccd51b72864
rev   line source
cannam@135 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@135 2 // Licensed under the MIT License:
cannam@135 3 //
cannam@135 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@135 5 // of this software and associated documentation files (the "Software"), to deal
cannam@135 6 // in the Software without restriction, including without limitation the rights
cannam@135 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@135 8 // copies of the Software, and to permit persons to whom the Software is
cannam@135 9 // furnished to do so, subject to the following conditions:
cannam@135 10 //
cannam@135 11 // The above copyright notice and this permission notice shall be included in
cannam@135 12 // all copies or substantial portions of the Software.
cannam@135 13 //
cannam@135 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@135 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@135 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@135 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@135 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@135 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@135 20 // THE SOFTWARE.
cannam@135 21
cannam@135 22 #ifndef KJ_ASYNC_IO_H_
cannam@135 23 #define KJ_ASYNC_IO_H_
cannam@135 24
cannam@135 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
cannam@135 26 #pragma GCC system_header
cannam@135 27 #endif
cannam@135 28
cannam@135 29 #include "async.h"
cannam@135 30 #include "function.h"
cannam@135 31 #include "thread.h"
cannam@135 32 #include "time.h"
cannam@135 33
cannam@135 34 struct sockaddr;
cannam@135 35
cannam@135 36 namespace kj {
cannam@135 37
cannam@135 38 class UnixEventPort;
cannam@135 39 class NetworkAddress;
cannam@135 40
cannam@135 41 // =======================================================================================
cannam@135 42 // Streaming I/O
cannam@135 43
cannam@135 44 class AsyncInputStream {
cannam@135 45 // Asynchronous equivalent of InputStream (from io.h).
cannam@135 46
cannam@135 47 public:
cannam@135 48 virtual Promise<size_t> read(void* buffer, size_t minBytes, size_t maxBytes) = 0;
cannam@135 49 virtual Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
cannam@135 50
cannam@135 51 Promise<void> read(void* buffer, size_t bytes);
cannam@135 52 };
cannam@135 53
cannam@135 54 class AsyncOutputStream {
cannam@135 55 // Asynchronous equivalent of OutputStream (from io.h).
cannam@135 56
cannam@135 57 public:
cannam@135 58 virtual Promise<void> write(const void* buffer, size_t size) = 0;
cannam@135 59 virtual Promise<void> write(ArrayPtr<const ArrayPtr<const byte>> pieces) = 0;
cannam@135 60 };
cannam@135 61
cannam@135 62 class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream {
cannam@135 63 // A combination input and output stream.
cannam@135 64
cannam@135 65 public:
cannam@135 66 virtual void shutdownWrite() = 0;
cannam@135 67 // Cleanly shut down just the write end of the stream, while keeping the read end open.
cannam@135 68
cannam@135 69 virtual void abortRead() {}
cannam@135 70 // Similar to shutdownWrite, but this will shut down the read end of the stream, and should only
cannam@135 71 // be called when an error has occurred.
cannam@135 72
cannam@135 73 virtual void getsockopt(int level, int option, void* value, uint* length);
cannam@135 74 virtual void setsockopt(int level, int option, const void* value, uint length);
cannam@135 75 // Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception
cannam@135 76 // if the stream is not a socket or the option is not appropriate for the socket type. The
cannam@135 77 // default implementations always throw "unimplemented".
cannam@135 78
cannam@135 79 virtual void getsockname(struct sockaddr* addr, uint* length);
cannam@135 80 virtual void getpeername(struct sockaddr* addr, uint* length);
cannam@135 81 // Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented"
cannam@135 82 // exception if the stream is not a socket. The default implementations always throw
cannam@135 83 // "unimplemented".
cannam@135 84 //
cannam@135 85 // Note that we don't provide methods that return NetworkAddress because it usually wouldn't
cannam@135 86 // be useful. You can't connect() to or listen() on these addresses, obviously, because they are
cannam@135 87 // ephemeral addresses for a single connection.
cannam@135 88 };
cannam@135 89
cannam@135 90 struct OneWayPipe {
cannam@135 91 // A data pipe with an input end and an output end. (Typically backed by pipe() system call.)
cannam@135 92
cannam@135 93 Own<AsyncInputStream> in;
cannam@135 94 Own<AsyncOutputStream> out;
cannam@135 95 };
cannam@135 96
cannam@135 97 struct TwoWayPipe {
cannam@135 98 // A data pipe that supports sending in both directions. Each end's output sends data to the
cannam@135 99 // other end's input. (Typically backed by socketpair() system call.)
cannam@135 100
cannam@135 101 Own<AsyncIoStream> ends[2];
cannam@135 102 };
cannam@135 103
cannam@135 104 class ConnectionReceiver {
cannam@135 105 // Represents a server socket listening on a port.
cannam@135 106
cannam@135 107 public:
cannam@135 108 virtual Promise<Own<AsyncIoStream>> accept() = 0;
cannam@135 109 // Accept the next incoming connection.
cannam@135 110
cannam@135 111 virtual uint getPort() = 0;
cannam@135 112 // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
cannam@135 113 // specify a port when constructing the NetworkAddress -- one will have been assigned
cannam@135 114 // automatically.
cannam@135 115
cannam@135 116 virtual void getsockopt(int level, int option, void* value, uint* length);
cannam@135 117 virtual void setsockopt(int level, int option, const void* value, uint length);
cannam@135 118 // Same as the methods of AsyncIoStream.
cannam@135 119 };
cannam@135 120
cannam@135 121 // =======================================================================================
cannam@135 122 // Datagram I/O
cannam@135 123
cannam@135 124 class AncillaryMessage {
cannam@135 125 // Represents an ancillary message (aka control message) received using the recvmsg() system
cannam@135 126 // call (or equivalent). Most apps will not use this.
cannam@135 127
cannam@135 128 public:
cannam@135 129 inline AncillaryMessage(int level, int type, ArrayPtr<const byte> data);
cannam@135 130 AncillaryMessage() = default;
cannam@135 131
cannam@135 132 inline int getLevel() const;
cannam@135 133 // Originating protocol / socket level.
cannam@135 134
cannam@135 135 inline int getType() const;
cannam@135 136 // Protocol-specific message type.
cannam@135 137
cannam@135 138 template <typename T>
cannam@135 139 inline Maybe<const T&> as();
cannam@135 140 // Interpret the ancillary message as the given struct type. Most ancillary messages are some
cannam@135 141 // sort of struct, so this is a convenient way to access it. Returns nullptr if the message
cannam@135 142 // is smaller than the struct -- this can happen if the message was truncated due to
cannam@135 143 // insufficient ancillary buffer space.
cannam@135 144
cannam@135 145 template <typename T>
cannam@135 146 inline ArrayPtr<const T> asArray();
cannam@135 147 // Interpret the ancillary message as an array of items. If the message size does not evenly
cannam@135 148 // divide into elements of type T, the remainder is discarded -- this can happen if the message
cannam@135 149 // was truncated due to insufficient ancillary buffer space.
cannam@135 150
cannam@135 151 private:
cannam@135 152 int level;
cannam@135 153 int type;
cannam@135 154 ArrayPtr<const byte> data;
cannam@135 155 // Message data. In most cases you should use `as()` or `asArray()`.
cannam@135 156 };
cannam@135 157
cannam@135 158 class DatagramReceiver {
cannam@135 159 // Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's
cannam@135 160 // capacity in advance; if a received packet is larger than the capacity, it will be truncated.
cannam@135 161
cannam@135 162 public:
cannam@135 163 virtual Promise<void> receive() = 0;
cannam@135 164 // Receive a new message, overwriting this object's content.
cannam@135 165 //
cannam@135 166 // receive() may reuse the same buffers for content and ancillary data with each call.
cannam@135 167
cannam@135 168 template <typename T>
cannam@135 169 struct MaybeTruncated {
cannam@135 170 T value;
cannam@135 171
cannam@135 172 bool isTruncated;
cannam@135 173 // True if the Receiver's capacity was insufficient to receive the value and therefore the
cannam@135 174 // value is truncated.
cannam@135 175 };
cannam@135 176
cannam@135 177 virtual MaybeTruncated<ArrayPtr<const byte>> getContent() = 0;
cannam@135 178 // Get the content of the datagram.
cannam@135 179
cannam@135 180 virtual MaybeTruncated<ArrayPtr<const AncillaryMessage>> getAncillary() = 0;
cannam@135 181 // Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr
cannam@135 182 // struct. Most apps don't need this.
cannam@135 183 //
cannam@135 184 // If the returned value is truncated, then the last message in the array may itself be
cannam@135 185 // truncated, meaning its as<T>() method will return nullptr or its asArray<T>() method will
cannam@135 186 // return fewer elements than expected. Truncation can also mean that additional messages were
cannam@135 187 // available but discarded.
cannam@135 188
cannam@135 189 virtual NetworkAddress& getSource() = 0;
cannam@135 190 // Get the datagram sender's address.
cannam@135 191
cannam@135 192 struct Capacity {
cannam@135 193 size_t content = 8192;
cannam@135 194 // How much space to allocate for the datagram content. If a datagram is received that is
cannam@135 195 // larger than this, it will be truncated, with no way to recover the tail.
cannam@135 196
cannam@135 197 size_t ancillary = 0;
cannam@135 198 // How much space to allocate for ancillary messages. As with content, if the ancillary data
cannam@135 199 // is larger than this, it will be truncated.
cannam@135 200 };
cannam@135 201 };
cannam@135 202
cannam@135 203 class DatagramPort {
cannam@135 204 public:
cannam@135 205 virtual Promise<size_t> send(const void* buffer, size_t size, NetworkAddress& destination) = 0;
cannam@135 206 virtual Promise<size_t> send(ArrayPtr<const ArrayPtr<const byte>> pieces,
cannam@135 207 NetworkAddress& destination) = 0;
cannam@135 208
cannam@135 209 virtual Own<DatagramReceiver> makeReceiver(
cannam@135 210 DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0;
cannam@135 211 // Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much
cannam@135 212 // space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`.
cannam@135 213
cannam@135 214 virtual uint getPort() = 0;
cannam@135 215 // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
cannam@135 216 // specify a port when constructing the NetworkAddress -- one will have been assigned
cannam@135 217 // automatically.
cannam@135 218
cannam@135 219 virtual void getsockopt(int level, int option, void* value, uint* length);
cannam@135 220 virtual void setsockopt(int level, int option, const void* value, uint length);
cannam@135 221 // Same as the methods of AsyncIoStream.
cannam@135 222 };
cannam@135 223
cannam@135 224 // =======================================================================================
cannam@135 225 // Networks
cannam@135 226
cannam@135 227 class NetworkAddress {
cannam@135 228 // Represents a remote address to which the application can connect.
cannam@135 229
cannam@135 230 public:
cannam@135 231 virtual Promise<Own<AsyncIoStream>> connect() = 0;
cannam@135 232 // Make a new connection to this address.
cannam@135 233 //
cannam@135 234 // The address must not be a wildcard ("*"). If it is an IP address, it must have a port number.
cannam@135 235
cannam@135 236 virtual Own<ConnectionReceiver> listen() = 0;
cannam@135 237 // Listen for incoming connections on this address.
cannam@135 238 //
cannam@135 239 // The address must be local.
cannam@135 240
cannam@135 241 virtual Own<DatagramPort> bindDatagramPort();
cannam@135 242 // Open this address as a datagram (e.g. UDP) port.
cannam@135 243 //
cannam@135 244 // The address must be local.
cannam@135 245
cannam@135 246 virtual Own<NetworkAddress> clone() = 0;
cannam@135 247 // Returns an equivalent copy of this NetworkAddress.
cannam@135 248
cannam@135 249 virtual String toString() = 0;
cannam@135 250 // Produce a human-readable string which hopefully can be passed to Network::parseAddress()
cannam@135 251 // to reproduce this address, although whether or not that works of course depends on the Network
cannam@135 252 // implementation. This should be called only to display the address to human users, who will
cannam@135 253 // hopefully know what they are able to do with it.
cannam@135 254 };
cannam@135 255
cannam@135 256 class Network {
cannam@135 257 // Factory for NetworkAddress instances, representing the network services offered by the
cannam@135 258 // operating system.
cannam@135 259 //
cannam@135 260 // This interface typically represents broad authority, and well-designed code should limit its
cannam@135 261 // use to high-level startup code and user interaction. Low-level APIs should accept
cannam@135 262 // NetworkAddress instances directly and work from there, if at all possible.
cannam@135 263
cannam@135 264 public:
cannam@135 265 virtual Promise<Own<NetworkAddress>> parseAddress(StringPtr addr, uint portHint = 0) = 0;
cannam@135 266 // Construct a network address from a user-provided string. The format of the address
cannam@135 267 // strings is not specified at the API level, and application code should make no assumptions
cannam@135 268 // about them. These strings should always be provided by humans, and said humans will know
cannam@135 269 // what format to use in their particular context.
cannam@135 270 //
cannam@135 271 // `portHint`, if provided, specifies the "standard" IP port number for the application-level
cannam@135 272 // service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a
cannam@135 273 // port number, this port will be used. If `addr` lacks a port number *and* `portHint` is
cannam@135 274 // omitted, then the returned address will only support listen() and bindDatagramPort()
cannam@135 275 // (not connect()), and an unused port will be chosen each time one of those methods is called.
cannam@135 276
cannam@135 277 virtual Own<NetworkAddress> getSockaddr(const void* sockaddr, uint len) = 0;
cannam@135 278 // Construct a network address from a legacy struct sockaddr.
cannam@135 279 };
cannam@135 280
cannam@135 281 // =======================================================================================
cannam@135 282 // I/O Provider
cannam@135 283
cannam@135 284 class AsyncIoProvider {
cannam@135 285 // Class which constructs asynchronous wrappers around the operating system's I/O facilities.
cannam@135 286 //
cannam@135 287 // Generally, the implementation of this interface must integrate closely with a particular
cannam@135 288 // `EventLoop` implementation. Typically, the EventLoop implementation itself will provide
cannam@135 289 // an AsyncIoProvider.
cannam@135 290
cannam@135 291 public:
cannam@135 292 virtual OneWayPipe newOneWayPipe() = 0;
cannam@135 293 // Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with
cannam@135 294 // the pipe(2) system call).
cannam@135 295
cannam@135 296 virtual TwoWayPipe newTwoWayPipe() = 0;
cannam@135 297 // Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with
cannam@135 298 // socketpair(2) system call). Data written to one end can be read from the other.
cannam@135 299
cannam@135 300 virtual Network& getNetwork() = 0;
cannam@135 301 // Creates a new `Network` instance representing the networks exposed by the operating system.
cannam@135 302 //
cannam@135 303 // DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If
cannam@135 304 // you call this from low-level code, then you are preventing higher-level code from injecting an
cannam@135 305 // alternative implementation. Instead, if your code needs to use network functionality, it
cannam@135 306 // should ask for a `Network` as a constructor or method parameter, so that higher-level code can
cannam@135 307 // chose what implementation to use. The system network is essentially a singleton. See:
cannam@135 308 // http://www.object-oriented-security.org/lets-argue/singletons
cannam@135 309 //
cannam@135 310 // Code that uses the system network should not make any assumptions about what kinds of
cannam@135 311 // addresses it will parse, as this could differ across platforms. String addresses should come
cannam@135 312 // strictly from the user, who will know how to write them correctly for their system.
cannam@135 313 //
cannam@135 314 // With that said, KJ currently supports the following string address formats:
cannam@135 315 // - IPv4: "1.2.3.4", "1.2.3.4:80"
cannam@135 316 // - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80"
cannam@135 317 // - Local IP wildcard (covers both v4 and v6): "*", "*:80"
cannam@135 318 // - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http"
cannam@135 319 // - Unix domain: "unix:/path/to/socket"
cannam@135 320
cannam@135 321 struct PipeThread {
cannam@135 322 // A combination of a thread and a two-way pipe that communicates with that thread.
cannam@135 323 //
cannam@135 324 // The fields are intentionally ordered so that the pipe will be destroyed (and therefore
cannam@135 325 // disconnected) before the thread is destroyed (and therefore joined). Thus if the thread
cannam@135 326 // arranges to exit when it detects disconnect, destruction should be clean.
cannam@135 327
cannam@135 328 Own<Thread> thread;
cannam@135 329 Own<AsyncIoStream> pipe;
cannam@135 330 };
cannam@135 331
cannam@135 332 virtual PipeThread newPipeThread(
cannam@135 333 Function<void(AsyncIoProvider&, AsyncIoStream&, WaitScope&)> startFunc) = 0;
cannam@135 334 // Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate
cannam@135 335 // with it. One end of the pipe is passed to the thread's start function and the other end of
cannam@135 336 // the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will
cannam@135 337 // already have an active `EventLoop` when `startFunc` is called.
cannam@135 338 //
cannam@135 339 // TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too
cannam@135 340 // much at once but I'm not sure how to cleanly break it down.
cannam@135 341
cannam@135 342 virtual Timer& getTimer() = 0;
cannam@135 343 // Returns a `Timer` based on real time. Time does not pass while event handlers are running --
cannam@135 344 // it only updates when the event loop polls for system events. This means that calling `now()`
cannam@135 345 // on this timer does not require a system call.
cannam@135 346 //
cannam@135 347 // This timer is not affected by changes to the system date. It is unspecified whether the timer
cannam@135 348 // continues to count while the system is suspended.
cannam@135 349 };
cannam@135 350
cannam@135 351 class LowLevelAsyncIoProvider {
cannam@135 352 // Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on
cannam@135 353 // different operating systems. You should prefer to use `AsyncIoProvider` over this interface
cannam@135 354 // whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection.
cannam@135 355 //
cannam@135 356 // On Unix, this interface can be used to import native file descriptors into the async framework.
cannam@135 357 // Different implementations of this interface might work on top of different event handling
cannam@135 358 // primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library.
cannam@135 359 //
cannam@135 360 // On Windows, this interface can be used to import native HANDLEs into the async framework.
cannam@135 361 // Different implementations of this interface might work on top of different event handling
cannam@135 362 // primitives, such as I/O completion ports vs. completion routines.
cannam@135 363 //
cannam@135 364 // TODO(port): Actually implement Windows support.
cannam@135 365
cannam@135 366 public:
cannam@135 367 // ---------------------------------------------------------------------------
cannam@135 368 // Unix-specific stuff
cannam@135 369
cannam@135 370 enum Flags {
cannam@135 371 // Flags controlling how to wrap a file descriptor.
cannam@135 372
cannam@135 373 TAKE_OWNERSHIP = 1 << 0,
cannam@135 374 // The returned object should own the file descriptor, automatically closing it when destroyed.
cannam@135 375 // The close-on-exec flag will be set on the descriptor if it is not already.
cannam@135 376 //
cannam@135 377 // If this flag is not used, then the file descriptor is not automatically closed and the
cannam@135 378 // close-on-exec flag is not modified.
cannam@135 379
cannam@135 380 ALREADY_CLOEXEC = 1 << 1,
cannam@135 381 // Indicates that the close-on-exec flag is known already to be set, so need not be set again.
cannam@135 382 // Only relevant when combined with TAKE_OWNERSHIP.
cannam@135 383 //
cannam@135 384 // On Linux, all system calls which yield new file descriptors have flags or variants which
cannam@135 385 // set the close-on-exec flag immediately. Unfortunately, other OS's do not.
cannam@135 386
cannam@135 387 ALREADY_NONBLOCK = 1 << 2
cannam@135 388 // Indicates that the file descriptor is known already to be in non-blocking mode, so the flag
cannam@135 389 // need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode
cannam@135 390 // automatically.
cannam@135 391 //
cannam@135 392 // On Linux, all system calls which yield new file descriptors have flags or variants which
cannam@135 393 // enable non-blocking mode immediately. Unfortunately, other OS's do not.
cannam@135 394 };
cannam@135 395
cannam@135 396 virtual Own<AsyncInputStream> wrapInputFd(int fd, uint flags = 0) = 0;
cannam@135 397 // Create an AsyncInputStream wrapping a file descriptor.
cannam@135 398 //
cannam@135 399 // `flags` is a bitwise-OR of the values of the `Flags` enum.
cannam@135 400
cannam@135 401 virtual Own<AsyncOutputStream> wrapOutputFd(int fd, uint flags = 0) = 0;
cannam@135 402 // Create an AsyncOutputStream wrapping a file descriptor.
cannam@135 403 //
cannam@135 404 // `flags` is a bitwise-OR of the values of the `Flags` enum.
cannam@135 405
cannam@135 406 virtual Own<AsyncIoStream> wrapSocketFd(int fd, uint flags = 0) = 0;
cannam@135 407 // Create an AsyncIoStream wrapping a socket file descriptor.
cannam@135 408 //
cannam@135 409 // `flags` is a bitwise-OR of the values of the `Flags` enum.
cannam@135 410
cannam@135 411 virtual Promise<Own<AsyncIoStream>> wrapConnectingSocketFd(int fd, uint flags = 0) = 0;
cannam@135 412 // Create an AsyncIoStream wrapping a socket that is in the process of connecting. The returned
cannam@135 413 // promise should not resolve until connection has completed -- traditionally indicated by the
cannam@135 414 // descriptor becoming writable.
cannam@135 415 //
cannam@135 416 // `flags` is a bitwise-OR of the values of the `Flags` enum.
cannam@135 417
cannam@135 418 virtual Own<ConnectionReceiver> wrapListenSocketFd(int fd, uint flags = 0) = 0;
cannam@135 419 // Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already
cannam@135 420 // have had `bind()` and `listen()` called on it, so it's ready for `accept()`.
cannam@135 421 //
cannam@135 422 // `flags` is a bitwise-OR of the values of the `Flags` enum.
cannam@135 423
cannam@135 424 virtual Own<DatagramPort> wrapDatagramSocketFd(int fd, uint flags = 0);
cannam@135 425
cannam@135 426 virtual Timer& getTimer() = 0;
cannam@135 427 // Returns a `Timer` based on real time. Time does not pass while event handlers are running --
cannam@135 428 // it only updates when the event loop polls for system events. This means that calling `now()`
cannam@135 429 // on this timer does not require a system call.
cannam@135 430 //
cannam@135 431 // This timer is not affected by changes to the system date. It is unspecified whether the timer
cannam@135 432 // continues to count while the system is suspended.
cannam@135 433 };
cannam@135 434
cannam@135 435 Own<AsyncIoProvider> newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel);
cannam@135 436 // Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`.
cannam@135 437
cannam@135 438 struct AsyncIoContext {
cannam@135 439 Own<LowLevelAsyncIoProvider> lowLevelProvider;
cannam@135 440 Own<AsyncIoProvider> provider;
cannam@135 441 WaitScope& waitScope;
cannam@135 442
cannam@135 443 UnixEventPort& unixEventPort;
cannam@135 444 // TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This
cannam@135 445 // field will go away at some point when we have a chance to improve these interfaces.
cannam@135 446 };
cannam@135 447
cannam@135 448 AsyncIoContext setupAsyncIo();
cannam@135 449 // Convenience method which sets up the current thread with everything it needs to do async I/O.
cannam@135 450 // The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for
cannam@135 451 // doing I/O on the host system, so everything is ready for the thread to start making async calls
cannam@135 452 // and waiting on promises.
cannam@135 453 //
cannam@135 454 // You would typically call this in your main() loop or in the start function of a thread.
cannam@135 455 // Example:
cannam@135 456 //
cannam@135 457 // int main() {
cannam@135 458 // auto ioContext = kj::setupAsyncIo();
cannam@135 459 //
cannam@135 460 // // Now we can call an async function.
cannam@135 461 // Promise<String> textPromise = getHttp(*ioContext.provider, "http://example.com");
cannam@135 462 //
cannam@135 463 // // And we can wait for the promise to complete. Note that you can only use `wait()`
cannam@135 464 // // from the top level, not from inside a promise callback.
cannam@135 465 // String text = textPromise.wait(ioContext.waitScope);
cannam@135 466 // print(text);
cannam@135 467 // return 0;
cannam@135 468 // }
cannam@135 469 //
cannam@135 470 // WARNING: An AsyncIoContext can only be used in the thread and process that created it. In
cannam@135 471 // particular, note that after a fork(), an AsyncIoContext created in the parent process will
cannam@135 472 // not work correctly in the child, even if the parent ceases to use its copy. In particular
cannam@135 473 // note that this means that server processes which daemonize themselves at startup must wait
cannam@135 474 // until after daemonization to create an AsyncIoContext.
cannam@135 475
cannam@135 476 // =======================================================================================
cannam@135 477 // inline implementation details
cannam@135 478
cannam@135 479 inline AncillaryMessage::AncillaryMessage(
cannam@135 480 int level, int type, ArrayPtr<const byte> data)
cannam@135 481 : level(level), type(type), data(data) {}
cannam@135 482
cannam@135 483 inline int AncillaryMessage::getLevel() const { return level; }
cannam@135 484 inline int AncillaryMessage::getType() const { return type; }
cannam@135 485
cannam@135 486 template <typename T>
cannam@135 487 inline Maybe<const T&> AncillaryMessage::as() {
cannam@135 488 if (data.size() >= sizeof(T)) {
cannam@135 489 return *reinterpret_cast<const T*>(data.begin());
cannam@135 490 } else {
cannam@135 491 return nullptr;
cannam@135 492 }
cannam@135 493 }
cannam@135 494
cannam@135 495 template <typename T>
cannam@135 496 inline ArrayPtr<const T> AncillaryMessage::asArray() {
cannam@135 497 return arrayPtr(reinterpret_cast<const T*>(data.begin()), data.size() / sizeof(T));
cannam@135 498 }
cannam@135 499
cannam@135 500 } // namespace kj
cannam@135 501
cannam@135 502 #endif // KJ_ASYNC_IO_H_