0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +01:00

ircd::fs::aio: Fix waiting on cancels; various fixes.

This commit is contained in:
Jason Volk 2019-04-21 00:20:44 -07:00
parent 003f9f771a
commit 1137f8a29b
2 changed files with 50 additions and 29 deletions

View file

@ -405,6 +405,8 @@ ircd::fs::aio::request::operator()()
// Wait for completion // Wait for completion
system->wait(*this); system->wait(*this);
assert(completed());
assert(retval <= ssize_t(submitted_bytes)); assert(retval <= ssize_t(submitted_bytes));
// Update stats for completion phase. // Update stats for completion phase.
@ -438,11 +440,22 @@ ircd::fs::aio::request::operator()()
}; };
} }
bool
ircd::fs::aio::request::queued()
const
{
return !for_each_queued([this]
(const auto &request)
{
return &request != this; // true to continue and return true
});
}
bool bool
ircd::fs::aio::request::completed() ircd::fs::aio::request::completed()
const const
{ {
return retval != std::numeric_limits<decltype(retval)>::min(); return retval >= -1L;
} }
ircd::fs::const_iovec_view ircd::fs::const_iovec_view
@ -607,36 +620,40 @@ ircd::fs::aio::system::wait()
void void
ircd::fs::aio::system::wait(request &request) ircd::fs::aio::system::wait(request &request)
try
{ {
assert(ctx::current == request.waiter); assert(ctx::current == request.waiter);
while(request.retval == std::numeric_limits<ssize_t>::min()) while(!request.completed()) try
{
ctx::wait(); ctx::wait();
} }
catch(const ctx::interrupted &e) catch(...)
{ {
// When the ctx is interrupted we're obligated to cancel the request. // When the ctx is interrupted we're obliged to cancel the request
// The handler callstack is invoked directly from here by cancel() for // if it has not reached a completed state.
// what it's worth but we rethrow the interrupt anyway. if(request.completed())
if(!request.completed()) throw;
request.cancel();
throw; // The handler callstack is invoked synchronously on this stack for
} // requests which are still in our userspace queue.
catch(const ctx::terminated &) if(request.queued())
{ {
if(!request.completed()) request.cancel();
request.cancel(); throw;
}
throw; // The handler callstack is invoked asynchronously for requests
// submitted to the kernel; we *must* wait for that by blocking
// ctx interrupts and terminations and continue to wait.
continue;
}
} }
bool bool
ircd::fs::aio::system::cancel(request &request) ircd::fs::aio::system::cancel(request &request)
try try
{ {
assert(request.retval == std::numeric_limits<ssize_t>::min());
assert(request.aio_data == uintptr_t(&request)); assert(request.aio_data == uintptr_t(&request));
assert(!request.completed() || request.queued());
iocb *const cb iocb *const cb
{ {
@ -681,6 +698,7 @@ try
result.res = -1; result.res = -1;
result.res2 = ECANCELED; result.res2 = ECANCELED;
} else { } else {
assert(!request.queued());
syscall_nointr<SYS_io_cancel>(head.get(), cb, &result); syscall_nointr<SYS_io_cancel>(head.get(), cb, &result);
in_flight--; in_flight--;
stats.cur_submits--; stats.cur_submits--;
@ -692,7 +710,8 @@ try
} }
catch(const std::system_error &e) catch(const std::system_error &e)
{ {
log::error assert(request.aio_data == uintptr_t(&request));
log::critical
{ {
"AIO(%p) cancel(fd:%d size:%zu off:%zd op:%u pri:%u) #%lu :%s", "AIO(%p) cancel(fd:%d size:%zu off:%zd op:%u pri:%u) #%lu :%s",
this, this,
@ -715,10 +734,10 @@ ircd::fs::aio::system::submit(request &request)
assert(qcount < queue.size()); assert(qcount < queue.size());
assert(qcount + in_flight < max_events()); assert(qcount + in_flight < max_events());
assert(request.aio_data == uintptr_t(&request)); assert(request.aio_data == uintptr_t(&request));
assert(!request.completed());
const ctx::critical_assertion ca; const ctx::critical_assertion ca;
queue.at(qcount++) = static_cast<iocb *>(&request);
queue.at(qcount++) = static_cast<iocb *>(&request);
stats.cur_queued++; stats.cur_queued++;
stats.max_queued = std::max(stats.max_queued, stats.cur_queued); stats.max_queued = std::max(stats.max_queued, stats.cur_queued);
assert(stats.cur_queued == qcount); assert(stats.cur_queued == qcount);
@ -754,7 +773,7 @@ ircd::fs::aio::system::submit(request &request)
} }
} }
/// The chaser is posted to the IRCd event loop after the first request is /// The chaser is posted to the IRCd event loop after the first request.
/// Ideally more requests will queue up before the chaser reaches the front /// Ideally more requests will queue up before the chaser reaches the front
/// of the IRCd event queue and executes. /// of the IRCd event queue and executes.
void void
@ -780,7 +799,8 @@ catch(const std::exception &e)
}; };
} }
/// The submitter submits all queued requests and resets the count. /// The submitter submits all queued requests and resets our userspace queue
/// count down to zero.
size_t size_t
ircd::fs::aio::system::submit() ircd::fs::aio::system::submit()
noexcept try noexcept try
@ -832,7 +852,7 @@ try
{ {
assert(qcount > 0); assert(qcount > 0);
#ifndef NDEBUG #ifdef RB_DEBUG
const size_t count[3] const size_t count[3]
{ {
count_queued(op::READ), count_queued(op::READ),
@ -856,7 +876,7 @@ try
syscall<SYS_io_submit>(head.get(), qcount, queue.data()) syscall<SYS_io_submit>(head.get(), qcount, queue.data())
}; };
#ifndef NDEBUG #ifdef RB_DEBUG
stats.stalls += warning.timer.stop() > 0; stats.stalls += warning.timer.stop() > 0;
#endif #endif

View file

@ -114,14 +114,15 @@ struct ircd::fs::aio::request
struct fdsync; struct fdsync;
struct fsync; struct fsync;
ctx::ctx *waiter {ctx::current}; ssize_t retval {-2L};
ssize_t retval {std::numeric_limits<ssize_t>::min()}; ssize_t errcode {0L};
ssize_t errcode {0};
const struct opts *opts {nullptr}; const struct opts *opts {nullptr};
ctx::ctx *waiter {ctx::current};
public: public:
const_iovec_view iovec() const; const_iovec_view iovec() const;
bool completed() const; bool completed() const;
bool queued() const;
size_t operator()(); size_t operator()();
bool cancel(); bool cancel();