xref: /qemu/include/block/aio-wait.h (revision cfe29d8294e06420e15d4938421ae006c8ac49e7)
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"
297719f3c9SStefan Hajnoczi 
307719f3c9SStefan Hajnoczi /**
317719f3c9SStefan Hajnoczi  * AioWait:
327719f3c9SStefan Hajnoczi  *
33*cfe29d82SKevin Wolf  * An object that facilitates synchronous waiting on a condition. A single
34*cfe29d82SKevin Wolf  * global AioWait object (global_aio_wait) is used internally.
357719f3c9SStefan Hajnoczi  *
36*cfe29d82SKevin Wolf  * The main loop can wait on an operation running in an IOThread as follows:
37*cfe29d82SKevin Wolf  *
387719f3c9SStefan Hajnoczi  *   AioContext *ctx = ...;
397719f3c9SStefan Hajnoczi  *   MyWork work = { .done = false };
407719f3c9SStefan Hajnoczi  *   schedule_my_work_in_iothread(ctx, &work);
41*cfe29d82SKevin Wolf  *   AIO_WAIT_WHILE(ctx, !work.done);
427719f3c9SStefan Hajnoczi  *
437719f3c9SStefan Hajnoczi  * The IOThread must call aio_wait_kick() to notify the main loop when
447719f3c9SStefan Hajnoczi  * work.done changes:
457719f3c9SStefan Hajnoczi  *
467719f3c9SStefan Hajnoczi  *   static void do_work(...)
477719f3c9SStefan Hajnoczi  *   {
487719f3c9SStefan Hajnoczi  *       ...
497719f3c9SStefan Hajnoczi  *       work.done = true;
50*cfe29d82SKevin Wolf  *       aio_wait_kick();
517719f3c9SStefan Hajnoczi  *   }
527719f3c9SStefan Hajnoczi  */
537719f3c9SStefan Hajnoczi typedef struct {
547376eda7SStefan Hajnoczi     /* Number of waiting AIO_WAIT_WHILE() callers. Accessed with atomic ops. */
557376eda7SStefan Hajnoczi     unsigned num_waiters;
567719f3c9SStefan Hajnoczi } AioWait;
577719f3c9SStefan Hajnoczi 
58*cfe29d82SKevin Wolf extern AioWait global_aio_wait;
59*cfe29d82SKevin Wolf 
607719f3c9SStefan Hajnoczi /**
617719f3c9SStefan Hajnoczi  * AIO_WAIT_WHILE:
624d22bbf4SKevin Wolf  * @ctx: the aio context, or NULL if multiple aio contexts (for which the
634d22bbf4SKevin Wolf  *       caller does not hold a lock) are involved in the polling condition.
647719f3c9SStefan Hajnoczi  * @cond: wait while this conditional expression is true
657719f3c9SStefan Hajnoczi  *
667719f3c9SStefan Hajnoczi  * Wait while a condition is true.  Use this to implement synchronous
677719f3c9SStefan Hajnoczi  * operations that require event loop activity.
687719f3c9SStefan Hajnoczi  *
697719f3c9SStefan Hajnoczi  * The caller must be sure that something calls aio_wait_kick() when the value
707719f3c9SStefan Hajnoczi  * of @cond might have changed.
717719f3c9SStefan Hajnoczi  *
727719f3c9SStefan Hajnoczi  * The caller's thread must be the IOThread that owns @ctx or the main loop
737719f3c9SStefan Hajnoczi  * thread (with @ctx acquired exactly once).  This function cannot be used to
747719f3c9SStefan Hajnoczi  * wait on conditions between two IOThreads since that could lead to deadlock,
757719f3c9SStefan Hajnoczi  * go via the main loop instead.
767719f3c9SStefan Hajnoczi  */
77*cfe29d82SKevin Wolf #define AIO_WAIT_WHILE(ctx, cond) ({                               \
787719f3c9SStefan Hajnoczi     bool waited_ = false;                                          \
79*cfe29d82SKevin Wolf     AioWait *wait_ = &global_aio_wait;                             \
807719f3c9SStefan Hajnoczi     AioContext *ctx_ = (ctx);                                      \
8148657448SKevin Wolf     /* Increment wait_->num_waiters before evaluating cond. */     \
8248657448SKevin Wolf     atomic_inc(&wait_->num_waiters);                               \
834d22bbf4SKevin Wolf     if (ctx_ && in_aio_context_home_thread(ctx_)) {                \
841cc8e54aSKevin Wolf         while ((cond)) {                                           \
851cc8e54aSKevin Wolf             aio_poll(ctx_, true);                                  \
861cc8e54aSKevin Wolf             waited_ = true;                                        \
877719f3c9SStefan Hajnoczi         }                                                          \
887719f3c9SStefan Hajnoczi     } else {                                                       \
897719f3c9SStefan Hajnoczi         assert(qemu_get_current_aio_context() ==                   \
907719f3c9SStefan Hajnoczi                qemu_get_aio_context());                            \
911cc8e54aSKevin Wolf         while ((cond)) {                                           \
924d22bbf4SKevin Wolf             if (ctx_) {                                            \
937719f3c9SStefan Hajnoczi                 aio_context_release(ctx_);                         \
944d22bbf4SKevin Wolf             }                                                      \
957719f3c9SStefan Hajnoczi             aio_poll(qemu_get_aio_context(), true);                \
964d22bbf4SKevin Wolf             if (ctx_) {                                            \
977719f3c9SStefan Hajnoczi                 aio_context_acquire(ctx_);                         \
984d22bbf4SKevin Wolf             }                                                      \
991cc8e54aSKevin Wolf             waited_ = true;                                        \
1007719f3c9SStefan Hajnoczi         }                                                          \
1017719f3c9SStefan Hajnoczi     }                                                              \
10248657448SKevin Wolf     atomic_dec(&wait_->num_waiters);                               \
1037719f3c9SStefan Hajnoczi     waited_; })
1047719f3c9SStefan Hajnoczi 
1057719f3c9SStefan Hajnoczi /**
1067719f3c9SStefan Hajnoczi  * aio_wait_kick:
1077719f3c9SStefan Hajnoczi  * Wake up the main thread if it is waiting on AIO_WAIT_WHILE().  During
1087719f3c9SStefan Hajnoczi  * synchronous operations performed in an IOThread, the main thread lets the
1097719f3c9SStefan Hajnoczi  * IOThread's event loop run, waiting for the operation to complete.  A
1107719f3c9SStefan Hajnoczi  * aio_wait_kick() call will wake up the main thread.
1117719f3c9SStefan Hajnoczi  */
112*cfe29d82SKevin Wolf void aio_wait_kick(void);
1137719f3c9SStefan Hajnoczi 
114b89d92f3SStefan Hajnoczi /**
115b89d92f3SStefan Hajnoczi  * aio_wait_bh_oneshot:
116b89d92f3SStefan Hajnoczi  * @ctx: the aio context
117b89d92f3SStefan Hajnoczi  * @cb: the BH callback function
118b89d92f3SStefan Hajnoczi  * @opaque: user data for the BH callback function
119b89d92f3SStefan Hajnoczi  *
120b89d92f3SStefan Hajnoczi  * Run a BH in @ctx and wait for it to complete.
121b89d92f3SStefan Hajnoczi  *
122b89d92f3SStefan Hajnoczi  * Must be called from the main loop thread with @ctx acquired exactly once.
123b89d92f3SStefan Hajnoczi  * Note that main loop event processing may occur.
124b89d92f3SStefan Hajnoczi  */
125b89d92f3SStefan Hajnoczi void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
126b89d92f3SStefan Hajnoczi 
1277719f3c9SStefan Hajnoczi #endif /* QEMU_AIO_WAIT */
128