xref: /qemu/include/block/aio-wait.h (revision 3c18a92dc4b55ca8cc37a755ed119f11c0f34099)
17719f3c9SStefan Hajnoczi /*
27719f3c9SStefan Hajnoczi  * AioContext wait support
37719f3c9SStefan Hajnoczi  *
47719f3c9SStefan Hajnoczi  * Copyright (C) 2018 Red Hat, Inc.
57719f3c9SStefan Hajnoczi  *
67719f3c9SStefan Hajnoczi  * Permission is hereby granted, free of charge, to any person obtaining a copy
77719f3c9SStefan Hajnoczi  * of this software and associated documentation files (the "Software"), to deal
87719f3c9SStefan Hajnoczi  * in the Software without restriction, including without limitation the rights
97719f3c9SStefan Hajnoczi  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
107719f3c9SStefan Hajnoczi  * copies of the Software, and to permit persons to whom the Software is
117719f3c9SStefan Hajnoczi  * furnished to do so, subject to the following conditions:
127719f3c9SStefan Hajnoczi  *
137719f3c9SStefan Hajnoczi  * The above copyright notice and this permission notice shall be included in
147719f3c9SStefan Hajnoczi  * all copies or substantial portions of the Software.
157719f3c9SStefan Hajnoczi  *
167719f3c9SStefan Hajnoczi  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177719f3c9SStefan Hajnoczi  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187719f3c9SStefan Hajnoczi  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
197719f3c9SStefan Hajnoczi  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207719f3c9SStefan Hajnoczi  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
217719f3c9SStefan Hajnoczi  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
227719f3c9SStefan Hajnoczi  * THE SOFTWARE.
237719f3c9SStefan Hajnoczi  */
247719f3c9SStefan Hajnoczi 
257719f3c9SStefan Hajnoczi #ifndef QEMU_AIO_WAIT_H
267719f3c9SStefan Hajnoczi #define QEMU_AIO_WAIT_H
277719f3c9SStefan Hajnoczi 
287719f3c9SStefan Hajnoczi #include "block/aio.h"
29*3c18a92dSPaolo Bonzini #include "qemu/main-loop.h"
307719f3c9SStefan Hajnoczi 
317719f3c9SStefan Hajnoczi /**
327719f3c9SStefan Hajnoczi  * AioWait:
337719f3c9SStefan Hajnoczi  *
34cfe29d82SKevin Wolf  * An object that facilitates synchronous waiting on a condition. A single
35cfe29d82SKevin Wolf  * global AioWait object (global_aio_wait) is used internally.
367719f3c9SStefan Hajnoczi  *
37cfe29d82SKevin Wolf  * The main loop can wait on an operation running in an IOThread as follows:
38cfe29d82SKevin Wolf  *
397719f3c9SStefan Hajnoczi  *   AioContext *ctx = ...;
407719f3c9SStefan Hajnoczi  *   MyWork work = { .done = false };
417719f3c9SStefan Hajnoczi  *   schedule_my_work_in_iothread(ctx, &work);
42cfe29d82SKevin Wolf  *   AIO_WAIT_WHILE(ctx, !work.done);
437719f3c9SStefan Hajnoczi  *
447719f3c9SStefan Hajnoczi  * The IOThread must call aio_wait_kick() to notify the main loop when
457719f3c9SStefan Hajnoczi  * work.done changes:
467719f3c9SStefan Hajnoczi  *
477719f3c9SStefan Hajnoczi  *   static void do_work(...)
487719f3c9SStefan Hajnoczi  *   {
497719f3c9SStefan Hajnoczi  *       ...
507719f3c9SStefan Hajnoczi  *       work.done = true;
51cfe29d82SKevin Wolf  *       aio_wait_kick();
527719f3c9SStefan Hajnoczi  *   }
537719f3c9SStefan Hajnoczi  */
547719f3c9SStefan Hajnoczi typedef struct {
557376eda7SStefan Hajnoczi     /* Number of waiting AIO_WAIT_WHILE() callers. Accessed with atomic ops. */
567376eda7SStefan Hajnoczi     unsigned num_waiters;
577719f3c9SStefan Hajnoczi } AioWait;
587719f3c9SStefan Hajnoczi 
59cfe29d82SKevin Wolf extern AioWait global_aio_wait;
60cfe29d82SKevin Wolf 
617719f3c9SStefan Hajnoczi /**
627719f3c9SStefan Hajnoczi  * AIO_WAIT_WHILE:
634d22bbf4SKevin Wolf  * @ctx: the aio context, or NULL if multiple aio contexts (for which the
644d22bbf4SKevin Wolf  *       caller does not hold a lock) are involved in the polling condition.
657719f3c9SStefan Hajnoczi  * @cond: wait while this conditional expression is true
667719f3c9SStefan Hajnoczi  *
677719f3c9SStefan Hajnoczi  * Wait while a condition is true.  Use this to implement synchronous
687719f3c9SStefan Hajnoczi  * operations that require event loop activity.
697719f3c9SStefan Hajnoczi  *
707719f3c9SStefan Hajnoczi  * The caller must be sure that something calls aio_wait_kick() when the value
717719f3c9SStefan Hajnoczi  * of @cond might have changed.
727719f3c9SStefan Hajnoczi  *
737719f3c9SStefan Hajnoczi  * The caller's thread must be the IOThread that owns @ctx or the main loop
747719f3c9SStefan Hajnoczi  * thread (with @ctx acquired exactly once).  This function cannot be used to
757719f3c9SStefan Hajnoczi  * wait on conditions between two IOThreads since that could lead to deadlock,
767719f3c9SStefan Hajnoczi  * go via the main loop instead.
777719f3c9SStefan Hajnoczi  */
78cfe29d82SKevin Wolf #define AIO_WAIT_WHILE(ctx, cond) ({                               \
797719f3c9SStefan Hajnoczi     bool waited_ = false;                                          \
80cfe29d82SKevin Wolf     AioWait *wait_ = &global_aio_wait;                             \
817719f3c9SStefan Hajnoczi     AioContext *ctx_ = (ctx);                                      \
8248657448SKevin Wolf     /* Increment wait_->num_waiters before evaluating cond. */     \
8348657448SKevin Wolf     atomic_inc(&wait_->num_waiters);                               \
844d22bbf4SKevin Wolf     if (ctx_ && in_aio_context_home_thread(ctx_)) {                \
851cc8e54aSKevin Wolf         while ((cond)) {                                           \
861cc8e54aSKevin Wolf             aio_poll(ctx_, true);                                  \
871cc8e54aSKevin Wolf             waited_ = true;                                        \
887719f3c9SStefan Hajnoczi         }                                                          \
897719f3c9SStefan Hajnoczi     } else {                                                       \
907719f3c9SStefan Hajnoczi         assert(qemu_get_current_aio_context() ==                   \
917719f3c9SStefan Hajnoczi                qemu_get_aio_context());                            \
921cc8e54aSKevin Wolf         while ((cond)) {                                           \
934d22bbf4SKevin Wolf             if (ctx_) {                                            \
947719f3c9SStefan Hajnoczi                 aio_context_release(ctx_);                         \
954d22bbf4SKevin Wolf             }                                                      \
967719f3c9SStefan Hajnoczi             aio_poll(qemu_get_aio_context(), true);                \
974d22bbf4SKevin Wolf             if (ctx_) {                                            \
987719f3c9SStefan Hajnoczi                 aio_context_acquire(ctx_);                         \
994d22bbf4SKevin Wolf             }                                                      \
1001cc8e54aSKevin Wolf             waited_ = true;                                        \
1017719f3c9SStefan Hajnoczi         }                                                          \
1027719f3c9SStefan Hajnoczi     }                                                              \
10348657448SKevin Wolf     atomic_dec(&wait_->num_waiters);                               \
1047719f3c9SStefan Hajnoczi     waited_; })
1057719f3c9SStefan Hajnoczi 
1067719f3c9SStefan Hajnoczi /**
1077719f3c9SStefan Hajnoczi  * aio_wait_kick:
1087719f3c9SStefan Hajnoczi  * Wake up the main thread if it is waiting on AIO_WAIT_WHILE().  During
1097719f3c9SStefan Hajnoczi  * synchronous operations performed in an IOThread, the main thread lets the
1107719f3c9SStefan Hajnoczi  * IOThread's event loop run, waiting for the operation to complete.  A
1117719f3c9SStefan Hajnoczi  * aio_wait_kick() call will wake up the main thread.
1127719f3c9SStefan Hajnoczi  */
113cfe29d82SKevin Wolf void aio_wait_kick(void);
1147719f3c9SStefan Hajnoczi 
115b89d92f3SStefan Hajnoczi /**
116b89d92f3SStefan Hajnoczi  * aio_wait_bh_oneshot:
117b89d92f3SStefan Hajnoczi  * @ctx: the aio context
118b89d92f3SStefan Hajnoczi  * @cb: the BH callback function
119b89d92f3SStefan Hajnoczi  * @opaque: user data for the BH callback function
120b89d92f3SStefan Hajnoczi  *
121b89d92f3SStefan Hajnoczi  * Run a BH in @ctx and wait for it to complete.
122b89d92f3SStefan Hajnoczi  *
123b89d92f3SStefan Hajnoczi  * Must be called from the main loop thread with @ctx acquired exactly once.
124b89d92f3SStefan Hajnoczi  * Note that main loop event processing may occur.
125b89d92f3SStefan Hajnoczi  */
126b89d92f3SStefan Hajnoczi void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
127b89d92f3SStefan Hajnoczi 
128*3c18a92dSPaolo Bonzini /**
129*3c18a92dSPaolo Bonzini  * in_aio_context_home_thread:
130*3c18a92dSPaolo Bonzini  * @ctx: the aio context
131*3c18a92dSPaolo Bonzini  *
132*3c18a92dSPaolo Bonzini  * Return whether we are running in the thread that normally runs @ctx.  Note
133*3c18a92dSPaolo Bonzini  * that acquiring/releasing ctx does not affect the outcome, each AioContext
134*3c18a92dSPaolo Bonzini  * still only has one home thread that is responsible for running it.
135*3c18a92dSPaolo Bonzini  */
136*3c18a92dSPaolo Bonzini static inline bool in_aio_context_home_thread(AioContext *ctx)
137*3c18a92dSPaolo Bonzini {
138*3c18a92dSPaolo Bonzini     if (ctx == qemu_get_current_aio_context()) {
139*3c18a92dSPaolo Bonzini         return true;
140*3c18a92dSPaolo Bonzini     }
141*3c18a92dSPaolo Bonzini 
142*3c18a92dSPaolo Bonzini     if (ctx == qemu_get_aio_context()) {
143*3c18a92dSPaolo Bonzini         return qemu_mutex_iothread_locked();
144*3c18a92dSPaolo Bonzini     } else {
145*3c18a92dSPaolo Bonzini         return false;
146*3c18a92dSPaolo Bonzini     }
147*3c18a92dSPaolo Bonzini }
148*3c18a92dSPaolo Bonzini 
1496834c3f4SMarkus Armbruster #endif /* QEMU_AIO_WAIT_H */
150