Annotation of qemu/coroutine-gthread.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * GThread coroutine initialization code
                      3:  *
                      4:  * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
                      5:  * Copyright (C) 2011  Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
                      6:  *
                      7:  * This library is free software; you can redistribute it and/or
                      8:  * modify it under the terms of the GNU Lesser General Public
                      9:  * License as published by the Free Software Foundation; either
                     10:  * version 2.0 of the License, or (at your option) any later version.
                     11:  *
                     12:  * This library is distributed in the hope that it will be useful,
                     13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     15:  * Lesser General Public License for more details.
                     16:  *
                     17:  * You should have received a copy of the GNU Lesser General Public
                     18:  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
                     19:  */
                     20: 
                     21: #include <glib.h>
                     22: #include "qemu-common.h"
                     23: #include "qemu-coroutine-int.h"
                     24: 
                     25: typedef struct {
                     26:     Coroutine base;
                     27:     GThread *thread;
                     28:     bool runnable;
1.1.1.2 ! root       29:     bool free_on_thread_exit;
1.1       root       30:     CoroutineAction action;
                     31: } CoroutineGThread;
                     32: 
                     33: static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
1.1.1.2 ! root       34: 
        !            35: /* GLib 2.31 and beyond deprecated various parts of the thread API,
        !            36:  * but the new interfaces are not available in older GLib versions
        !            37:  * so we have to cope with both.
        !            38:  */
        !            39: #if GLIB_CHECK_VERSION(2, 31, 0)
        !            40: /* Default zero-initialisation is sufficient for 2.31+ GCond */
        !            41: static GCond the_coroutine_cond;
        !            42: static GCond *coroutine_cond = &the_coroutine_cond;
        !            43: static inline void init_coroutine_cond(void)
        !            44: {
        !            45: }
        !            46: 
        !            47: /* Awkwardly, the GPrivate API doesn't provide a way to update the
        !            48:  * GDestroyNotify handler for the coroutine key dynamically. So instead
        !            49:  * we track whether or not the CoroutineGThread should be freed on
        !            50:  * thread exit / coroutine key update using the free_on_thread_exit
        !            51:  * field.
        !            52:  */
        !            53: static void coroutine_destroy_notify(gpointer data)
        !            54: {
        !            55:     CoroutineGThread *co = data;
        !            56:     if (co && co->free_on_thread_exit) {
        !            57:         g_free(co);
        !            58:     }
        !            59: }
        !            60: 
        !            61: static GPrivate coroutine_key = G_PRIVATE_INIT(coroutine_destroy_notify);
        !            62: 
        !            63: static inline CoroutineGThread *get_coroutine_key(void)
        !            64: {
        !            65:     return g_private_get(&coroutine_key);
        !            66: }
        !            67: 
        !            68: static inline void set_coroutine_key(CoroutineGThread *co,
        !            69:                                      bool free_on_thread_exit)
        !            70: {
        !            71:     /* Unlike g_static_private_set() this does not call the GDestroyNotify
        !            72:      * if the previous value of the key was NULL. Fortunately we only need
        !            73:      * the GDestroyNotify in the non-NULL key case.
        !            74:      */
        !            75:     co->free_on_thread_exit = free_on_thread_exit;
        !            76:     g_private_replace(&coroutine_key, co);
        !            77: }
        !            78: 
        !            79: static inline GThread *create_thread(GThreadFunc func, gpointer data)
        !            80: {
        !            81:     return g_thread_new("coroutine", func, data);
        !            82: }
        !            83: 
        !            84: #else
        !            85: 
        !            86: /* Handle older GLib versions */
        !            87: static GCond *coroutine_cond;
        !            88: static inline void init_coroutine_cond(void)
        !            89: {
        !            90:     coroutine_cond = g_cond_new();
        !            91: }
        !            92: 
1.1       root       93: static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
                     94: 
