Commit c6bdae86 authored by Philip Pronin's avatar Philip Pronin Committed by Tudor Bosman

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
parent 09a81a96
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <unistd.h> #include <unistd.h>
#include <cerrno> #include <cerrno>
#include <ostream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <fstream>
#include <boost/intrusive/parent_from_member.hpp> #include <boost/intrusive/parent_from_member.hpp>
#include <glog/logging.h> #include <glog/logging.h>
...@@ -220,13 +220,25 @@ Range<AsyncIO::Op**> AsyncIO::pollCompleted() { ...@@ -220,13 +220,25 @@ Range<AsyncIO::Op**> AsyncIO::pollCompleted() {
Range<AsyncIO::Op**> AsyncIO::doWait(size_t minRequests, size_t maxRequests) { Range<AsyncIO::Op**> AsyncIO::doWait(size_t minRequests, size_t maxRequests) {
io_event events[maxRequests]; io_event events[maxRequests];
int count;
size_t count = 0;
do { do {
// Wait forever int ret;
count = io_getevents(ctx_, minRequests, maxRequests, events, nullptr); do {
} while (count == -EINTR); // GOTCHA: io_getevents() may returns less than min_nr results if
checkKernelError(count, "AsyncIO: io_getevents failed"); // interrupted after some events have been read (if before, -EINTR
DCHECK_GE(count, minRequests); // the man page says so // 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); DCHECK_LE(count, maxRequests);
completed_.clear(); completed_.clear();
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
#include <cstdint> #include <cstdint>
#include <deque> #include <deque>
#include <functional> #include <functional>
#include <iosfwd>
#include <mutex> #include <mutex>
#include <ostream>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -233,6 +233,7 @@ class AsyncIOQueue { ...@@ -233,6 +233,7 @@ class AsyncIOQueue {
*/ */
typedef std::function<AsyncIOOp*()> OpFactory; typedef std::function<AsyncIOOp*()> OpFactory;
void submit(OpFactory op); void submit(OpFactory op);
private: private:
void onCompleted(AsyncIOOp* op); void onCompleted(AsyncIOOp* op);
void maybeDequeue(); void maybeDequeue();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment