mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-gtk
synced 2026-02-04 04:58:16 +00:00
164 lines
3.6 KiB
C
164 lines
3.6 KiB
C
/*
|
|
* GTK VNC Widget
|
|
*
|
|
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "coroutine.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
static GCond *run_cond;
|
|
static GMutex *run_lock;
|
|
static struct coroutine *current;
|
|
static struct coroutine leader;
|
|
|
|
#if 0
|
|
#define CO_DEBUG(OP) fprintf(stderr, "%s %p %s %d\n", OP, g_thread_self(), __FUNCTION__, __LINE__)
|
|
#else
|
|
#define CO_DEBUG(OP)
|
|
#endif
|
|
|
|
static void coroutine_system_init(void)
|
|
{
|
|
if (!g_thread_supported()) {
|
|
CO_DEBUG("INIT");
|
|
g_thread_init(NULL);
|
|
}
|
|
|
|
|
|
run_cond = g_cond_new();
|
|
run_lock = g_mutex_new();
|
|
CO_DEBUG("LOCK");
|
|
g_mutex_lock(run_lock);
|
|
|
|
/* The thread that creates the first coroutine is the system coroutine
|
|
* so let's fill out a structure for it */
|
|
leader.entry = NULL;
|
|
leader.release = NULL;
|
|
leader.stack_size = 0;
|
|
leader.exited = 0;
|
|
leader.thread = g_thread_self();
|
|
leader.runnable = TRUE; /* we're the one running right now */
|
|
leader.caller = NULL;
|
|
leader.data = NULL;
|
|
|
|
current = &leader;
|
|
}
|
|
|
|
static gpointer coroutine_thread(gpointer opaque)
|
|
{
|
|
struct coroutine *co = opaque;
|
|
CO_DEBUG("LOCK");
|
|
g_mutex_lock(run_lock);
|
|
while (!co->runnable) {
|
|
CO_DEBUG("WAIT");
|
|
g_cond_wait(run_cond, run_lock);
|
|
}
|
|
|
|
CO_DEBUG("RUNNABLE");
|
|
current = co;
|
|
co->data = co->entry(co->data);
|
|
co->exited = 1;
|
|
|
|
co->caller->runnable = TRUE;
|
|
CO_DEBUG("BROADCAST");
|
|
g_cond_broadcast(run_cond);
|
|
CO_DEBUG("UNLOCK");
|
|
g_mutex_unlock(run_lock);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int coroutine_init(struct coroutine *co)
|
|
{
|
|
if (run_cond == NULL)
|
|
coroutine_system_init();
|
|
|
|
CO_DEBUG("NEW");
|
|
co->thread = g_thread_create_full(coroutine_thread, co, co->stack_size,
|
|
FALSE, TRUE,
|
|
G_THREAD_PRIORITY_NORMAL,
|
|
NULL);
|
|
if (co->thread == NULL)
|
|
return -1;
|
|
|
|
co->exited = 0;
|
|
co->runnable = FALSE;
|
|
co->caller = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int coroutine_release(struct coroutine *co G_GNUC_UNUSED)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void *coroutine_swap(struct coroutine *from, struct coroutine *to, void *arg)
|
|
{
|
|
from->runnable = FALSE;
|
|
to->runnable = TRUE;
|
|
to->data = arg;
|
|
to->caller = from;
|
|
CO_DEBUG("BROADCAST");
|
|
g_cond_broadcast(run_cond);
|
|
CO_DEBUG("UNLOCK");
|
|
g_mutex_unlock(run_lock);
|
|
CO_DEBUG("LOCK");
|
|
g_mutex_lock(run_lock);
|
|
while (!from->runnable) {
|
|
CO_DEBUG("WAIT");
|
|
g_cond_wait(run_cond, run_lock);
|
|
}
|
|
current = from;
|
|
|
|
CO_DEBUG("SWAPPED");
|
|
return from->data;
|
|
}
|
|
|
|
struct coroutine *coroutine_self(void)
|
|
{
|
|
return current;
|
|
}
|
|
|
|
void *coroutine_yieldto(struct coroutine *to, void *arg)
|
|
{
|
|
if (to->caller) {
|
|
fprintf(stderr, "Co-routine is re-entering itself\n");
|
|
abort();
|
|
}
|
|
CO_DEBUG("SWAP");
|
|
return coroutine_swap(coroutine_self(), to, arg);
|
|
}
|
|
|
|
void *coroutine_yield(void *arg)
|
|
{
|
|
struct coroutine *to = coroutine_self()->caller;
|
|
if (!to) {
|
|
fprintf(stderr, "Co-routine is yielding to no one\n");
|
|
abort();
|
|
}
|
|
|
|
CO_DEBUG("SWAP");
|
|
coroutine_self()->caller = NULL;
|
|
return coroutine_swap(coroutine_self(), to, arg);
|
|
}
|
|
|