async-unix-test.c++ 17.2 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// 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:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// 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.
21

22 23
#if !_WIN32

24 25 26
#include "async-unix.h"
#include "thread.h"
#include "debug.h"
27
#include "io.h"
28 29 30
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
31
#include <sys/socket.h>
32
#include <sys/stat.h>
33
#include <netinet/in.h>
34
#include <kj/compat/gtest.h>
35
#include <pthread.h>
36
#include <algorithm>
37 38

namespace kj {
39
namespace {
40 41 42

inline void delay() { usleep(10000); }

43 44 45 46 47 48 49
// On OSX, si_code seems to be zero when SI_USER is expected.
#if __linux__ || __CYGWIN__
#define EXPECT_SI_CODE EXPECT_EQ
#else
#define EXPECT_SI_CODE(a,b)
#endif

50 51 52 53 54
void captureSignals() {
  static bool captured = false;
  if (!captured) {
    captured = true;

55 56 57 58
    // We use SIGIO and SIGURG as our test signals because they're two signals that we can be
    // reasonably confident won't otherwise be delivered to any KJ or Cap'n Proto test.  We can't
    // use SIGUSR1 because it is reserved by UnixEventPort and SIGUSR2 is used by Valgrind on OSX.
    UnixEventPort::captureSignal(SIGURG);
59
    UnixEventPort::captureSignal(SIGIO);
60
  }
61
}
62

63 64
TEST(AsyncUnixTest, Signals) {
  captureSignals();
65 66
  UnixEventPort port;
  EventLoop loop(port);
67
  WaitScope waitScope(loop);
68

69
  kill(getpid(), SIGURG);
70

71 72
  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
73
  EXPECT_SI_CODE(SI_USER, info.si_code);
74 75
}

76
#if defined(SIGRTMIN) && !__BIONIC__ && !(__linux__ && __mips__)
77
TEST(AsyncUnixTest, SignalWithValue) {
78 79
  // This tests that if we use sigqueue() to attach a value to the signal, that value is received
  // correctly.  Note that this only works on platforms that support real-time signals -- even
80
  // though the signal we're sending is SIGURG, the sigqueue() system call is introduced by RT
81
  // signals.  Hence this test won't run on e.g. Mac OSX.
Kenton Varda's avatar
Kenton Varda committed
82 83
  //
  // Also, Android's bionic does not appear to support sigqueue() even though the kernel does.
84 85 86 87
  //
  // Also, this test fails on Linux on mipsel. si_value comes back as zero. No one with a mips
  // machine wants to debug the problem but they demand a patch fixing it, so we disable the test.
  // Sad. https://github.com/sandstorm-io/capnproto/issues/204
88

89
  captureSignals();
90 91
  UnixEventPort port;
  EventLoop loop(port);
92
  WaitScope waitScope(loop);
93

94
  union sigval value;
95
  memset(&value, 0, sizeof(value));
96
  value.sival_int = 123;
97
  sigqueue(getpid(), SIGURG, value);
98

99 100
  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
101
  EXPECT_SI_CODE(SI_QUEUE, info.si_code);
102 103
  EXPECT_EQ(123, info.si_value.sival_int);
}
104

105
TEST(AsyncUnixTest, SignalWithPointerValue) {
106 107 108 109
  // This tests that if we use sigqueue() to attach a value to the signal, that value is received
  // correctly.  Note that this only works on platforms that support real-time signals -- even
  // though the signal we're sending is SIGURG, the sigqueue() system call is introduced by RT
  // signals.  Hence this test won't run on e.g. Mac OSX.
Kenton Varda's avatar
Kenton Varda committed
110 111
  //
  // Also, Android's bionic does not appear to support sigqueue() even though the kernel does.
112 113 114 115
  //
  // Also, this test fails on Linux on mipsel. si_value comes back as zero. No one with a mips
  // machine wants to debug the problem but they demand a patch fixing it, so we disable the test.
  // Sad. https://github.com/sandstorm-io/capnproto/issues/204
116

117
  captureSignals();
118 119 120 121 122 123 124 125 126 127 128 129 130 131
  UnixEventPort port;
  EventLoop loop(port);
  WaitScope waitScope(loop);

  union sigval value;
  memset(&value, 0, sizeof(value));
  value.sival_ptr = &port;
  sigqueue(getpid(), SIGURG, value);

  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
  EXPECT_SI_CODE(SI_QUEUE, info.si_code);
  EXPECT_EQ(&port, info.si_value.sival_ptr);
}
132
#endif
133

134 135
TEST(AsyncUnixTest, SignalsMultiListen) {
  captureSignals();
136 137
  UnixEventPort port;
  EventLoop loop(port);
138
  WaitScope waitScope(loop);
139

140
  port.onSignal(SIGIO).then([](siginfo_t&&) {
141
    KJ_FAIL_EXPECT("Received wrong signal.");
142
  }).detach([](kj::Exception&& exception) {
143
    KJ_FAIL_EXPECT(exception);
144
  });
145

146
  kill(getpid(), SIGURG);
147

148 149
  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
150
  EXPECT_SI_CODE(SI_USER, info.si_code);
151 152
}

153 154 155 156 157
#if !__CYGWIN32__
// Cygwin32 (but not Cygwin64) appears not to deliver SIGURG in the following test (but it does
// deliver SIGIO, if you reverse the order of the waits).  Since this doesn't occur on any other
// platform I'm assuming it's a Cygwin bug.

158 159
TEST(AsyncUnixTest, SignalsMultiReceive) {
  captureSignals();
160 161
  UnixEventPort port;
  EventLoop loop(port);
162
  WaitScope waitScope(loop);
163

164
  kill(getpid(), SIGURG);
165 166
  kill(getpid(), SIGIO);

167 168
  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
169 170
  EXPECT_SI_CODE(SI_USER, info.si_code);

171
  info = port.onSignal(SIGIO).wait(waitScope);
172 173 174 175
  EXPECT_EQ(SIGIO, info.si_signo);
  EXPECT_SI_CODE(SI_USER, info.si_code);
}

176 177
#endif  // !__CYGWIN32__

178 179
TEST(AsyncUnixTest, SignalsAsync) {
  captureSignals();
180 181
  UnixEventPort port;
  EventLoop loop(port);
182
  WaitScope waitScope(loop);
183 184 185

  // Arrange for a signal to be sent from another thread.
  pthread_t mainThread = pthread_self();
186
  Thread thread([&]() {
187
    delay();
188
    pthread_kill(mainThread, SIGURG);
189
  });
190

191 192
  siginfo_t info = port.onSignal(SIGURG).wait(waitScope);
  EXPECT_EQ(SIGURG, info.si_signo);
193
#if __linux__
194
  EXPECT_SI_CODE(SI_TKILL, info.si_code);
195
#endif
196 197
}

198 199 200 201 202
#if !__CYGWIN32__
// Cygwin32 (but not Cygwin64) appears not to deliver SIGURG in the following test (but it does
// deliver SIGIO, if you reverse the order of the waits).  Since this doesn't occur on any other
// platform I'm assuming it's a Cygwin bug.

203
TEST(AsyncUnixTest, SignalsNoWait) {
204 205
  // Verify that UnixEventPort::poll() correctly receives pending signals.

206
  captureSignals();
207 208
  UnixEventPort port;
  EventLoop loop(port);
209
  WaitScope waitScope(loop);
210

211
  bool receivedSigurg = false;
212
  bool receivedSigio = false;
213 214 215
  port.onSignal(SIGURG).then([&](siginfo_t&& info) {
    receivedSigurg = true;
    EXPECT_EQ(SIGURG, info.si_signo);
216
    EXPECT_SI_CODE(SI_USER, info.si_code);
217
  }).detach([](Exception&& e) { KJ_FAIL_EXPECT(e); });
218 219 220 221
  port.onSignal(SIGIO).then([&](siginfo_t&& info) {
    receivedSigio = true;
    EXPECT_EQ(SIGIO, info.si_signo);
    EXPECT_SI_CODE(SI_USER, info.si_code);
222
  }).detach([](Exception&& e) { KJ_FAIL_EXPECT(e); });
223

224
  kill(getpid(), SIGURG);
225 226
  kill(getpid(), SIGIO);

227
  EXPECT_FALSE(receivedSigurg);
228 229 230 231
  EXPECT_FALSE(receivedSigio);

  loop.run();

232
  EXPECT_FALSE(receivedSigurg);
233 234 235 236
  EXPECT_FALSE(receivedSigio);

  port.poll();

237
  EXPECT_FALSE(receivedSigurg);
238 239 240 241
  EXPECT_FALSE(receivedSigio);

  loop.run();

242
  EXPECT_TRUE(receivedSigurg);
243 244 245
  EXPECT_TRUE(receivedSigio);
}

246 247
#endif  // !__CYGWIN32__

248 249
TEST(AsyncUnixTest, ReadObserver) {
  captureSignals();
250 251
  UnixEventPort port;
  EventLoop loop(port);
252
  WaitScope waitScope(loop);
253 254 255

  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
256 257
  kj::AutoCloseFd infd(pipefds[0]), outfd(pipefds[1]);

258
  UnixEventPort::FdObserver observer(port, infd, UnixEventPort::FdObserver::OBSERVE_READ);
259 260 261

  KJ_SYSCALL(write(outfd, "foo", 3));

262
  observer.whenBecomesReadable().wait(waitScope);
263 264

#if __linux__  // platform known to support POLLRDHUP
265
  EXPECT_FALSE(KJ_ASSERT_NONNULL(observer.atEndHint()));
266

267 268 269 270 271 272 273 274
  char buffer[4096];
  ssize_t n;
  KJ_SYSCALL(n = read(infd, &buffer, sizeof(buffer)));
  EXPECT_EQ(3, n);

  KJ_SYSCALL(write(outfd, "bar", 3));
  outfd = nullptr;

275
  observer.whenBecomesReadable().wait(waitScope);
276

277
  EXPECT_TRUE(KJ_ASSERT_NONNULL(observer.atEndHint()));
278
#endif
279 280
}

281 282
TEST(AsyncUnixTest, ReadObserverMultiListen) {
  captureSignals();
283 284
  UnixEventPort port;
  EventLoop loop(port);
285
  WaitScope waitScope(loop);
286 287 288 289 290

  int bogusPipefds[2];
  KJ_SYSCALL(pipe(bogusPipefds));
  KJ_DEFER({ close(bogusPipefds[1]); close(bogusPipefds[0]); });

291 292 293 294
  UnixEventPort::FdObserver bogusObserver(port, bogusPipefds[0],
      UnixEventPort::FdObserver::OBSERVE_READ);

  bogusObserver.whenBecomesReadable().then([]() {
295
    ADD_FAILURE() << "Received wrong poll.";
296
  }).detach([](kj::Exception&& exception) {
297 298
    ADD_FAILURE() << kj::str(exception).cStr();
  });
299 300 301 302

  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
  KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); });
