2008-09-22 23:17:18 +04:00
|
|
|
/*
|
|
|
|
* QEMU aio implementation
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2008
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef QEMU_AIO_H
|
|
|
|
#define QEMU_AIO_H
|
|
|
|
|
|
|
|
#include "qemu-common.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/queue.h"
|
|
|
|
#include "qemu/event_notifier.h"
|
2013-07-16 08:28:58 +04:00
|
|
|
#include "qemu/thread.h"
|
2014-03-03 14:30:04 +04:00
|
|
|
#include "qemu/rfifolock.h"
|
2013-08-21 19:02:49 +04:00
|
|
|
#include "qemu/timer.h"
|
2008-09-22 23:17:18 +04:00
|
|
|
|
2014-10-07 15:59:14 +04:00
|
|
|
typedef struct BlockAIOCB BlockAIOCB;
|
2014-10-07 15:59:15 +04:00
|
|
|
typedef void BlockCompletionFunc(void *opaque, int ret);
|
2012-03-12 20:01:48 +04:00
|
|
|
|
2012-10-31 19:34:37 +04:00
|
|
|
typedef struct AIOCBInfo {
|
2014-10-07 15:59:14 +04:00
|
|
|
void (*cancel_async)(BlockAIOCB *acb);
|
|
|
|
AioContext *(*get_aio_context)(BlockAIOCB *acb);
|
2012-10-31 19:34:35 +04:00
|
|
|
size_t aiocb_size;
|
2012-10-31 19:34:37 +04:00
|
|
|
} AIOCBInfo;
|
2012-03-12 20:01:48 +04:00
|
|
|
|
2014-10-07 15:59:14 +04:00
|
|
|
struct BlockAIOCB {
|
2012-10-31 19:34:37 +04:00
|
|
|
const AIOCBInfo *aiocb_info;
|
2012-03-12 20:01:48 +04:00
|
|
|
BlockDriverState *bs;
|
2014-10-07 15:59:15 +04:00
|
|
|
BlockCompletionFunc *cb;
|
2012-03-12 20:01:48 +04:00
|
|
|
void *opaque;
|
2014-09-11 09:41:08 +04:00
|
|
|
int refcnt;
|
2012-03-12 20:01:48 +04:00
|
|
|
};
|
|
|
|
|
2012-10-31 19:34:37 +04:00
|
|
|
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
|
2014-10-07 15:59:15 +04:00
|
|
|
BlockCompletionFunc *cb, void *opaque);
|
2014-09-11 09:41:28 +04:00
|
|
|
void qemu_aio_unref(void *p);
|
2014-09-11 09:41:08 +04:00
|
|
|
void qemu_aio_ref(void *p);
|
2012-03-12 20:01:48 +04:00
|
|
|
|
2012-10-30 02:45:23 +04:00
|
|
|
typedef struct AioHandler AioHandler;
|
|
|
|
typedef void QEMUBHFunc(void *opaque);
|
|
|
|
typedef void IOHandler(void *opaque);
|
|
|
|
|
2016-07-04 19:33:20 +03:00
|
|
|
struct ThreadPool;
|
|
|
|
struct LinuxAioState;
|
|
|
|
|
2013-08-21 19:02:47 +04:00
|
|
|
struct AioContext {
|
2012-09-24 16:57:41 +04:00
|
|
|
GSource source;
|
|
|
|
|
2014-03-03 14:30:04 +04:00
|
|
|
/* Protects all fields from multi-threaded access */
|
|
|
|
RFifoLock lock;
|
|
|
|
|
2012-09-13 14:28:51 +04:00
|
|
|
/* The list of registered AIO handlers */
|
|
|
|
QLIST_HEAD(, AioHandler) aio_handlers;
|
|
|
|
|
|
|
|
/* This is a simple lock used to protect the aio_handlers list.
|
|
|
|
* Specifically, it's used to ensure that no callbacks are removed while
|
|
|
|
* we're walking and dispatching callbacks.
|
|
|
|
*/
|
|
|
|
int walking_handlers;
|
|
|
|
|
AioContext: fix broken ctx->dispatching optimization
This patch rewrites the ctx->dispatching optimization, which was the cause
of some mysterious hangs that could be reproduced on aarch64 KVM only.
The hangs were indirectly caused by aio_poll() and in particular by
flash memory updates's call to blk_write(), which invokes aio_poll().
Fun stuff: they had an extremely short race window, so much that
adding all kind of tracing to either the kernel or QEMU made it
go away (a single printf made it half as reproducible).
On the plus side, the failure mode (a hang until the next keypress)
made it very easy to examine the state of the process with a debugger.
And there was a very nice reproducer from Laszlo, which failed pretty
often (more than half of the time) on any version of QEMU with a non-debug
kernel; it also failed fast, while still in the firmware. So, it could
have been worse.
For some unknown reason they happened only with virtio-scsi, but
that's not important. It's more interesting that they disappeared with
io=native, making thread-pool.c a likely suspect for where the bug arose.
thread-pool.c is also one of the few places which use bottom halves
across threads, by the way.
I hope that no other similar bugs exist, but just in case :) I am
going to describe how the successful debugging went... Since the
likely culprit was the ctx->dispatching optimization, which mostly
affects bottom halves, the first observation was that there are two
qemu_bh_schedule() invocations in the thread pool: the one in the aio
worker and the one in thread_pool_completion_bh. The latter always
causes the optimization to trigger, the former may or may not. In
order to restrict the possibilities, I introduced new functions
qemu_bh_schedule_slow() and qemu_bh_schedule_fast():
/* qemu_bh_schedule_slow: */
ctx = bh->ctx;
bh->idle = 0;
if (atomic_xchg(&bh->scheduled, 1) == 0) {
event_notifier_set(&ctx->notifier);
}
/* qemu_bh_schedule_fast: */
ctx = bh->ctx;
bh->idle = 0;
assert(ctx->dispatching);
atomic_xchg(&bh->scheduled, 1);
Notice how the atomic_xchg is still in qemu_bh_schedule_slow(). This
was already debated a few months ago, so I assumed it to be correct.
In retrospect this was a very good idea, as you'll see later.
Changing thread_pool_completion_bh() to qemu_bh_schedule_fast() didn't
trigger the assertion (as expected). Changing the worker's invocation
to qemu_bh_schedule_slow() didn't hide the bug (another assumption
which luckily held). This already limited heavily the amount of
interaction between the threads, hinting that the problematic events
must have triggered around thread_pool_completion_bh().
As mentioned early, invoking a debugger to examine the state of a
hung process was pretty easy; the iothread was always waiting on a
poll(..., -1) system call. Infinite timeouts are much rarer on x86,
and this could be the reason why the bug was never observed there.
With the buggy sequence more or less resolved to an interaction between
thread_pool_completion_bh() and poll(..., -1), my "tracing" strategy was
to just add a few qemu_clock_get_ns(QEMU_CLOCK_REALTIME) calls, hoping
that the ordering of aio_ctx_prepare(), aio_ctx_dispatch, poll() and
qemu_bh_schedule_fast() would provide some hint. The output was:
(gdb) p last_prepare
$3 = 103885451
(gdb) p last_dispatch
$4 = 103876492
(gdb) p last_poll
$5 = 115909333
(gdb) p last_schedule
$6 = 115925212
Notice how the last call to qemu_poll_ns() came after aio_ctx_dispatch().
This makes little sense unless there is an aio_poll() call involved,
and indeed with a slightly different instrumentation you can see that
there is one:
(gdb) p last_prepare
$3 = 107569679
(gdb) p last_dispatch
$4 = 107561600
(gdb) p last_aio_poll
$5 = 110671400
(gdb) p last_schedule
$6 = 110698917
So the scenario becomes clearer:
iothread VCPU thread
--------------------------------------------------------------------------
aio_ctx_prepare
aio_ctx_check
qemu_poll_ns(timeout=-1)
aio_poll
aio_dispatch
thread_pool_completion_bh
qemu_bh_schedule()
At this point bh->scheduled = 1 and the iothread has not been woken up.
The solution must be close, but this alone should not be a problem,
because the bottom half is only rescheduled to account for rare situations
(see commit 3c80ca1, thread-pool: avoid deadlock in nested aio_poll()
calls, 2014-07-15).
Introducing a third thread---a thread pool worker thread, which
also does qemu_bh_schedule()---does bring out the problematic case.
The third thread must be awakened *after* the callback is complete and
thread_pool_completion_bh has redone the whole loop, explaining the
short race window. And then this is what happens:
thread pool worker
--------------------------------------------------------------------------
<I/O completes>
qemu_bh_schedule()
Tada, bh->scheduled is already 1, so qemu_bh_schedule() does nothing
and the iothread is never woken up. This is where the bh->scheduled
optimization comes into play---it is correct, but removing it would
have masked the bug.
So, what is the bug?
Well, the question asked by the ctx->dispatching optimization ("is any
active aio_poll dispatching?") was wrong. The right question to ask
instead is "is any active aio_poll *not* dispatching", i.e. in the prepare
or poll phases? In that case, the aio_poll is sleeping or might go to
sleep anytime soon, and the EventNotifier must be invoked to wake
it up.
In any other case (including if there is *no* active aio_poll at all!)
we can just wait for the next prepare phase to pick up the event (e.g. a
bottom half); the prepare phase will avoid the blocking and service the
bottom half.
Expressing the invariant with a logic formula, the broken one looked like:
!(exists(thread): in_dispatching(thread)) => !optimize
or equivalently:
!(exists(thread):
in_aio_poll(thread) && in_dispatching(thread)) => !optimize
In the correct one, the negation is in a slightly different place:
(exists(thread):
in_aio_poll(thread) && !in_dispatching(thread)) => !optimize
or equivalently:
(exists(thread): in_prepare_or_poll(thread)) => !optimize
Even if the difference boils down to moving an exclamation mark :)
the implementation is quite different. However, I think the new
one is simpler to understand.
In the old implementation, the "exists" was implemented with a boolean
value. This didn't really support well the case of multiple concurrent
event loops, but I thought that this was okay: aio_poll holds the
AioContext lock so there cannot be concurrent aio_poll invocations, and
I was just considering nested event loops. However, aio_poll _could_
indeed be concurrent with the GSource. This is why I came up with the
wrong invariant.
In the new implementation, "exists" is computed simply by counting how many
threads are in the prepare or poll phases. There are some interesting
points to consider, but the gist of the idea remains:
1) AioContext can be used through GSource as well; as mentioned in the
patch, bit 0 of the counter is reserved for the GSource.
2) the counter need not be updated for a non-blocking aio_poll, because
it won't sleep forever anyway. This is just a matter of checking
the "blocking" variable. This requires some changes to the win32
implementation, but is otherwise not too complicated.
3) as mentioned above, the new implementation will not call aio_notify
when there is *no* active aio_poll at all. The tests have to be
adjusted for this change. The calls to aio_notify in async.c are fine;
they only want to kick aio_poll out of a blocking wait, but need not
do anything if aio_poll is not running.
4) nested aio_poll: these just work with the new implementation; when
a nested event loop is invoked, the outer event loop is never in the
prepare or poll phases. The outer event loop thus has already decremented
the counter.
Reported-by: Richard W. M. Jones <rjones@redhat.com>
Reported-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Message-id: 1437487673-23740-5-git-send-email-pbonzini@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-07-21 17:07:51 +03:00
|
|
|
/* Used to avoid unnecessary event_notifier_set calls in aio_notify;
|
|
|
|
* accessed with atomic primitives. If this field is 0, everything
|
|
|
|
* (file descriptors, bottom halves, timers) will be re-evaluated
|
|
|
|
* before the next blocking poll(), thus the event_notifier_set call
|
|
|
|
* can be skipped. If it is non-zero, you may need to wake up a
|
|
|
|
* concurrent aio_poll or the glib main event loop, making
|
|
|
|
* event_notifier_set necessary.
|
|
|
|
*
|
|
|
|
* Bit 0 is reserved for GSource usage of the AioContext, and is 1
|
2016-07-15 12:44:18 +03:00
|
|
|
* between a call to aio_ctx_prepare and the next call to aio_ctx_check.
|
AioContext: fix broken ctx->dispatching optimization
This patch rewrites the ctx->dispatching optimization, which was the cause
of some mysterious hangs that could be reproduced on aarch64 KVM only.
The hangs were indirectly caused by aio_poll() and in particular by
flash memory updates's call to blk_write(), which invokes aio_poll().
Fun stuff: they had an extremely short race window, so much that
adding all kind of tracing to either the kernel or QEMU made it
go away (a single printf made it half as reproducible).
On the plus side, the failure mode (a hang until the next keypress)
made it very easy to examine the state of the process with a debugger.
And there was a very nice reproducer from Laszlo, which failed pretty
often (more than half of the time) on any version of QEMU with a non-debug
kernel; it also failed fast, while still in the firmware. So, it could
have been worse.
For some unknown reason they happened only with virtio-scsi, but
that's not important. It's more interesting that they disappeared with
io=native, making thread-pool.c a likely suspect for where the bug arose.
thread-pool.c is also one of the few places which use bottom halves
across threads, by the way.
I hope that no other similar bugs exist, but just in case :) I am
going to describe how the successful debugging went... Since the
likely culprit was the ctx->dispatching optimization, which mostly
affects bottom halves, the first observation was that there are two
qemu_bh_schedule() invocations in the thread pool: the one in the aio
worker and the one in thread_pool_completion_bh. The latter always
causes the optimization to trigger, the former may or may not. In
order to restrict the possibilities, I introduced new functions
qemu_bh_schedule_slow() and qemu_bh_schedule_fast():
/* qemu_bh_schedule_slow: */
ctx = bh->ctx;
bh->idle = 0;
if (atomic_xchg(&bh->scheduled, 1) == 0) {
event_notifier_set(&ctx->notifier);
}
/* qemu_bh_schedule_fast: */
ctx = bh->ctx;
bh->idle = 0;
assert(ctx->dispatching);
atomic_xchg(&bh->scheduled, 1);
Notice how the atomic_xchg is still in qemu_bh_schedule_slow(). This
was already debated a few months ago, so I assumed it to be correct.
In retrospect this was a very good idea, as you'll see later.
Changing thread_pool_completion_bh() to qemu_bh_schedule_fast() didn't
trigger the assertion (as expected). Changing the worker's invocation
to qemu_bh_schedule_slow() didn't hide the bug (another assumption
which luckily held). This already limited heavily the amount of
interaction between the threads, hinting that the problematic events
must have triggered around thread_pool_completion_bh().
As mentioned early, invoking a debugger to examine the state of a
hung process was pretty easy; the iothread was always waiting on a
poll(..., -1) system call. Infinite timeouts are much rarer on x86,
and this could be the reason why the bug was never observed there.
With the buggy sequence more or less resolved to an interaction between
thread_pool_completion_bh() and poll(..., -1), my "tracing" strategy was
to just add a few qemu_clock_get_ns(QEMU_CLOCK_REALTIME) calls, hoping
that the ordering of aio_ctx_prepare(), aio_ctx_dispatch, poll() and
qemu_bh_schedule_fast() would provide some hint. The output was:
(gdb) p last_prepare
$3 = 103885451
(gdb) p last_dispatch
$4 = 103876492
(gdb) p last_poll
$5 = 115909333
(gdb) p last_schedule
$6 = 115925212
Notice how the last call to qemu_poll_ns() came after aio_ctx_dispatch().
This makes little sense unless there is an aio_poll() call involved,
and indeed with a slightly different instrumentation you can see that
there is one:
(gdb) p last_prepare
$3 = 107569679
(gdb) p last_dispatch
$4 = 107561600
(gdb) p last_aio_poll
$5 = 110671400
(gdb) p last_schedule
$6 = 110698917
So the scenario becomes clearer:
iothread VCPU thread
--------------------------------------------------------------------------
aio_ctx_prepare
aio_ctx_check
qemu_poll_ns(timeout=-1)
aio_poll
aio_dispatch
thread_pool_completion_bh
qemu_bh_schedule()
At this point bh->scheduled = 1 and the iothread has not been woken up.
The solution must be close, but this alone should not be a problem,
because the bottom half is only rescheduled to account for rare situations
(see commit 3c80ca1, thread-pool: avoid deadlock in nested aio_poll()
calls, 2014-07-15).
Introducing a third thread---a thread pool worker thread, which
also does qemu_bh_schedule()---does bring out the problematic case.
The third thread must be awakened *after* the callback is complete and
thread_pool_completion_bh has redone the whole loop, explaining the
short race window. And then this is what happens:
thread pool worker
--------------------------------------------------------------------------
<I/O completes>
qemu_bh_schedule()
Tada, bh->scheduled is already 1, so qemu_bh_schedule() does nothing
and the iothread is never woken up. This is where the bh->scheduled
optimization comes into play---it is correct, but removing it would
have masked the bug.
So, what is the bug?
Well, the question asked by the ctx->dispatching optimization ("is any
active aio_poll dispatching?") was wrong. The right question to ask
instead is "is any active aio_poll *not* dispatching", i.e. in the prepare
or poll phases? In that case, the aio_poll is sleeping or might go to
sleep anytime soon, and the EventNotifier must be invoked to wake
it up.
In any other case (including if there is *no* active aio_poll at all!)
we can just wait for the next prepare phase to pick up the event (e.g. a
bottom half); the prepare phase will avoid the blocking and service the
bottom half.
Expressing the invariant with a logic formula, the broken one looked like:
!(exists(thread): in_dispatching(thread)) => !optimize
or equivalently:
!(exists(thread):
in_aio_poll(thread) && in_dispatching(thread)) => !optimize
In the correct one, the negation is in a slightly different place:
(exists(thread):
in_aio_poll(thread) && !in_dispatching(thread)) => !optimize
or equivalently:
(exists(thread): in_prepare_or_poll(thread)) => !optimize
Even if the difference boils down to moving an exclamation mark :)
the implementation is quite different. However, I think the new
one is simpler to understand.
In the old implementation, the "exists" was implemented with a boolean
value. This didn't really support well the case of multiple concurrent
event loops, but I thought that this was okay: aio_poll holds the
AioContext lock so there cannot be concurrent aio_poll invocations, and
I was just considering nested event loops. However, aio_poll _could_
indeed be concurrent with the GSource. This is why I came up with the
wrong invariant.
In the new implementation, "exists" is computed simply by counting how many
threads are in the prepare or poll phases. There are some interesting
points to consider, but the gist of the idea remains:
1) AioContext can be used through GSource as well; as mentioned in the
patch, bit 0 of the counter is reserved for the GSource.
2) the counter need not be updated for a non-blocking aio_poll, because
it won't sleep forever anyway. This is just a matter of checking
the "blocking" variable. This requires some changes to the win32
implementation, but is otherwise not too complicated.
3) as mentioned above, the new implementation will not call aio_notify
when there is *no* active aio_poll at all. The tests have to be
adjusted for this change. The calls to aio_notify in async.c are fine;
they only want to kick aio_poll out of a blocking wait, but need not
do anything if aio_poll is not running.
4) nested aio_poll: these just work with the new implementation; when
a nested event loop is invoked, the outer event loop is never in the
prepare or poll phases. The outer event loop thus has already decremented
the counter.
Reported-by: Richard W. M. Jones <rjones@redhat.com>
Reported-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Message-id: 1437487673-23740-5-git-send-email-pbonzini@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-07-21 17:07:51 +03:00
|
|
|
* Bits 1-31 simply count the number of active calls to aio_poll
|
|
|
|
* that are in the prepare or poll phase.
|
|
|
|
*
|
|
|
|
* The GSource and aio_poll must use a different mechanism because
|
|
|
|
* there is no certainty that a call to GSource's prepare callback
|
|
|
|
* (via g_main_context_prepare) is indeed followed by check and
|
|
|
|
* dispatch. It's not clear whether this would be a bug, but let's
|
|
|
|
* play safe and allow it---it will just cause extra calls to
|
|
|
|
* event_notifier_set until the next call to dispatch.
|
|
|
|
*
|
|
|
|
* Instead, the aio_poll calls include both the prepare and the
|
|
|
|
* dispatch phase, hence a simple counter is enough for them.
|
2014-07-07 17:18:04 +04:00
|
|
|
*/
|
AioContext: fix broken ctx->dispatching optimization
This patch rewrites the ctx->dispatching optimization, which was the cause
of some mysterious hangs that could be reproduced on aarch64 KVM only.
The hangs were indirectly caused by aio_poll() and in particular by
flash memory updates's call to blk_write(), which invokes aio_poll().
Fun stuff: they had an extremely short race window, so much that
adding all kind of tracing to either the kernel or QEMU made it
go away (a single printf made it half as reproducible).
On the plus side, the failure mode (a hang until the next keypress)
made it very easy to examine the state of the process with a debugger.
And there was a very nice reproducer from Laszlo, which failed pretty
often (more than half of the time) on any version of QEMU with a non-debug
kernel; it also failed fast, while still in the firmware. So, it could
have been worse.
For some unknown reason they happened only with virtio-scsi, but
that's not important. It's more interesting that they disappeared with
io=native, making thread-pool.c a likely suspect for where the bug arose.
thread-pool.c is also one of the few places which use bottom halves
across threads, by the way.
I hope that no other similar bugs exist, but just in case :) I am
going to describe how the successful debugging went... Since the
likely culprit was the ctx->dispatching optimization, which mostly
affects bottom halves, the first observation was that there are two
qemu_bh_schedule() invocations in the thread pool: the one in the aio
worker and the one in thread_pool_completion_bh. The latter always
causes the optimization to trigger, the former may or may not. In
order to restrict the possibilities, I introduced new functions
qemu_bh_schedule_slow() and qemu_bh_schedule_fast():
/* qemu_bh_schedule_slow: */
ctx = bh->ctx;
bh->idle = 0;
if (atomic_xchg(&bh->scheduled, 1) == 0) {
event_notifier_set(&ctx->notifier);
}
/* qemu_bh_schedule_fast: */
ctx = bh->ctx;
bh->idle = 0;
assert(ctx->dispatching);
atomic_xchg(&bh->scheduled, 1);
Notice how the atomic_xchg is still in qemu_bh_schedule_slow(). This
was already debated a few months ago, so I assumed it to be correct.
In retrospect this was a very good idea, as you'll see later.
Changing thread_pool_completion_bh() to qemu_bh_schedule_fast() didn't
trigger the assertion (as expected). Changing the worker's invocation
to qemu_bh_schedule_slow() didn't hide the bug (another assumption
which luckily held). This already limited heavily the amount of
interaction between the threads, hinting that the problematic events
must have triggered around thread_pool_completion_bh().
As mentioned early, invoking a debugger to examine the state of a
hung process was pretty easy; the iothread was always waiting on a
poll(..., -1) system call. Infinite timeouts are much rarer on x86,
and this could be the reason why the bug was never observed there.
With the buggy sequence more or less resolved to an interaction between
thread_pool_completion_bh() and poll(..., -1), my "tracing" strategy was
to just add a few qemu_clock_get_ns(QEMU_CLOCK_REALTIME) calls, hoping
that the ordering of aio_ctx_prepare(), aio_ctx_dispatch, poll() and
qemu_bh_schedule_fast() would provide some hint. The output was:
(gdb) p last_prepare
$3 = 103885451
(gdb) p last_dispatch
$4 = 103876492
(gdb) p last_poll
$5 = 115909333
(gdb) p last_schedule
$6 = 115925212
Notice how the last call to qemu_poll_ns() came after aio_ctx_dispatch().
This makes little sense unless there is an aio_poll() call involved,
and indeed with a slightly different instrumentation you can see that
there is one:
(gdb) p last_prepare
$3 = 107569679
(gdb) p last_dispatch
$4 = 107561600
(gdb) p last_aio_poll
$5 = 110671400
(gdb) p last_schedule
$6 = 110698917
So the scenario becomes clearer:
iothread VCPU thread
--------------------------------------------------------------------------
aio_ctx_prepare
aio_ctx_check
qemu_poll_ns(timeout=-1)
aio_poll
aio_dispatch
thread_pool_completion_bh
qemu_bh_schedule()
At this point bh->scheduled = 1 and the iothread has not been woken up.
The solution must be close, but this alone should not be a problem,
because the bottom half is only rescheduled to account for rare situations
(see commit 3c80ca1, thread-pool: avoid deadlock in nested aio_poll()
calls, 2014-07-15).
Introducing a third thread---a thread pool worker thread, which
also does qemu_bh_schedule()---does bring out the problematic case.
The third thread must be awakened *after* the callback is complete and
thread_pool_completion_bh has redone the whole loop, explaining the
short race window. And then this is what happens:
thread pool worker
--------------------------------------------------------------------------
<I/O completes>
qemu_bh_schedule()
Tada, bh->scheduled is already 1, so qemu_bh_schedule() does nothing
and the iothread is never woken up. This is where the bh->scheduled
optimization comes into play---it is correct, but removing it would
have masked the bug.
So, what is the bug?
Well, the question asked by the ctx->dispatching optimization ("is any
active aio_poll dispatching?") was wrong. The right question to ask
instead is "is any active aio_poll *not* dispatching", i.e. in the prepare
or poll phases? In that case, the aio_poll is sleeping or might go to
sleep anytime soon, and the EventNotifier must be invoked to wake
it up.
In any other case (including if there is *no* active aio_poll at all!)
we can just wait for the next prepare phase to pick up the event (e.g. a
bottom half); the prepare phase will avoid the blocking and service the
bottom half.
Expressing the invariant with a logic formula, the broken one looked like:
!(exists(thread): in_dispatching(thread)) => !optimize
or equivalently:
!(exists(thread):
in_aio_poll(thread) && in_dispatching(thread)) => !optimize
In the correct one, the negation is in a slightly different place:
(exists(thread):
in_aio_poll(thread) && !in_dispatching(thread)) => !optimize
or equivalently:
(exists(thread): in_prepare_or_poll(thread)) => !optimize
Even if the difference boils down to moving an exclamation mark :)
the implementation is quite different. However, I think the new
one is simpler to understand.
In the old implementation, the "exists" was implemented with a boolean
value. This didn't really support well the case of multiple concurrent
event loops, but I thought that this was okay: aio_poll holds the
AioContext lock so there cannot be concurrent aio_poll invocations, and
I was just considering nested event loops. However, aio_poll _could_
indeed be concurrent with the GSource. This is why I came up with the
wrong invariant.
In the new implementation, "exists" is computed simply by counting how many
threads are in the prepare or poll phases. There are some interesting
points to consider, but the gist of the idea remains:
1) AioContext can be used through GSource as well; as mentioned in the
patch, bit 0 of the counter is reserved for the GSource.
2) the counter need not be updated for a non-blocking aio_poll, because
it won't sleep forever anyway. This is just a matter of checking
the "blocking" variable. This requires some changes to the win32
implementation, but is otherwise not too complicated.
3) as mentioned above, the new implementation will not call aio_notify
when there is *no* active aio_poll at all. The tests have to be
adjusted for this change. The calls to aio_notify in async.c are fine;
they only want to kick aio_poll out of a blocking wait, but need not
do anything if aio_poll is not running.
4) nested aio_poll: these just work with the new implementation; when
a nested event loop is invoked, the outer event loop is never in the
prepare or poll phases. The outer event loop thus has already decremented
the counter.
Reported-by: Richard W. M. Jones <rjones@redhat.com>
Reported-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Message-id: 1437487673-23740-5-git-send-email-pbonzini@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-07-21 17:07:51 +03:00
|
|
|
uint32_t notify_me;
|
2014-07-07 17:18:04 +04:00
|
|
|
|
2013-07-16 08:28:58 +04:00
|
|
|
/* lock to protect between bh's adders and deleter */
|
|
|
|
QemuMutex bh_lock;
|
2014-07-07 17:18:04 +04:00
|
|
|
|
2012-10-30 02:45:23 +04:00
|
|
|
/* Anchor of the list of Bottom Halves belonging to the context */
|
|
|
|
struct QEMUBH *first_bh;
|
|
|
|
|
|
|
|
/* A simple lock used to protect the first_bh list, and ensure that
|
|
|
|
* no callbacks are removed while we're walking and dispatching callbacks.
|
|
|
|
*/
|
|
|
|
int walking_bh;
|
2012-09-24 20:44:14 +04:00
|
|
|
|
2015-07-21 17:07:53 +03:00
|
|
|
/* Used by aio_notify.
|
|
|
|
*
|
|
|
|
* "notified" is used to avoid expensive event_notifier_test_and_clear
|
|
|
|
* calls. When it is clear, the EventNotifier is clear, or one thread
|
|
|
|
* is going to clear "notified" before processing more events. False
|
|
|
|
* positives are possible, i.e. "notified" could be set even though the
|
|
|
|
* EventNotifier is clear.
|
|
|
|
*
|
|
|
|
* Note that event_notifier_set *cannot* be optimized the same way. For
|
|
|
|
* more information on the problem that would result, see "#ifdef BUG2"
|
|
|
|
* in the docs/aio_notify_accept.promela formal model.
|
|
|
|
*/
|
|
|
|
bool notified;
|
2012-09-24 20:44:14 +04:00
|
|
|
EventNotifier notifier;
|
2013-02-20 14:28:32 +04:00
|
|
|
|
2015-07-28 19:34:09 +03:00
|
|
|
/* Scheduling this BH forces the event loop it iterate */
|
|
|
|
QEMUBH *notify_dummy_bh;
|
|
|
|
|
2013-03-07 16:41:47 +04:00
|
|
|
/* Thread pool for performing work and receiving completion callbacks */
|
|
|
|
struct ThreadPool *thread_pool;
|
2013-08-21 19:02:49 +04:00
|
|
|
|
2016-07-04 19:33:20 +03:00
|
|
|
#ifdef CONFIG_LINUX_AIO
|
|
|
|
/* State for native Linux AIO. Uses aio_context_acquire/release for
|
|
|
|
* locking.
|
|
|
|
*/
|
|
|
|
struct LinuxAioState *linux_aio;
|
|
|
|
#endif
|
|
|
|
|
2013-08-21 19:02:49 +04:00
|
|
|
/* TimerLists for calling timers - one per clock type */
|
|
|
|
QEMUTimerListGroup tlg;
|
2015-10-23 06:08:08 +03:00
|
|
|
|
|
|
|
int external_disable_cnt;
|
2015-10-30 07:06:29 +03:00
|
|
|
|
|
|
|
/* epoll(7) state used when built with CONFIG_EPOLL */
|
|
|
|
int epollfd;
|
|
|
|
bool epoll_enabled;
|
|
|
|
bool epoll_available;
|
2013-08-21 19:02:47 +04:00
|
|
|
};
|
2012-10-30 02:45:23 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* aio_context_new: Allocate a new AioContext.
|
|
|
|
*
|
|
|
|
* AioContext provide a mini event-loop that can be waited on synchronously.
|
|
|
|
* They also provide bottom halves, a service to execute a piece of code
|
|
|
|
* as soon as possible.
|
|
|
|
*/
|
2014-09-18 15:30:49 +04:00
|
|
|
AioContext *aio_context_new(Error **errp);
|
2012-10-30 02:45:23 +04:00
|
|
|
|
2012-09-24 16:57:41 +04:00
|
|
|
/**
|
|
|
|
* aio_context_ref:
|
|
|
|
* @ctx: The AioContext to operate on.
|
|
|
|
*
|
|
|
|
* Add a reference to an AioContext.
|
|
|
|
*/
|
|
|
|
void aio_context_ref(AioContext *ctx);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aio_context_unref:
|
|
|
|
* @ctx: The AioContext to operate on.
|
|
|
|
*
|
|
|
|
* Drop a reference to an AioContext.
|
|
|
|
*/
|
|
|
|
void aio_context_unref(AioContext *ctx);
|
|
|
|
|
2014-03-03 14:30:04 +04:00
|
|
|
/* Take ownership of the AioContext. If the AioContext will be shared between
|
2015-02-20 19:26:51 +03:00
|
|
|
* threads, and a thread does not want to be interrupted, it will have to
|
|
|
|
* take ownership around calls to aio_poll(). Otherwise, aio_poll()
|
|
|
|
* automatically takes care of calling aio_context_acquire and
|
|
|
|
* aio_context_release.
|
2014-03-03 14:30:04 +04:00
|
|
|
*
|
2015-02-20 19:26:51 +03:00
|
|
|
* Access to timers and BHs from a thread that has not acquired AioContext
|
|
|
|
* is possible. Access to callbacks for now must be done while the AioContext
|
|
|
|
* is owned by the thread (FIXME).
|
2014-03-03 14:30:04 +04:00
|
|
|
*/
|
|
|
|
void aio_context_acquire(AioContext *ctx);
|
|
|
|
|
|
|
|
/* Relinquish ownership of the AioContext. */
|
|
|
|
void aio_context_release(AioContext *ctx);
|
|
|
|
|
2012-10-30 02:45:23 +04:00
|
|
|
/**
|
|
|
|
* aio_bh_new: Allocate a new bottom half structure.
|
|
|
|
*
|
|
|
|
* Bottom halves are lightweight callbacks whose invocation is guaranteed
|
|
|
|
* to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
|
|
|
|
* is opaque and must be allocated prior to its use.
|
|
|
|
*/
|
|
|
|
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
|
|
|
|
|
2012-09-24 20:44:14 +04:00
|
|
|
/**
|
|
|
|
* aio_notify: Force processing of pending events.
|
|
|
|
*
|
|
|
|
* Similar to signaling a condition variable, aio_notify forces
|
|
|
|
* aio_wait to exit, so that the next call will re-examine pending events.
|
|
|
|
* The caller of aio_notify will usually call aio_wait again very soon,
|
|
|
|
* or go through another iteration of the GLib main loop. Hence, aio_notify
|
|
|
|
* also has the side effect of recalculating the sets of file descriptors
|
|
|
|
* that the main loop waits for.
|
|
|
|
*
|
|
|
|
* Calling aio_notify is rarely necessary, because for example scheduling
|
|
|
|
* a bottom half calls it already.
|
|
|
|
*/
|
|
|
|
void aio_notify(AioContext *ctx);
|
|
|
|
|
2015-07-21 17:07:53 +03:00
|
|
|
/**
|
|
|
|
* aio_notify_accept: Acknowledge receiving an aio_notify.
|
|
|
|
*
|
|
|
|
* aio_notify() uses an EventNotifier in order to wake up a sleeping
|
|
|
|
* aio_poll() or g_main_context_iteration(). Calls to aio_notify() are
|
|
|
|
* usually rare, but the AioContext has to clear the EventNotifier on
|
|
|
|
* every aio_poll() or g_main_context_iteration() in order to avoid
|
|
|
|
* busy waiting. This event_notifier_test_and_clear() cannot be done
|
|
|
|
* using the usual aio_context_set_event_notifier(), because it must
|
|
|
|
* be done before processing all events (file descriptors, bottom halves,
|
|
|
|
* timers).
|
|
|
|
*
|
|
|
|
* aio_notify_accept() is an optimized event_notifier_test_and_clear()
|
|
|
|
* that is specific to an AioContext's notifier; it is used internally
|
|
|
|
* to clear the EventNotifier only if aio_notify() had been called.
|
|
|
|
*/
|
|
|
|
void aio_notify_accept(AioContext *ctx);
|
|
|
|
|
2015-09-17 19:24:50 +03:00
|
|
|
/**
|
|
|
|
* aio_bh_call: Executes callback function of the specified BH.
|
|
|
|
*/
|
|
|
|
void aio_bh_call(QEMUBH *bh);
|
|
|
|
|
2012-10-30 02:45:23 +04:00
|
|
|
/**
|
|
|
|
* aio_bh_poll: Poll bottom halves for an AioContext.
|
|
|
|
*
|
|
|
|
* These are internal functions used by the QEMU main loop.
|
2013-07-16 08:28:58 +04:00
|
|
|
* And notice that multiple occurrences of aio_bh_poll cannot
|
|
|
|
* be called concurrently
|
2012-10-30 02:45:23 +04:00
|
|
|
*/
|
|
|
|
int aio_bh_poll(AioContext *ctx);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemu_bh_schedule: Schedule a bottom half.
|
|
|
|
*
|
|
|
|
* Scheduling a bottom half interrupts the main loop and causes the
|
|
|
|
* execution of the callback that was passed to qemu_bh_new.
|
|
|
|
*
|
|
|
|
* Bottom halves that are scheduled from a bottom half handler are instantly
|
|
|
|
* invoked. This can create an infinite loop if a bottom half handler
|
|
|
|
* schedules itself.
|
|
|
|
*
|
|
|
|
* @bh: The bottom half to be scheduled.
|
|
|
|
*/
|
|
|
|
void qemu_bh_schedule(QEMUBH *bh);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qemu_bh_cancel: Cancel execution of a bottom half.
|
|
|
|
*
|
|
|
|
* Canceling execution of a bottom half undoes the effect of calls to
|
|
|
|
* qemu_bh_schedule without freeing its resources yet. While cancellation
|
|
|
|
* itself is also wait-free and thread-safe, it can of course race with the
|
|
|
|
* loop that executes bottom halves unless you are holding the iothread
|
|
|
|
* mutex. This makes it mostly useless if you are not holding the mutex.
|
|
|
|
*
|
|
|
|
* @bh: The bottom half to be canceled.
|
|
|
|
*/
|
|
|
|
void qemu_bh_cancel(QEMUBH *bh);
|
|
|
|
|
|
|
|
/**
|
|
|
|
*qemu_bh_delete: Cancel execution of a bottom half and free its resources.
|
|
|
|
*
|
|
|
|
* Deleting a bottom half frees the memory that was allocated for it by
|
|
|
|
* qemu_bh_new. It also implies canceling the bottom half if it was
|
|
|
|
* scheduled.
|
2013-07-16 08:28:58 +04:00
|
|
|
* This func is async. The bottom half will do the delete action at the finial
|
|
|
|
* end.
|
2012-10-30 02:45:23 +04:00
|
|
|
*
|
|
|
|
* @bh: The bottom half to be deleted.
|
|
|
|
*/
|
|
|
|
void qemu_bh_delete(QEMUBH *bh);
|
|
|
|
|
2012-09-24 16:57:22 +04:00
|
|
|
/* Return whether there are any pending callbacks from the GSource
|
2014-07-09 13:53:08 +04:00
|
|
|
* attached to the AioContext, before g_poll is invoked.
|
|
|
|
*
|
|
|
|
* This is used internally in the implementation of the GSource.
|
|
|
|
*/
|
|
|
|
bool aio_prepare(AioContext *ctx);
|
|
|
|
|
|
|
|
/* Return whether there are any pending callbacks from the GSource
|
|
|
|
* attached to the AioContext, after g_poll is invoked.
|
2012-09-24 16:57:22 +04:00
|
|
|
*
|
|
|
|
* This is used internally in the implementation of the GSource.
|
|
|
|
*/
|
|
|
|
bool aio_pending(AioContext *ctx);
|
|
|
|
|
2014-07-09 13:53:05 +04:00
|
|
|
/* Dispatch any pending callbacks from the GSource attached to the AioContext.
|
|
|
|
*
|
|
|
|
* This is used internally in the implementation of the GSource.
|
|
|
|
*/
|
|
|
|
bool aio_dispatch(AioContext *ctx);
|
|
|
|
|
2012-09-24 16:37:53 +04:00
|
|
|
/* Progress in completing AIO work to occur. This can issue new pending
|
|
|
|
* aio as a result of executing I/O completion or bh callbacks.
|
2012-04-12 16:00:55 +04:00
|
|
|
*
|
AioContext: do not rely on aio_poll(ctx, true) result to end a loop
Currently, whenever aio_poll(ctx, true) has completed all pending
work it returns true *and* the next call to aio_poll(ctx, true)
will not block.
This invariant has its roots in qemu_aio_flush()'s implementation
as "while (qemu_aio_wait()) {}". However, qemu_aio_flush() does
not exist anymore and bdrv_drain_all() is implemented differently;
and this invariant is complicated to maintain and subtly different
from the return value of GMainLoop's g_main_context_iteration.
All calls to aio_poll(ctx, true) except one are guarded by a
while() loop checking for a request to be incomplete, or a
BlockDriverState to be idle. The one remaining call (in
iothread.c) uses this to delay the aio_context_release/acquire
pair until the AioContext is quiescent, however:
- we can do the same just by using non-blocking aio_poll,
similar to how vl.c invokes main_loop_wait
- it is buggy, because it does not ensure that the AioContext
is released between an aio_notify and the next time the
iothread goes to sleep. This leads to hangs when stopping
the dataplane thread.
In the end, these semantics are a bad match for the current
users of AioContext. So modify that one exception in iothread.c,
which also fixes the hangs, as well as the testcase so that
it use the same idiom as the actual QEMU code.
Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-07-09 12:49:46 +04:00
|
|
|
* Return whether any progress was made by executing AIO or bottom half
|
|
|
|
* handlers. If @blocking == true, this should always be true except
|
|
|
|
* if someone called aio_notify.
|
2012-09-24 16:37:53 +04:00
|
|
|
*
|
|
|
|
* If there are no pending bottom halves, but there are pending AIO
|
|
|
|
* operations, it may not be possible to make any progress without
|
|
|
|
* blocking. If @blocking is true, this function will wait until one
|
|
|
|
* or more AIO events have completed, to ensure something has moved
|
|
|
|
* before returning.
|
|
|
|
*/
|
|
|
|
bool aio_poll(AioContext *ctx, bool blocking);
|
2008-09-22 23:17:18 +04:00
|
|
|
|
|
|
|
/* Register a file descriptor and associated callbacks. Behaves very similarly
|
2015-06-04 09:45:19 +03:00
|
|
|
* to qemu_set_fd_handler. Unlike qemu_set_fd_handler, these callbacks will
|
2014-07-07 17:18:02 +04:00
|
|
|
* be invoked when using aio_poll().
|
2008-09-22 23:17:18 +04:00
|
|
|
*
|
|
|
|
* Code that invokes AIO completion functions should rely on this function
|
|
|
|
* instead of qemu_set_fd_handler[2].
|
|
|
|
*/
|
2012-09-13 14:28:51 +04:00
|
|
|
void aio_set_fd_handler(AioContext *ctx,
|
|
|
|
int fd,
|
2015-10-23 06:08:05 +03:00
|
|
|
bool is_external,
|
2012-09-13 14:28:51 +04:00
|
|
|
IOHandler *io_read,
|
|
|
|
IOHandler *io_write,
|
|
|
|
void *opaque);
|
2012-06-09 05:44:00 +04:00
|
|
|
|
|
|
|
/* Register an event notifier and associated callbacks. Behaves very similarly
|
|
|
|
* to event_notifier_set_handler. Unlike event_notifier_set_handler, these callbacks
|
2014-07-07 17:18:02 +04:00
|
|
|
* will be invoked when using aio_poll().
|
2012-06-09 05:44:00 +04:00
|
|
|
*
|
|
|
|
* Code that invokes AIO completion functions should rely on this function
|
|
|
|
* instead of event_notifier_set_handler.
|
|
|
|
*/
|
2012-09-13 14:28:51 +04:00
|
|
|
void aio_set_event_notifier(AioContext *ctx,
|
|
|
|
EventNotifier *notifier,
|
2015-10-23 06:08:05 +03:00
|
|
|
bool is_external,
|
2013-04-11 19:26:25 +04:00
|
|
|
EventNotifierHandler *io_read);
|
2012-09-13 14:28:51 +04:00
|
|
|
|
2012-09-24 16:57:41 +04:00
|
|
|
/* Return a GSource that lets the main loop poll the file descriptors attached
|
|
|
|
* to this AioContext.
|
|
|
|
*/
|
|
|
|
GSource *aio_get_g_source(AioContext *ctx);
|
|
|
|
|
2013-03-07 16:41:47 +04:00
|
|
|
/* Return the ThreadPool bound to this AioContext */
|
|
|
|
struct ThreadPool *aio_get_thread_pool(AioContext *ctx);
|
|
|
|
|
2016-07-04 19:33:20 +03:00
|
|
|
/* Return the LinuxAioState bound to this AioContext */
|
|
|
|
struct LinuxAioState *aio_get_linux_aio(AioContext *ctx);
|
|
|
|
|
2013-08-21 19:02:52 +04:00
|
|
|
/**
|
|
|
|
* aio_timer_new:
|
|
|
|
* @ctx: the aio context
|
|
|
|
* @type: the clock type
|
|
|
|
* @scale: the scale
|
|
|
|
* @cb: the callback to call on timer expiry
|
|
|
|
* @opaque: the opaque pointer to pass to the callback
|
|
|
|
*
|
|
|
|
* Allocate a new timer attached to the context @ctx.
|
|
|
|
* The function is responsible for memory allocation.
|
|
|
|
*
|
|
|
|
* The preferred interface is aio_timer_init. Use that
|
|
|
|
* unless you really need dynamic memory allocation.
|
|
|
|
*
|
|
|
|
* Returns: a pointer to the new timer
|
|
|
|
*/
|
|
|
|
static inline QEMUTimer *aio_timer_new(AioContext *ctx, QEMUClockType type,
|
|
|
|
int scale,
|
|
|
|
QEMUTimerCB *cb, void *opaque)
|
|
|
|
{
|
|
|
|
return timer_new_tl(ctx->tlg.tl[type], scale, cb, opaque);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aio_timer_init:
|
|
|
|
* @ctx: the aio context
|
|
|
|
* @ts: the timer
|
|
|
|
* @type: the clock type
|
|
|
|
* @scale: the scale
|
|
|
|
* @cb: the callback to call on timer expiry
|
|
|
|
* @opaque: the opaque pointer to pass to the callback
|
|
|
|
*
|
|
|
|
* Initialise a new timer attached to the context @ctx.
|
|
|
|
* The caller is responsible for memory allocation.
|
|
|
|
*/
|
|
|
|
static inline void aio_timer_init(AioContext *ctx,
|
|
|
|
QEMUTimer *ts, QEMUClockType type,
|
|
|
|
int scale,
|
|
|
|
QEMUTimerCB *cb, void *opaque)
|
|
|
|
{
|
2014-12-23 23:54:14 +03:00
|
|
|
timer_init_tl(ts, ctx->tlg.tl[type], scale, cb, opaque);
|
2013-08-21 19:02:52 +04:00
|
|
|
}
|
|
|
|
|
2014-07-09 13:53:01 +04:00
|
|
|
/**
|
|
|
|
* aio_compute_timeout:
|
|
|
|
* @ctx: the aio context
|
|
|
|
*
|
|
|
|
* Compute the timeout that a blocking aio_poll should use.
|
|
|
|
*/
|
|
|
|
int64_t aio_compute_timeout(AioContext *ctx);
|
|
|
|
|
2015-10-23 06:08:08 +03:00
|
|
|
/**
|
|
|
|
* aio_disable_external:
|
|
|
|
* @ctx: the aio context
|
|
|
|
*
|
|
|
|
* Disable the further processing of external clients.
|
|
|
|
*/
|
|
|
|
static inline void aio_disable_external(AioContext *ctx)
|
|
|
|
{
|
|
|
|
atomic_inc(&ctx->external_disable_cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* aio_enable_external:
|
|
|
|
* @ctx: the aio context
|
|
|
|
*
|
|
|
|
* Enable the processing of external clients.
|
|
|
|
*/
|
|
|
|
static inline void aio_enable_external(AioContext *ctx)
|
|
|
|
{
|
|
|
|
assert(ctx->external_disable_cnt > 0);
|
|
|
|
atomic_dec(&ctx->external_disable_cnt);
|
|
|
|
}
|
|
|
|
|
2015-10-30 07:06:27 +03:00
|
|
|
/**
|
|
|
|
* aio_external_disabled:
|
|
|
|
* @ctx: the aio context
|
|
|
|
*
|
|
|
|
* Return true if the external clients are disabled.
|
|
|
|
*/
|
|
|
|
static inline bool aio_external_disabled(AioContext *ctx)
|
|
|
|
{
|
|
|
|
return atomic_read(&ctx->external_disable_cnt);
|
|
|
|
}
|
|
|
|
|
2015-10-23 06:08:08 +03:00
|
|
|
/**
|
|
|
|
* aio_node_check:
|
|
|
|
* @ctx: the aio context
|
|
|
|
* @is_external: Whether or not the checked node is an external event source.
|
|
|
|
*
|
|
|
|
* Check if the node's is_external flag is okay to be polled by the ctx at this
|
|
|
|
* moment. True means green light.
|
|
|
|
*/
|
|
|
|
static inline bool aio_node_check(AioContext *ctx, bool is_external)
|
|
|
|
{
|
|
|
|
return !is_external || !atomic_read(&ctx->external_disable_cnt);
|
|
|
|
}
|
|
|
|
|
2015-10-30 07:06:28 +03:00
|
|
|
/**
|
|
|
|
* aio_context_setup:
|
|
|
|
* @ctx: the aio context
|
|
|
|
*
|
|
|
|
* Initialize the aio context.
|
|
|
|
*/
|
2016-07-15 13:28:44 +03:00
|
|
|
void aio_context_setup(AioContext *ctx);
|
2015-10-30 07:06:28 +03:00
|
|
|
|
2008-09-22 23:17:18 +04:00
|
|
|
#endif
|