| /* | 
 |  * GThread coroutine initialization code | 
 |  * | 
 |  * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws> | 
 |  * Copyright (C) 2011  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.0 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, see <http://www.gnu.org/licenses/>. | 
 |  */ | 
 |  | 
 | #include <glib.h> | 
 | #include "qemu-common.h" | 
 | #include "block/coroutine_int.h" | 
 |  | 
 | typedef struct { | 
 |     Coroutine base; | 
 |     GThread *thread; | 
 |     bool runnable; | 
 |     bool free_on_thread_exit; | 
 |     CoroutineAction action; | 
 | } CoroutineGThread; | 
 |  | 
 | static CompatGMutex coroutine_lock; | 
 | static CompatGCond coroutine_cond; | 
 |  | 
 | /* GLib 2.31 and beyond deprecated various parts of the thread API, | 
 |  * but the new interfaces are not available in older GLib versions | 
 |  * so we have to cope with both. | 
 |  */ | 
 | #if GLIB_CHECK_VERSION(2, 31, 0) | 
 | /* Awkwardly, the GPrivate API doesn't provide a way to update the | 
 |  * GDestroyNotify handler for the coroutine key dynamically. So instead | 
 |  * we track whether or not the CoroutineGThread should be freed on | 
 |  * thread exit / coroutine key update using the free_on_thread_exit | 
 |  * field. | 
 |  */ | 
 | static void coroutine_destroy_notify(gpointer data) | 
 | { | 
 |     CoroutineGThread *co = data; | 
 |     if (co && co->free_on_thread_exit) { | 
 |         g_free(co); | 
 |     } | 
 | } | 
 |  | 
 | static GPrivate coroutine_key = G_PRIVATE_INIT(coroutine_destroy_notify); | 
 |  | 
 | static inline CoroutineGThread *get_coroutine_key(void) | 
 | { | 
 |     return g_private_get(&coroutine_key); | 
 | } | 
 |  | 
 | static inline void set_coroutine_key(CoroutineGThread *co, | 
 |                                      bool free_on_thread_exit) | 
 | { | 
 |     /* Unlike g_static_private_set() this does not call the GDestroyNotify | 
 |      * if the previous value of the key was NULL. Fortunately we only need | 
 |      * the GDestroyNotify in the non-NULL key case. | 
 |      */ | 
 |     co->free_on_thread_exit = free_on_thread_exit; | 
 |     g_private_replace(&coroutine_key, co); | 
 | } | 
 |  | 
 | static inline GThread *create_thread(GThreadFunc func, gpointer data) | 
 | { | 
 |     return g_thread_new("coroutine", func, data); | 
 | } | 
 |  | 
 | #else | 
 |  | 
 | /* Handle older GLib versions */ | 
 |  | 
 | static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT; | 
 |  | 
 | static inline CoroutineGThread *get_coroutine_key(void) | 
 | { | 
 |     return g_static_private_get(&coroutine_key); | 
 | } | 
 |  | 
 | static inline void set_coroutine_key(CoroutineGThread *co, | 
 |                                      bool free_on_thread_exit) | 
 | { | 
 |     g_static_private_set(&coroutine_key, co, | 
 |                          free_on_thread_exit ? (GDestroyNotify)g_free : NULL); | 
 | } | 
 |  | 
 | static inline GThread *create_thread(GThreadFunc func, gpointer data) | 
 | { | 
 |     return g_thread_create_full(func, data, 0, TRUE, TRUE, | 
 |                                 G_THREAD_PRIORITY_NORMAL, NULL); | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 |  | 
 | static void __attribute__((constructor)) coroutine_init(void) | 
 | { | 
 | #if !GLIB_CHECK_VERSION(2, 31, 0) | 
 |     if (!g_thread_supported()) { | 
 |         g_thread_init(NULL); | 
 |     } | 
 | #endif | 
 | } | 
 |  | 
 | static void coroutine_wait_runnable_locked(CoroutineGThread *co) | 
 | { | 
 |     while (!co->runnable) { | 
 |         g_cond_wait(&coroutine_cond, &coroutine_lock); | 
 |     } | 
 | } | 
 |  | 
 | static void coroutine_wait_runnable(CoroutineGThread *co) | 
 | { | 
 |     g_mutex_lock(&coroutine_lock); | 
 |     coroutine_wait_runnable_locked(co); | 
 |     g_mutex_unlock(&coroutine_lock); | 
 | } | 
 |  | 
 | static gpointer coroutine_thread(gpointer opaque) | 
 | { | 
 |     CoroutineGThread *co = opaque; | 
 |  | 
 |     set_coroutine_key(co, false); | 
 |     coroutine_wait_runnable(co); | 
 |     co->base.entry(co->base.entry_arg); | 
 |     qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE); | 
 |     return NULL; | 
 | } | 
 |  | 
 | Coroutine *qemu_coroutine_new(void) | 
 | { | 
 |     CoroutineGThread *co; | 
 |  | 
 |     co = g_malloc0(sizeof(*co)); | 
 |     co->thread = create_thread(coroutine_thread, co); | 
 |     if (!co->thread) { | 
 |         g_free(co); | 
 |         return NULL; | 
 |     } | 
 |     return &co->base; | 
 | } | 
 |  | 
 | void qemu_coroutine_delete(Coroutine *co_) | 
 | { | 
 |     CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_); | 
 |  | 
 |     g_thread_join(co->thread); | 
 |     g_free(co); | 
 | } | 
 |  | 
 | CoroutineAction qemu_coroutine_switch(Coroutine *from_, | 
 |                                       Coroutine *to_, | 
 |                                       CoroutineAction action) | 
 | { | 
 |     CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_); | 
 |     CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_); | 
 |  | 
 |     g_mutex_lock(&coroutine_lock); | 
 |     from->runnable = false; | 
 |     from->action = action; | 
 |     to->runnable = true; | 
 |     to->action = action; | 
 |     g_cond_broadcast(&coroutine_cond); | 
 |  | 
 |     if (action != COROUTINE_TERMINATE) { | 
 |         coroutine_wait_runnable_locked(from); | 
 |     } | 
 |     g_mutex_unlock(&coroutine_lock); | 
 |     return from->action; | 
 | } | 
 |  | 
 | Coroutine *qemu_coroutine_self(void) | 
 | { | 
 |     CoroutineGThread *co = get_coroutine_key(); | 
 |     if (!co) { | 
 |         co = g_malloc0(sizeof(*co)); | 
 |         co->runnable = true; | 
 |         set_coroutine_key(co, true); | 
 |     } | 
 |  | 
 |     return &co->base; | 
 | } | 
 |  | 
 | bool qemu_in_coroutine(void) | 
 | { | 
 |     CoroutineGThread *co = get_coroutine_key(); | 
 |  | 
 |     return co && co->base.caller; | 
 | } |