303

304 305
  UnixEventPort::FdObserver observer(port, pipefds[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
306 307
  KJ_SYSCALL(write(pipefds[1], "foo", 3));

308
  observer.whenBecomesReadable().wait(waitScope);
309 310
}

311 312
TEST(AsyncUnixTest, ReadObserverMultiReceive) {
  captureSignals();
313 314
  UnixEventPort port;
  EventLoop loop(port);
315
  WaitScope waitScope(loop);
316 317 318 319

  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
  KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); });
320

321 322
  UnixEventPort::FdObserver observer(port, pipefds[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
323 324 325 326 327
  KJ_SYSCALL(write(pipefds[1], "foo", 3));

  int pipefds2[2];
  KJ_SYSCALL(pipe(pipefds2));
  KJ_DEFER({ close(pipefds2[1]); close(pipefds2[0]); });
328

329 330
  UnixEventPort::FdObserver observer2(port, pipefds2[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
331 332
  KJ_SYSCALL(write(pipefds2[1], "bar", 3));

333 334 335 336
  auto promise1 = observer.whenBecomesReadable();
  auto promise2 = observer2.whenBecomesReadable();
  promise1.wait(waitScope);
  promise2.wait(waitScope);
337 338
}

339 340
TEST(AsyncUnixTest, ReadObserverAsync) {
  captureSignals();
341 342
  UnixEventPort port;
  EventLoop loop(port);
343
  WaitScope waitScope(loop);
344

345
  // Make a pipe and wait on its read end while another thread writes to it.
346 347
  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
348
  KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); });
349 350
  UnixEventPort::FdObserver observer(port, pipefds[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
351

352 353 354
  Thread thread([&]() {
    delay();
    KJ_SYSCALL(write(pipefds[1], "foo", 3));
355 356
  });

357
  // Wait for the event in this thread.
358
  observer.whenBecomesReadable().wait(waitScope);
359 360
}

361
TEST(AsyncUnixTest, ReadObserverNoWait) {
362 363
  // Verify that UnixEventPort::poll() correctly receives pending FD events.

364
  captureSignals();
365 366
  UnixEventPort port;
  EventLoop loop(port);
367
  WaitScope waitScope(loop);
368 369 370 371

  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
  KJ_DEFER({ close(pipefds[1]); close(pipefds[0]); });
372 373
  UnixEventPort::FdObserver observer(port, pipefds[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
374 375 376 377

  int pipefds2[2];
  KJ_SYSCALL(pipe(pipefds2));
  KJ_DEFER({ close(pipefds2[1]); close(pipefds2[0]); });
378 379
  UnixEventPort::FdObserver observer2(port, pipefds2[0],
      UnixEventPort::FdObserver::OBSERVE_READ);
380 381

  int receivedCount = 0;
382
  observer.whenBecomesReadable().then([&]() {
383
    receivedCount++;
384
  }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); });
385
  observer2.whenBecomesReadable().then([&]() {
386
    receivedCount++;
387
  }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); });
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404

  KJ_SYSCALL(write(pipefds[1], "foo", 3));
  KJ_SYSCALL(write(pipefds2[1], "bar", 3));

  EXPECT_EQ(0, receivedCount);

  loop.run();

  EXPECT_EQ(0, receivedCount);

  port.poll();

  EXPECT_EQ(0, receivedCount);

  loop.run();

  EXPECT_EQ(2, receivedCount);
405 406
}

