| 31 | namespace internal { |
| 32 | |
| 33 | Future<size_t> read(int_fd fd, void* data, size_t size) |
| 34 | { |
| 35 | // TODO(benh): Let the system calls do what ever they're supposed to |
| 36 | // rather than return 0 here? |
| 37 | if (size == 0) { |
| 38 | return 0; |
| 39 | } |
| 40 | |
| 41 | return loop( |
| 42 | None(), |
| 43 | [=]() -> Future<Option<size_t>> { |
| 44 | // Because the file descriptor is non-blocking, we call |
| 45 | // read()/recv() immediately. If no data is available than |
| 46 | // we'll call `poll` and block. We also observed that for some |
| 47 | // combination of libev and Linux kernel versions, the poll |
| 48 | // would block for non-deterministically long periods of |
| 49 | // time. This may be fixed in a newer version of libev (we use |
| 50 | // 3.8 at the time of writing this comment). |
| 51 | ssize_t length = os::read(fd, data, size); |
| 52 | if (length < 0) { |
| 53 | #ifdef __WINDOWS__ |
| 54 | WindowsSocketError error; |
| 55 | #else |
| 56 | ErrnoError error; |
| 57 | #endif // __WINDOWS__ |
| 58 | |
| 59 | if (!net::is_restartable_error(error.code) && |
| 60 | !net::is_retryable_error(error.code)) { |
| 61 | return Failure(error.message); |
| 62 | } |
| 63 | |
| 64 | return None(); |
| 65 | } |
| 66 | |
| 67 | return length; |
| 68 | }, |
| 69 | [=](const Option<size_t>& length) -> Future<ControlFlow<size_t>> { |
| 70 | // Restart/retry if we don't yet have a result. |
| 71 | if (length.isNone()) { |
| 72 | return io::poll(fd, io::READ) |
| 73 | .then([](short event) -> ControlFlow<size_t> { |
| 74 | CHECK_EQ(io::READ, event); |
| 75 | return Continue(); |
| 76 | }); |
| 77 | } |
| 78 | return Break(length.get()); |
| 79 | }); |
| 80 | } |
| 81 | |
| 82 | |
| 83 | Future<size_t> write(int_fd fd, const void* data, size_t size) |