qemu/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-common.h"
  26#include "qemu-coroutine-int.h"
  27
  28typedef struct
  29{
  30    Coroutine base;
  31
  32    LPVOID fiber;
  33    CoroutineAction action;
  34} CoroutineWin32;
  35
  36static __thread CoroutineWin32 leader;
  37static __thread Coroutine *current;
  38
  39CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
  40                                      CoroutineAction action)
  41{
  42    CoroutineWin32 *from = DO_UPCAST(CoroutineWin32, base, from_);
  43    CoroutineWin32 *to = DO_UPCAST(CoroutineWin32, base, to_);
  44
  45    current = to_;
  46
  47    to->action = action;
  48    SwitchToFiber(to->fiber);
  49    return from->action;
  50}
  51
  52static void CALLBACK coroutine_trampoline(void *co_)
  53{
  54    Coroutine *co = co_;
  55
  56    while (true) {
  57        co->entry(co->entry_arg);
  58        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
  59    }
  60}
  61
  62Coroutine *qemu_coroutine_new(void)
  63{
  64    const size_t stack_size = 1 << 20;
  65    CoroutineWin32 *co;
  66
  67    co = g_malloc0(sizeof(*co));
  68    co->fiber = CreateFiber(stack_size, coroutine_trampoline, &co->base);
  69    return &co->base;
  70}
  71
  72void qemu_coroutine_delete(Coroutine *co_)
  73{
  74    CoroutineWin32 *co = DO_UPCAST(CoroutineWin32, base, co_);
  75
  76    DeleteFiber(co->fiber);
  77    g_free(co);
  78}
  79
  80Coroutine *qemu_coroutine_self(void)
  81{
  82    if (!current) {
  83        current = &leader.base;
  84        leader.fiber = ConvertThreadToFiber(NULL);
  85    }
  86    return current;
  87}
  88
  89bool qemu_in_coroutine(void)
  90{
  91    return current && current->caller;
  92}
  93