407 408 409 410 411 412 413 414
static void setNonblocking(int fd) {
  int flags;
  KJ_SYSCALL(flags = fcntl(fd, F_GETFL));
  if ((flags & O_NONBLOCK) == 0) {
    KJ_SYSCALL(fcntl(fd, F_SETFL, flags | O_NONBLOCK));
  }
}

415 416
TEST(AsyncUnixTest, WriteObserver) {
  captureSignals();
417 418 419 420 421 422 423 424
  UnixEventPort port;
  EventLoop loop(port);
  WaitScope waitScope(loop);

  int pipefds[2];
  KJ_SYSCALL(pipe(pipefds));
  kj::AutoCloseFd infd(pipefds[0]), outfd(pipefds[1]);
  setNonblocking(outfd);
425
  setNonblocking(infd);
426

427
  UnixEventPort::FdObserver observer(port, outfd, UnixEventPort::FdObserver::OBSERVE_WRITE);
428 429 430 431 432 433 434 435

  // Fill buffer.
  ssize_t n;
  do {
    KJ_NONBLOCKING_SYSCALL(n = write(outfd, "foo", 3));
  } while (n >= 0);

  bool writable = false;
436
  auto promise = observer.whenBecomesWritable()
437 438 439 440 441 442 443 444
      .then([&]() { writable = true; }).eagerlyEvaluate(nullptr);

  loop.run();
  port.poll();
  loop.run();

  EXPECT_FALSE(writable);

445 446 447 448
  // Empty the read end so that the write end becomes writable. Note that Linux implements a
  // high watermark / low watermark heuristic which means that only reading one byte is not
  // sufficient. The amount we have to read is in fact architecture-dependent -- it appears to be
  // 1 page. To be safe, we read everything.
449
  char buffer[4096];
450
  do {
451
    KJ_NONBLOCKING_SYSCALL(n = read(infd, &buffer, sizeof(buffer)));
452
  } while (n > 0);
453 454 455 456 457 458 459 460

  loop.run();
  port.poll();
  loop.run();

  EXPECT_TRUE(writable);
}

461 462
#if !__APPLE__
// Disabled on macOS due to https://github.com/sandstorm-io/capnproto/issues/374.
463 464 465
TEST(AsyncUnixTest, UrgentObserver) {
  // Verify that FdObserver correctly detects availability of out-of-band data.
  // Availability of out-of-band data is implementation-specific.
466 467
  // Linux's and OS X's TCP/IP stack supports out-of-band messages for TCP sockets, which is used
  // for this test.
468 469 470 471 472

  UnixEventPort port;
  EventLoop loop(port);
  WaitScope waitScope(loop);
  int tmpFd;
473
  char c;
474

475
  // Spawn a TCP server
476 477
  KJ_SYSCALL(tmpFd = socket(AF_INET, SOCK_STREAM, 0));
  kj::AutoCloseFd serverFd(tmpFd);
478 479
  sockaddr_in saddr;
  memset(&saddr, 0, sizeof(saddr));
480 481 482
  saddr.sin_family = AF_INET;
  saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  KJ_SYSCALL(bind(serverFd, reinterpret_cast<sockaddr*>(&saddr), sizeof(saddr)));
483 484
  socklen_t saddrLen = sizeof(saddr);
  KJ_SYSCALL(getsockname(serverFd, reinterpret_cast<sockaddr*>(&saddr), &saddrLen));
485 486
  KJ_SYSCALL(listen(serverFd, 1));

487
  // Accept one connection, send in-band and OOB byte, wait for a quit message
488
  Thread thread([&]() {
489 490 491
    int tmpFd;
    char c;

492 493 494 495 496
    sockaddr_in caddr;
    socklen_t caddrLen = sizeof(caddr);
    KJ_SYSCALL(tmpFd = accept(serverFd, reinterpret_cast<sockaddr*>(&caddr), &caddrLen));
    kj::AutoCloseFd clientFd(tmpFd);
    delay();
497 498 499 500 501

    // Workaround: OS X won't signal POLLPRI without POLLIN. Also enqueue some in-band data.
    c = 'i';
    KJ_SYSCALL(send(clientFd, &c, 1, 0));
    c = 'o';
502
    KJ_SYSCALL(send(clientFd, &c, 1, MSG_OOB));
503

504
    KJ_SYSCALL(recv(clientFd, &c, 1, 0));
505
    EXPECT_EQ('q', c);
506
  });
507
  KJ_DEFER({ shutdown(serverFd, SHUT_RDWR); serverFd = nullptr; });
508 509 510

  KJ_SYSCALL(tmpFd = socket(AF_INET, SOCK_STREAM, 0));
  kj::AutoCloseFd clientFd(tmpFd);
511
  KJ_SYSCALL(connect(clientFd, reinterpret_cast<sockaddr*>(&saddr), saddrLen));
512

513 514 515 516
  UnixEventPort::FdObserver observer(port, clientFd,
      UnixEventPort::FdObserver::OBSERVE_READ | UnixEventPort::FdObserver::OBSERVE_URGENT);

  // Attempt to read the urgent byte prior to reading the in-band byte.
517
  observer.whenUrgentDataAvailable().wait(waitScope);
518 519 520 521
  KJ_SYSCALL(recv(clientFd, &c, 1, MSG_OOB));
  EXPECT_EQ('o', c);
  KJ_SYSCALL(recv(clientFd, &c, 1, 0));
  EXPECT_EQ('i', c);
522

523 524
  // Allow server thread to let its clientFd go out of scope.
  c = 'q';
525
  KJ_SYSCALL(send(clientFd, &c, 1, 0));
526
  KJ_SYSCALL(shutdown(clientFd, SHUT_RDWR));
527
}
528
#endif
529

