File:  [Qemu by Fabrice Bellard] / qemu / coroutine-gthread.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:17:20 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    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;
   29:     CoroutineAction action;
   30: } CoroutineGThread;
   31: 
   32: static GCond *coroutine_cond;
   33: static GStaticMutex coroutine_lock = G_STATIC_MUTEX_INIT;
   34: static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT;
   35: 
   36: static void __attribute__((constructor)) coroutine_init(void)
   37: {
   38:     if (!g_thread_supported()) {
   39:         g_thread_init(NULL);
   40:     }
   41: 
   42:     coroutine_cond = g_cond_new();
   43: }
   44: 
   45: static void coroutine_wait_runnable_locked(CoroutineGThread *co)
   46: {
   47:     while (!co->runnable) {
   48:         g_cond_wait(coroutine_cond, g_static_mutex_get_mutex(&coroutine_lock));
   49:     }
   50: }
   51: 
   52: static void coroutine_wait_runnable(CoroutineGThread *co)
   53: {
   54:     g_static_mutex_lock(&coroutine_lock);
   55:     coroutine_wait_runnable_locked(co);
   56:     g_static_mutex_unlock(&coroutine_lock);
   57: }
   58: 
   59: static gpointer coroutine_thread(gpointer opaque)
   60: {
   61:     CoroutineGThread *co = opaque;
   62: 
   63:     g_static_private_set(&coroutine_key, co, NULL);
   64:     coroutine_wait_runnable(co);
   65:     co->base.entry(co->base.entry_arg);
   66:     qemu_coroutine_switch(&co->base, co->base.caller, COROUTINE_TERMINATE);
   67:     return NULL;
   68: }
   69: 
   70: Coroutine *qemu_coroutine_new(void)
   71: {
   72:     CoroutineGThread *co;
   73: 
   74:     co = g_malloc0(sizeof(*co));
   75:     co->thread = g_thread_create_full(coroutine_thread, co, 0, TRUE, TRUE,
   76:                                       G_THREAD_PRIORITY_NORMAL, NULL);
   77:     if (!co->thread) {
   78:         g_free(co);
   79:         return NULL;
   80:     }
   81:     return &co->base;
   82: }
   83: 
   84: void qemu_coroutine_delete(Coroutine *co_)
   85: {
   86:     CoroutineGThread *co = DO_UPCAST(CoroutineGThread, base, co_);
   87: 
   88:     g_thread_join(co->thread);
   89:     g_free(co);
   90: }
   91: 
   92: CoroutineAction qemu_coroutine_switch(Coroutine *from_,
   93:                                       Coroutine *to_,
   94:                                       CoroutineAction action)
   95: {
   96:     CoroutineGThread *from = DO_UPCAST(CoroutineGThread, base, from_);
   97:     CoroutineGThread *to = DO_UPCAST(CoroutineGThread, base, to_);
   98: 
   99:     g_static_mutex_lock(&coroutine_lock);
  100:     from->runnable = false;
  101:     from->action = action;
  102:     to->runnable = true;
  103:     to->action = action;
  104:     g_cond_broadcast(coroutine_cond);
  105: 
  106:     if (action != COROUTINE_TERMINATE) {
  107:         coroutine_wait_runnable_locked(from);
  108:     }
  109:     g_static_mutex_unlock(&coroutine_lock);
  110:     return from->action;
  111: }
  112: 
  113: Coroutine *qemu_coroutine_self(void)
  114: {
  115:     CoroutineGThread *co = g_static_private_get(&coroutine_key);
  116: 
  117:     if (!co) {
  118:         co = g_malloc0(sizeof(*co));
  119:         co->runnable = true;
  120:         g_static_private_set(&coroutine_key, co, (GDestroyNotify)g_free);
  121:     }
  122: 
  123:     return &co->base;
  124: }
  125: 
  126: bool qemu_in_coroutine(void)
  127: {
  128:     CoroutineGThread *co = g_static_private_get(&coroutine_key);
  129: 
  130:     return co && co->base.caller;
  131: }

unix.superglobalmegacorp.com