qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

aio-wait.h (6429B)


      1 /*
      2  * AioContext wait support
      3  *
      4  * Copyright (C) 2018 Red Hat, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #ifndef QEMU_AIO_WAIT_H
     26 #define QEMU_AIO_WAIT_H
     27 
     28 #include "block/aio.h"
     29 #include "qemu/main-loop.h"
     30 
     31 /**
     32  * AioWait:
     33  *
     34  * An object that facilitates synchronous waiting on a condition. A single
     35  * global AioWait object (global_aio_wait) is used internally.
     36  *
     37  * The main loop can wait on an operation running in an IOThread as follows:
     38  *
     39  *   AioContext *ctx = ...;
     40  *   MyWork work = { .done = false };
     41  *   schedule_my_work_in_iothread(ctx, &work);
     42  *   AIO_WAIT_WHILE(ctx, !work.done);
     43  *
     44  * The IOThread must call aio_wait_kick() to notify the main loop when
     45  * work.done changes:
     46  *
     47  *   static void do_work(...)
     48  *   {
     49  *       ...
     50  *       work.done = true;
     51  *       aio_wait_kick();
     52  *   }
     53  */
     54 typedef struct {
     55     /* Number of waiting AIO_WAIT_WHILE() callers. Accessed with atomic ops. */
     56     unsigned num_waiters;
     57 } AioWait;
     58 
     59 extern AioWait global_aio_wait;
     60 
     61 /**
     62  * AIO_WAIT_WHILE_INTERNAL:
     63  * @ctx: the aio context, or NULL if multiple aio contexts (for which the
     64  *       caller does not hold a lock) are involved in the polling condition.
     65  * @cond: wait while this conditional expression is true
     66  * @unlock: whether to unlock and then lock again @ctx. This apples
     67  * only when waiting for another AioContext from the main loop.
     68  * Otherwise it's ignored.
     69  *
     70  * Wait while a condition is true.  Use this to implement synchronous
     71  * operations that require event loop activity.
     72  *
     73  * The caller must be sure that something calls aio_wait_kick() when the value
     74  * of @cond might have changed.
     75  *
     76  * The caller's thread must be the IOThread that owns @ctx or the main loop
     77  * thread (with @ctx acquired exactly once).  This function cannot be used to
     78  * wait on conditions between two IOThreads since that could lead to deadlock,
     79  * go via the main loop instead.
     80  */
     81 #define AIO_WAIT_WHILE_INTERNAL(ctx, cond, unlock) ({              \
     82     bool waited_ = false;                                          \
     83     AioWait *wait_ = &global_aio_wait;                             \
     84     AioContext *ctx_ = (ctx);                                      \
     85     /* Increment wait_->num_waiters before evaluating cond. */     \
     86     qatomic_inc(&wait_->num_waiters);                              \
     87     /* Paired with smp_mb in aio_wait_kick(). */                   \
     88     smp_mb();                                                      \
     89     if (ctx_ && in_aio_context_home_thread(ctx_)) {                \
     90         while ((cond)) {                                           \
     91             aio_poll(ctx_, true);                                  \
     92             waited_ = true;                                        \
     93         }                                                          \
     94     } else {                                                       \
     95         assert(qemu_get_current_aio_context() ==                   \
     96                qemu_get_aio_context());                            \
     97         while ((cond)) {                                           \
     98             if (unlock && ctx_) {                                  \
     99                 aio_context_release(ctx_);                         \
    100             }                                                      \
    101             aio_poll(qemu_get_aio_context(), true);                \
    102             if (unlock && ctx_) {                                  \
    103                 aio_context_acquire(ctx_);                         \
    104             }                                                      \
    105             waited_ = true;                                        \
    106         }                                                          \
    107     }                                                              \
    108     qatomic_dec(&wait_->num_waiters);                              \
    109     waited_; })
    110 
    111 #define AIO_WAIT_WHILE(ctx, cond)                                  \
    112     AIO_WAIT_WHILE_INTERNAL(ctx, cond, true)
    113 
    114 #define AIO_WAIT_WHILE_UNLOCKED(ctx, cond)                         \
    115     AIO_WAIT_WHILE_INTERNAL(ctx, cond, false)
    116 
    117 /**
    118  * aio_wait_kick:
    119  * Wake up the main thread if it is waiting on AIO_WAIT_WHILE().  During
    120  * synchronous operations performed in an IOThread, the main thread lets the
    121  * IOThread's event loop run, waiting for the operation to complete.  A
    122  * aio_wait_kick() call will wake up the main thread.
    123  */
    124 void aio_wait_kick(void);
    125 
    126 /**
    127  * aio_wait_bh_oneshot:
    128  * @ctx: the aio context
    129  * @cb: the BH callback function
    130  * @opaque: user data for the BH callback function
    131  *
    132  * Run a BH in @ctx and wait for it to complete.
    133  *
    134  * Must be called from the main loop thread with @ctx acquired exactly once.
    135  * Note that main loop event processing may occur.
    136  */
    137 void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
    138 
    139 /**
    140  * in_aio_context_home_thread:
    141  * @ctx: the aio context
    142  *
    143  * Return whether we are running in the thread that normally runs @ctx.  Note
    144  * that acquiring/releasing ctx does not affect the outcome, each AioContext
    145  * still only has one home thread that is responsible for running it.
    146  */
    147 static inline bool in_aio_context_home_thread(AioContext *ctx)
    148 {
    149     if (ctx == qemu_get_current_aio_context()) {
    150         return true;
    151     }
    152 
    153     if (ctx == qemu_get_aio_context()) {
    154         return qemu_mutex_iothread_locked();
    155     } else {
    156         return false;
    157     }
    158 }
    159 
    160 #endif /* QEMU_AIO_WAIT_H */