530 531
TEST(AsyncUnixTest, SteadyTimers) {
  captureSignals();
532 533 534 535
  UnixEventPort port;
  EventLoop loop(port);
  WaitScope waitScope(loop);

536 537 538
  auto& timer = port.getTimer();

  auto start = timer.now();
539 540
  kj::Vector<TimePoint> expected;
  kj::Vector<TimePoint> actual;
541

542 543
  auto addTimer = [&](Duration delay) {
    expected.add(max(start + delay, start));
544 545
    timer.atTime(start + delay).then([&]() {
      actual.add(timer.now());
546 547 548
    }).detach([](Exception&& e) { ADD_FAILURE() << str(e).cStr(); });
  };

549 550 551 552 553
  addTimer(30 * MILLISECONDS);
  addTimer(40 * MILLISECONDS);
  addTimer(20350 * MICROSECONDS);
  addTimer(30 * MILLISECONDS);
  addTimer(-10 * MILLISECONDS);
554 555

  std::sort(expected.begin(), expected.end());
556
  timer.atTime(expected.back() + MILLISECONDS).wait(waitScope);
557 558 559

  ASSERT_EQ(expected.size(), actual.size());
  for (int i = 0; i < expected.size(); ++i) {
560 561
    KJ_EXPECT(expected[i] <= actual[i], "Actual time for timer i is too early.",
              i, ((expected[i] - actual[i]) / NANOSECONDS));
562 563 564
  }
}

565 566
TEST(AsyncUnixTest, Wake) {
  captureSignals();
567 568 569 570 571 572 573 574 575 576 577 578 579
  UnixEventPort port;
  EventLoop loop(port);
  WaitScope waitScope(loop);

  EXPECT_FALSE(port.poll());
  port.wake();
  EXPECT_TRUE(port.poll());
  EXPECT_FALSE(port.poll());

  port.wake();
  EXPECT_TRUE(port.wait());

  {
580
    auto promise = port.getTimer().atTime(port.getTimer().now());
581 582 583 584 585 586 587 588 589 590 591 592 593
    EXPECT_FALSE(port.wait());
  }

  bool woken = false;
  Thread thread([&]() {
    delay();
    woken = true;
    port.wake();
  });

  EXPECT_TRUE(port.wait());
}

594
}  // namespace
595
}  // namespace kj
596 597

#endif  // !_WIN32