docs: remove AioContext lock from IOThread docs

Encourage the use of locking primitives and stop mentioning the
AioContext lock since it is being removed.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-ID: <20231205182011.1976568-12-stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2023-12-05 13:20:08 -05:00 committed by Kevin Wolf
parent 9f8d2fdcce
commit e0444c276a

View file

@ -88,27 +88,18 @@ loop, depending on which AioContext instance the caller passes in.
How to synchronize with an IOThread
-----------------------------------
AioContext is not thread-safe so some rules must be followed when using file
descriptors, event notifiers, timers, or BHs across threads:
Variables that can be accessed by multiple threads require some form of
synchronization such as qemu_mutex_lock(), rcu_read_lock(), etc.
1. AioContext functions can always be called safely. They handle their
own locking internally.
2. Other threads wishing to access the AioContext must use
aio_context_acquire()/aio_context_release() for mutual exclusion. Once the
context is acquired no other thread can access it or run event loop iterations
in this AioContext.
Legacy code sometimes nests aio_context_acquire()/aio_context_release() calls.
Do not use nesting anymore, it is incompatible with the BDRV_POLL_WHILE() macro
used in the block layer and can lead to hangs.
There is currently no lock ordering rule if a thread needs to acquire multiple
AioContexts simultaneously. Therefore, it is only safe for code holding the
QEMU global mutex to acquire other AioContexts.
AioContext functions like aio_set_fd_handler(), aio_set_event_notifier(),
aio_bh_new(), and aio_timer_new() are thread-safe. They can be used to trigger
activity in an IOThread.
Side note: the best way to schedule a function call across threads is to call
aio_bh_schedule_oneshot(). No acquire/release or locking is needed.
aio_bh_schedule_oneshot().
The main loop thread can wait synchronously for a condition using
AIO_WAIT_WHILE().
AioContext and the block layer
------------------------------
@ -124,22 +115,16 @@ Block layer code must therefore expect to run in an IOThread and avoid using
old APIs that implicitly use the main loop. See the "How to program for
IOThreads" above for information on how to do that.
If main loop code such as a QMP function wishes to access a BlockDriverState
it must first call aio_context_acquire(bdrv_get_aio_context(bs)) to ensure
that callbacks in the IOThread do not run in parallel.
Code running in the monitor typically needs to ensure that past
requests from the guest are completed. When a block device is running
in an IOThread, the IOThread can also process requests from the guest
(via ioeventfd). To achieve both objects, wrap the code between
bdrv_drained_begin() and bdrv_drained_end(), thus creating a "drained
section". The functions must be called between aio_context_acquire()
and aio_context_release(). You can freely release and re-acquire the
AioContext within a drained section.
section".
Long-running jobs (usually in the form of coroutines) are best scheduled in
the BlockDriverState's AioContext to avoid the need to acquire/release around
each bdrv_*() call. The functions bdrv_add/remove_aio_context_notifier,
or alternatively blk_add/remove_aio_context_notifier if you use BlockBackends,
can be used to get a notification whenever bdrv_try_change_aio_context() moves a
Long-running jobs (usually in the form of coroutines) are often scheduled in
the BlockDriverState's AioContext. The functions
bdrv_add/remove_aio_context_notifier, or alternatively
blk_add/remove_aio_context_notifier if you use BlockBackends, can be used to
get a notification whenever bdrv_try_change_aio_context() moves a
BlockDriverState to a different AioContext.