From c6bdae86629f05777dfa6d8f2f4f7846da936cda Mon Sep 17 00:00:00 2001 From: Philip Pronin Date: Sun, 29 Jun 2014 04:49:47 -0700 Subject: [PATCH] fix AsyncIO::doWait Summary: As it turns out, `io_getevents` may actually return less than `min_nr` events. According to the aio logic (https://github.com/torvalds/linux/blob/10b5b5361a3c2a7fff9dbfa0f127adc2531e7732/fs/aio.c#L1634), there may be a couple of rounds required to get at least `nr_min` events, and if interrupted after the first one, incomplete results would be returned Test Plan: fbconfig -r folly/experimental/io/test && fbmake runtests_opt -32 and was no longer able to repro #4609062 Reviewed By: soren@fb.com FB internal diff: D1410389 Tasks: 4609062 --- folly/experimental/io/AsyncIO.cpp | 26 +++++++++++++++++++------- folly/experimental/io/AsyncIO.h | 3 ++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/folly/experimental/io/AsyncIO.cpp b/folly/experimental/io/AsyncIO.cpp index 633a30bf..1a4273df 100644 --- a/folly/experimental/io/AsyncIO.cpp +++ b/folly/experimental/io/AsyncIO.cpp @@ -19,9 +19,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -220,13 +220,25 @@ Range AsyncIO::pollCompleted() { Range AsyncIO::doWait(size_t minRequests, size_t maxRequests) { io_event events[maxRequests]; - int count; + + size_t count = 0; do { - // Wait forever - count = io_getevents(ctx_, minRequests, maxRequests, events, nullptr); - } while (count == -EINTR); - checkKernelError(count, "AsyncIO: io_getevents failed"); - DCHECK_GE(count, minRequests); // the man page says so + int ret; + do { + // GOTCHA: io_getevents() may returns less than min_nr results if + // interrupted after some events have been read (if before, -EINTR + // is returned). + ret = io_getevents(ctx_, + minRequests - count, + maxRequests - count, + events + count, + /* timeout */ nullptr); // wait forever + } while (ret == -EINTR); + // Check as may not be able to recover without leaking events. + CHECK_GE(ret, 0) + << "AsyncIO: io_getevents failed with error " << errnoStr(-ret); + count += ret; + } while (count < minRequests); DCHECK_LE(count, maxRequests); completed_.clear(); diff --git a/folly/experimental/io/AsyncIO.h b/folly/experimental/io/AsyncIO.h index 6c9da8d2..b595a325 100644 --- a/folly/experimental/io/AsyncIO.h +++ b/folly/experimental/io/AsyncIO.h @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include @@ -233,6 +233,7 @@ class AsyncIOQueue { */ typedef std::function OpFactory; void submit(OpFactory op); + private: void onCompleted(AsyncIOOp* op); void maybeDequeue(); -- 2.34.1