qemu/util/coroutine-win32.c
<<
>>
Prefs
   1/*
   2 * Win32 coroutine initialization code
   3 *
   4 * Copyright (c) 2011 Kevin Wolf <kwolf@redhat.com>
   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#include "qemu/osdep.h"
  26#include "qemu-common.h"
  27#include "qemu/coroutine_int.h"
  28
  29typedef struct
  30{
  31    Coroutine base;
  32
  33    LPVOID fiber;
  34    CoroutineAction action;
  35} CoroutineWin32;
  36
  37static __thread CoroutineWin32 leader;
  38static __thread Coroutine *current;
  39
  40/* This function is marked noinline to prevent GCC from inlining it
  41 * into coroutine_trampoline(). If we allow it to do that then it
  42 * hoists the code to get the address of the TLS variable "current"
  43 * out of the while() loop. This is an invalid transformation because
  44 * the SwitchToFiber() call may be called when running thread A but
  45 * return in thread B, and so we might be in a different thread
  46 * context each time round the loop.
  47 */
  48CoroutineAction __attribute__((noinline))
  49qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
  50                      CoroutineAction action)
  51{
  52    CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
  53    CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
  54
  55    current = to_;
  56
  57    to->action = action;
  58    SwitchToFiber(to->fiber);
  59    return from->action;
  60}
  61
  62static void CALLBACK coroutine_trampoline(void *co_)
  63{
  64    Coroutine *co = co_;
  65
  66    while (true) {
  67        co->entry(co->entry_arg);
  68        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
  69    }
  70}
  71
  72Coroutine *qemu_coroutine_new(void)
  73{
  74    const size_t stack_size = COROUTINE_STACK_SIZE;
  75    CoroutineWin32 *co;
  76
  77    co = g_malloc0(sizeof(*co));
  78    co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
  79    return &co->base;
  80}
  81
  82void qemu_coroutine_delete(Coroutine *co_)
  83{
  84    CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
  85
  86    DeleteFiber(co->fiber);
  87    g_free(co);
  88}
  89
  90Coroutine *qemu_coroutine_self(void)
  91{
  92    if (!current) {
  93        current = &leader.base;
  94        leader.fiber = ConvertThreadToFiber(NULL);
  95    }
  96    return current;
  97}
  98
  99bool qemu_in_coroutine(void)
 100{
 101    return current && current->caller;
 102}
 103