1.1.1.2 ! root       95: static inline CoroutineGThread *get_coroutine_key(void)
        !            96: {
        !            97:     return g_static_private_get(&coroutine_key);
        !            98: }
        !            99: 
        !           100: static inline void set_coroutine_key(CoroutineGThread *co,
        !           101:                                      bool free_on_thread_exit)
        !           102: {
        !           103:     g_static_private_set(&coroutine_key, co,
        !           104:                          free_on_thread_exit ? (GDestroyNotify)g_free : NULL);
        !           105: }
        !           106: 
        !           107: static inline GThread *create_thread(GThreadFunc func, gpointer data)
        !           108: {
        !           109:     return g_thread_create_full(func, data, 0, TRUE, TRUE,
        !           110:                                 G_THREAD_PRIORITY_NORMAL, NULL);
        !           111: }
        !           112: 
        !           113: #endif
        !           114: 
        !           115: 
1.1       root      116: static void __attribute__((constructor)) coroutine_init(void)
                    117: {
                    118:     if (!g_thread_supported()) {
1.1.1.2 ! root      119: #if !GLIB_CHECK_VERSION(2, 31, 0)
1.1       root      120:         g_thread_init(NULL);
1.1.1.2 ! root      121: #else
        !           122:         fprintf(stderr, "glib threading failed to initialize.\n");
        !           123:         exit(1);
        !           124: #endif
1.1       root      125:     }
                    126: 
1.1.1.2 ! root      127:     init_coroutine_cond();
1.1       root      128: }
                    129: 
                    130: static void coroutine_wait_runnable_locked(CoroutineGThread *co)
                    131: {
                    132:     while (!co->runnable) {
                    133:         g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
                    134:     }
                    135: }
                    136: 
                    137: static void coroutine_wait_runnable(CoroutineGThread *co)
                    138: {
                    139:     g_static_mutex_lock(&coroutine_lock);
                    140:     coroutine_wait_runnable_locked(co);
                    141:     g_static_mutex_unlock(&coroutine_lock);
                    142: }
                    143: 
                    144: static gpointer coroutine_thread(gpointer opaque)
                    145: {
                    146:     CoroutineGThread *co = opaque;
                    147: 
1.1.1.2 ! root      148:     set_coroutine_key(co, false);
1.1       root      149:     coroutine_wait_runnable(co);
                    150:     co->base.entry(co->base.entry_arg);
                    151:     qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
                    152:     return NULL;
                    153: }
                    154: 
                    155: Coroutine *qemu_coroutine_new(void)
                    156: {
                    157:     CoroutineGThread *co;
                    158: 
                    159:     co = g_malloc0(sizeof(*co));
1.1.1.2 ! root      160:     co->thread = create_thread(coroutine_thread, co);
1.1       root      161:     if (!co->thread) {
                    162:         g_free(co);
                    163:         return NULL;
                    164:     }
                    165:     return &co->base;
                    166: }
                    167: 
                    168: void qemu_coroutine_delete(Coroutine *co_)
                    169: {
                    170:     CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_);
                    171: 
                    172:     g_thread_join(co->thread);
                    173:     g_free(co);
                    174: }
                    175: 
                    176: CoroutineAction qemu_coroutine_switch(Coroutine *from_,
                    177:                                       Coroutine *to_,
                    178:                                       CoroutineAction action)
                    179: {
                    180:     CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
                    181:     CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);
                    182: 
                    183:     g_static_mutex_lock(&coroutine_lock);
                    184:     from->runnable = false;
                    185:     from->action = action;
                    186:     to->runnable = true;
                    187:     to->action = action;
                    188:     g_cond_broadcast(coroutine_cond);
                    189: 
                    190:     if (action != COROUTINE_TERMINATE) {
                    191:         coroutine_wait_runnable_locked(from);
                    192:     }
                    193:     g_static_mutex_unlock(&coroutine_lock);
                    194:     return from->action;
                    195: }
                    196: 
                    197: Coroutine *qemu_coroutine_self(void)
                    198: {
1.1.1.2 ! root      199:     CoroutineGThread *co = get_coroutine_key();
1.1       root      200:     if (!co) {
                    201:         co = g_malloc0(sizeof(*co));
                    202:         co->runnable = true;
1.1.1.2 ! root      203:         set_coroutine_key(co, true);
1.1       root      204:     }
                    205: 
                    206:     return &co->base;
                    207: }
                    208: 
                    209: bool qemu_in_coroutine(void)
                    210: {
1.1.1.2 ! root      211:     CoroutineGThread *co = get_coroutine_key();
1.1       root      212: 
                    213:     return co && co->base.caller;
                    214: }

unix.superglobalmegacorp.com