diff options
Diffstat (limited to 'include/qemu/main-loop.h')
-rw-r--r-- | include/qemu/main-loop.h | 178 |
1 files changed, 142 insertions, 36 deletions
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index e59f9ae1e9..5764db157c 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -26,9 +26,19 @@ #define QEMU_MAIN_LOOP_H #include "block/aio.h" +#include "qom/object.h" +#include "sysemu/event-loop-base.h" #define SIG_IPI SIGUSR1 +#define TYPE_MAIN_LOOP "main-loop" +OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP) + +struct MainLoop { + EventLoopBase parent_obj; +}; +typedef struct MainLoop MainLoop; + /** * qemu_init_main_loop: Set up the process so that it can run the main loop. * @@ -52,7 +62,7 @@ int qemu_init_main_loop(Error **errp); * repeatedly calls main_loop_wait(false). * * Main loop services include file descriptor callbacks, bottom halves - * and timers (defined in qemu-timer.h). Bottom halves are similar to timers + * and timers (defined in qemu/timer.h). Bottom halves are similar to timers * that execute immediately, but have a lower overhead and scheduling them * is wait-free, thread-safe and signal-safe. * @@ -147,6 +157,8 @@ typedef void WaitObjectFunc(void *opaque); * in the main loop's calls to WaitForMultipleObjects. When the handle * is in a signaled state, QEMU will call @func. * + * If the same HANDLE is added twice, this function returns -1. + * * @handle: The Windows handle to be observed. * @func: A function to be called when @handle is in a signaled state. * @opaque: A pointer-size value that is passed to @func. @@ -234,72 +246,166 @@ void event_notifier_set_handler(EventNotifier *e, GSource *iohandler_get_g_source(void); AioContext *iohandler_get_aio_context(void); -#ifdef CONFIG_POSIX + /** - * qemu_add_child_watch: Register a child process for reaping. - * - * Under POSIX systems, a parent process must read the exit status of - * its child processes using waitpid, or the operating system will not - * free some of the resources attached to that process. + * bql_locked: Return lock status of the Big QEMU Lock (BQL) * - * This function directs the QEMU main loop to observe a child process - * and call waitpid as soon as it exits; the watch is then removed - * automatically. It is useful whenever QEMU forks a child process - * but will find out about its termination by other means such as a - * "broken pipe". + * The Big QEMU Lock (BQL) is the coarsest lock in QEMU, and as such it + * must always be taken outside other locks. This function helps + * functions take different paths depending on whether the current + * thread is running within the BQL. * - * @pid: The pid that QEMU should observe. + * This function should never be used in the block layer, because + * unit tests, block layer tools and qemu-storage-daemon do not + * have a BQL. + * Please instead refer to qemu_in_main_thread(). */ -int qemu_add_child_watch(pid_t pid); -#endif +bool bql_locked(void); /** - * qemu_mutex_iothread_locked: Return lock status of the main loop mutex. + * qemu_in_main_thread: return whether it's possible to safely access + * the global state of the block layer. * - * The main loop mutex is the coarsest lock in QEMU, and as such it - * must always be taken outside other locks. This function helps - * functions take different paths depending on whether the current - * thread is running within the main loop mutex. + * Global state of the block layer is not accessible from I/O threads + * or worker threads; only from threads that "own" the default + * AioContext that qemu_get_aio_context() returns. For tests, block + * layer tools and qemu-storage-daemon there is a designated thread that + * runs the event loop for qemu_get_aio_context(), and that is the + * main thread. + * + * For emulators, however, any thread that holds the BQL can act + * as the block layer main thread; this will be any of the actual + * main thread, the vCPU threads or the RCU thread. + * + * For clarity, do not use this function outside the block layer. + */ +bool qemu_in_main_thread(void); + +/* + * Mark and check that the function is part of the Global State API. + * Please refer to include/block/block-global-state.h for more + * information about GS API. + */ +#define GLOBAL_STATE_CODE() \ + do { \ + assert(qemu_in_main_thread()); \ + } while (0) + +/* + * Mark and check that the function is part of the I/O API. + * Please refer to include/block/block-io.h for more + * information about IO API. + */ +#define IO_CODE() \ + do { \ + /* nop */ \ + } while (0) + +/* + * Mark and check that the function is part of the "I/O OR GS" API. + * Please refer to include/block/block-io.h for more + * information about "IO or GS" API. */ -bool qemu_mutex_iothread_locked(void); +#define IO_OR_GS_CODE() \ + do { \ + /* nop */ \ + } while (0) /** - * qemu_mutex_lock_iothread: Lock the main loop mutex. + * bql_lock: Lock the Big QEMU Lock (BQL). * - * This function locks the main loop mutex. The mutex is taken by + * This function locks the Big QEMU Lock (BQL). The lock is taken by * main() in vl.c and always taken except while waiting on - * external events (such as with select). The mutex should be taken + * external events (such as with select). The lock should be taken * by threads other than the main loop thread when calling * qemu_bh_new(), qemu_set_fd_handler() and basically all other * functions documented in this file. * - * NOTE: tools currently are single-threaded and qemu_mutex_lock_iothread + * NOTE: tools currently are single-threaded and bql_lock * is a no-op there. */ -#define qemu_mutex_lock_iothread() \ - qemu_mutex_lock_iothread_impl(__FILE__, __LINE__) -void qemu_mutex_lock_iothread_impl(const char *file, int line); +#define bql_lock() bql_lock_impl(__FILE__, __LINE__) +void bql_lock_impl(const char *file, int line); /** - * qemu_mutex_unlock_iothread: Unlock the main loop mutex. + * bql_unlock: Unlock the Big QEMU Lock (BQL). * - * This function unlocks the main loop mutex. The mutex is taken by + * This function unlocks the Big QEMU Lock. The lock is taken by * main() in vl.c and always taken except while waiting on - * external events (such as with select). The mutex should be unlocked + * external events (such as with select). The lock should be unlocked * as soon as possible by threads other than the main loop thread, * because it prevents the main loop from processing callbacks, * including timers and bottom halves. * - * NOTE: tools currently are single-threaded and qemu_mutex_unlock_iothread + * NOTE: tools currently are single-threaded and bql_unlock * is a no-op there. */ -void qemu_mutex_unlock_iothread(void); +void bql_unlock(void); -/* internal interfaces */ +/** + * BQL_LOCK_GUARD + * + * Wrap a block of code in a conditional bql_{lock,unlock}. + */ +typedef struct BQLLockAuto BQLLockAuto; + +static inline BQLLockAuto *bql_auto_lock(const char *file, int line) +{ + if (bql_locked()) { + return NULL; + } + bql_lock_impl(file, line); + /* Anything non-NULL causes the cleanup function to be called */ + return (BQLLockAuto *)(uintptr_t)1; +} + +static inline void bql_auto_unlock(BQLLockAuto *l) +{ + bql_unlock(); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(BQLLockAuto, bql_auto_unlock) + +#define BQL_LOCK_GUARD() \ + g_autoptr(BQLLockAuto) _bql_lock_auto __attribute__((unused)) \ + = bql_auto_lock(__FILE__, __LINE__) + +/* + * qemu_cond_wait_bql: Wait on condition for the Big QEMU Lock (BQL) + * + * This function atomically releases the Big QEMU Lock (BQL) and causes + * the calling thread to block on the condition. + */ +void qemu_cond_wait_bql(QemuCond *cond); + +/* + * qemu_cond_timedwait_bql: like the previous, but with timeout + */ +void qemu_cond_timedwait_bql(QemuCond *cond, int ms); -void qemu_fd_register(int fd); +/* internal interfaces */ -QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +#define qemu_bh_new_guarded(cb, opaque, guard) \ + qemu_bh_new_full((cb), (opaque), (stringify(cb)), guard) +#define qemu_bh_new(cb, opaque) \ + qemu_bh_new_full((cb), (opaque), (stringify(cb)), NULL) +QEMUBH *qemu_bh_new_full(QEMUBHFunc *cb, void *opaque, const char *name, + MemReentrancyGuard *reentrancy_guard); void qemu_bh_schedule_idle(QEMUBH *bh); +enum { + MAIN_LOOP_POLL_FILL, + MAIN_LOOP_POLL_ERR, + MAIN_LOOP_POLL_OK, +}; + +typedef struct MainLoopPoll { + int state; + uint32_t timeout; + GArray *pollfds; +} MainLoopPoll; + +void main_loop_poll_add_notifier(Notifier *notify); +void main_loop_poll_remove_notifier(Notifier *notify); + #endif |