2000-11-11 15:13:50 +00:00
|
|
|
/* GStreamer
|
2000-12-28 22:12:02 +00:00
|
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
|
|
* 2000 Wim Taymans <wtay@chello.be>
|
|
|
|
*
|
|
|
|
* cothreads.c: Cothreading routines
|
2000-11-11 15:13:50 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 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
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2002-11-01 21:38:39 +00:00
|
|
|
#include <glib.h>
|
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
#include <stdio.h>
|
2000-01-30 09:03:00 +00:00
|
|
|
#include <stdlib.h>
|
2001-12-20 02:41:34 +00:00
|
|
|
#include <signal.h>
|
2000-01-30 09:03:00 +00:00
|
|
|
#include <setjmp.h>
|
|
|
|
#include <unistd.h>
|
2002-06-27 15:52:13 +00:00
|
|
|
#include <errno.h>
|
2000-01-30 09:03:00 +00:00
|
|
|
#include <sys/mman.h>
|
|
|
|
|
2000-12-28 22:12:02 +00:00
|
|
|
#include "gst_private.h"
|
Changes made to the DEBUG system. New header file gstdebug.h holds the stuff to keep it out of gst.h's hair. DEBUG ...
Original commit message from CVS:
Changes made to the DEBUG system. New header file gstdebug.h holds the
stuff to keep it out of gst.h's hair. DEBUG prints out the process id,
cothread id, source filename and line number. Two new macros DEBUG_ENTER
and DEBUG_LEAVE are used to show the entry and exit of a given function.
This eventually might be used to construct call trace graphs, even taking
cothreads into account. This would be quite useful in visualizing the
scheduling mechanism.
Minor changes to various debug messages.
Also sitting in gstdebug.h is a prototypical DEBUG_ENTER that's capable of
performing DEBUG_LEAVE automatically. It does this by utilizing a
little-known GCC extension that allows one to call a function with the
same parameters as the current function. The macro uses this to basically
call itself. A boolean is used to ensure that when it calls itself it
actually runs the body of the function. In the meantime it prints stuff
out before and after the real function, as well as constructing a
debugging string. This can be used eventually to provide call-wide data
on the DEBUG lines, instead of having to replicate data on each call to
DEBUG. More research is needed into how this would most cleanly be fit
into some other chunk of code, like GStreamer (I think of this DEBUG trick
as a separate project, sorta).
Unfortunately, the aforementioned DEBUG trick interacts quite poorly with
cothreads. Almost any time it's used in a function that has anything
remotely to do with a cothread context (as in, it runs in one), a segfault
results from the __builtin_apply call, which is the heart of the whole
thing. If someone who really knows assembly could analyze the resulting
code to see what's really going on, we might find a way to fix either the
macro or the cothreads (I'm thinking that there's something we missed in
constructing the cothreads themselves) so this works in all cases.
In the meantime, please insert both DEBUG_ENTER and DEBUG_LEAVE in your
functions. Be sure to put DEBUG_ENTER after your variable declarations
and before any functional code, not to put the function name in any DEBUG
strings (it's already there, trust me), and put a DEBUG_LEAVE if you care
enough.
Changes are going to happen in the way DEBUGs and other printouts occur,
so stay tuned.
2000-12-04 09:35:08 +00:00
|
|
|
|
2000-12-15 01:57:34 +00:00
|
|
|
#include "cothreads.h"
|
|
|
|
#include "gstarch.h"
|
2001-12-20 02:41:34 +00:00
|
|
|
#include "gstlog.h"
|
2002-05-29 14:59:48 +00:00
|
|
|
#include "gstutils.h"
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-08-13 13:56:05 +00:00
|
|
|
/* older glibc's have MAP_ANON instead of MAP_ANONYMOUS */
|
|
|
|
#ifndef MAP_ANONYMOUS
|
|
|
|
#define MAP_ANONYMOUS MAP_ANON
|
|
|
|
#endif
|
2000-12-28 22:12:02 +00:00
|
|
|
|
2001-05-10 22:10:19 +00:00
|
|
|
#define STACK_SIZE 0x200000
|
|
|
|
|
2002-06-28 10:58:05 +00:00
|
|
|
#define COTHREAD_MAGIC_NUMBER 0xabcdef
|
|
|
|
|
2001-06-06 18:29:57 +00:00
|
|
|
#define COTHREAD_MAXTHREADS 16
|
2001-06-04 16:02:48 +00:00
|
|
|
#define COTHREAD_STACKSIZE (STACK_SIZE/COTHREAD_MAXTHREADS)
|
2001-05-10 22:10:19 +00:00
|
|
|
|
2001-12-20 20:03:10 +00:00
|
|
|
static void cothread_destroy (cothread_state *thread);
|
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
struct _cothread_context
|
|
|
|
{
|
2002-09-12 18:56:31 +00:00
|
|
|
cothread_state *cothreads[COTHREAD_MAXTHREADS]; /* array of cothread states */
|
|
|
|
int ncothreads;
|
2001-05-10 22:35:50 +00:00
|
|
|
int current;
|
2002-11-15 09:51:41 +00:00
|
|
|
unsigned long stack_top;
|
2001-05-10 22:35:50 +00:00
|
|
|
GHashTable *data;
|
2002-12-04 00:07:13 +00:00
|
|
|
GThread *thread;
|
2001-05-10 22:35:50 +00:00
|
|
|
};
|
|
|
|
|
2002-12-03 21:02:55 +00:00
|
|
|
/* Disabling this define allows you to shut off a few checks in
|
|
|
|
* cothread_switch. This likely will speed things up fractionally */
|
|
|
|
#define COTHREAD_PARANOID
|
|
|
|
|
2001-05-10 22:35:50 +00:00
|
|
|
|
2002-11-01 21:38:39 +00:00
|
|
|
/* this _cothread_ctx_key is used as a GThread key to the thread's context
|
|
|
|
* a GThread key is a "pointer" to memory space that is/can be different
|
2002-09-12 18:56:31 +00:00
|
|
|
* (ie. private) for each thread. The key itself is shared among threads,
|
|
|
|
* so it only needs to be initialized once.
|
|
|
|
*/
|
2002-12-03 22:44:49 +00:00
|
|
|
static GStaticPrivate _cothread_ctx_key = G_STATIC_PRIVATE_INIT;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-12-03 21:02:55 +00:00
|
|
|
/*
|
|
|
|
* This should only after context init, since we do checking.
|
|
|
|
*/
|
|
|
|
static cothread_context *
|
|
|
|
cothread_get_current_context (void)
|
|
|
|
{
|
|
|
|
cothread_context *ctx;
|
|
|
|
|
2002-12-03 22:44:49 +00:00
|
|
|
ctx = g_static_private_get (&_cothread_ctx_key);
|
2002-12-03 21:02:55 +00:00
|
|
|
g_assert(ctx);
|
|
|
|
|
|
|
|
#ifdef COTHREAD_PARANOID
|
2002-12-04 00:07:13 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
2002-12-03 21:02:55 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
2000-11-29 10:05:47 +00:00
|
|
|
|
2001-01-04 10:54:27 +00:00
|
|
|
/**
|
2001-12-20 02:41:34 +00:00
|
|
|
* cothread_context_init:
|
2001-01-04 10:54:27 +00:00
|
|
|
*
|
2001-01-04 22:16:06 +00:00
|
|
|
* Create and initialize a new cothread context
|
2001-01-04 10:54:27 +00:00
|
|
|
*
|
|
|
|
* Returns: the new cothread context
|
|
|
|
*/
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_context *
|
|
|
|
cothread_context_init (void)
|
2001-01-04 10:54:27 +00:00
|
|
|
{
|
2002-11-01 21:38:39 +00:00
|
|
|
cothread_context *ctx;
|
2002-11-15 09:51:41 +00:00
|
|
|
void *sp;
|
2002-11-02 13:15:10 +00:00
|
|
|
|
2002-11-01 21:38:39 +00:00
|
|
|
/* if there already is a cotread context for this thread,
|
|
|
|
* just return it */
|
2002-12-03 22:44:49 +00:00
|
|
|
ctx = g_static_private_get (&_cothread_ctx_key);
|
2002-11-18 22:44:47 +00:00
|
|
|
if (ctx) {
|
|
|
|
GST_INFO (GST_CAT_COTHREADS,
|
|
|
|
"returning private _cothread_ctx_key %p", ctx);
|
2002-11-02 13:15:10 +00:00
|
|
|
return ctx;
|
2002-11-18 22:44:47 +00:00
|
|
|
}
|
2002-11-01 21:38:39 +00:00
|
|
|
|
2002-11-02 13:15:10 +00:00
|
|
|
/*
|
|
|
|
* initalize the whole of the cothreads context
|
|
|
|
*/
|
2002-11-01 21:38:39 +00:00
|
|
|
ctx = (cothread_context *) g_malloc (sizeof (cothread_context));
|
2001-01-04 10:54:27 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* we consider the initiating process to be cothread 0 */
|
2002-09-12 18:56:31 +00:00
|
|
|
ctx->ncothreads = 1;
|
2001-05-25 21:00:07 +00:00
|
|
|
ctx->current = 0;
|
2001-12-20 02:41:34 +00:00
|
|
|
ctx->data = g_hash_table_new (g_str_hash, g_str_equal);
|
2002-12-04 00:07:13 +00:00
|
|
|
ctx->thread = g_thread_self();
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "initializing cothreads");
|
2001-01-04 10:54:27 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
/* set this thread's context pointer */
|
2002-12-10 04:01:09 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "setting private _cothread_ctx_key to %p in thread %p",
|
|
|
|
ctx,g_thread_self());
|
2002-12-03 22:44:49 +00:00
|
|
|
g_static_private_set (&_cothread_ctx_key, ctx, NULL);
|
2002-09-12 18:56:31 +00:00
|
|
|
|
2002-12-10 04:01:09 +00:00
|
|
|
g_assert(ctx == cothread_get_current_context());
|
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
/* clear the cothread data */
|
|
|
|
memset (ctx->cothreads, 0, sizeof (ctx->cothreads));
|
2001-01-04 10:54:27 +00:00
|
|
|
|
2002-11-15 09:51:41 +00:00
|
|
|
sp = CURRENT_STACK_FRAME;
|
|
|
|
/* FIXME this may not be 64bit clean
|
|
|
|
* could use casts to uintptr_t from inttypes.h
|
|
|
|
* if only all platforms had inttypes.h
|
|
|
|
*/
|
|
|
|
/* stack_top is the address of the first byte past our stack segment. */
|
|
|
|
/* FIXME: an assumption is made that the stack segment is STACK_SIZE
|
|
|
|
* aligned. */
|
|
|
|
ctx->stack_top = ((gulong) sp | (STACK_SIZE - 1)) + 1;
|
2002-11-19 02:25:52 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "stack top is 0x%08lx", ctx->stack_top);
|
2002-11-15 09:51:41 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
/*
|
|
|
|
* initialize the 0th cothread
|
|
|
|
*/
|
|
|
|
ctx->cothreads[0] = (cothread_state *) g_malloc0 (sizeof (cothread_state));
|
|
|
|
ctx->cothreads[0]->ctx = ctx;
|
|
|
|
ctx->cothreads[0]->cothreadnum = 0;
|
|
|
|
ctx->cothreads[0]->func = NULL;
|
|
|
|
ctx->cothreads[0]->argc = 0;
|
|
|
|
ctx->cothreads[0]->argv = NULL;
|
|
|
|
ctx->cothreads[0]->priv = NULL;
|
|
|
|
ctx->cothreads[0]->flags = COTHREAD_STARTED;
|
|
|
|
ctx->cothreads[0]->sp = (void *) CURRENT_STACK_FRAME;
|
|
|
|
|
|
|
|
GST_INFO (GST_CAT_COTHREADS, "0th cothread is %p at sp:%p",
|
|
|
|
ctx->cothreads[0], ctx->cothreads[0]->sp);
|
2001-01-04 10:54:27 +00:00
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
/**
|
|
|
|
* cothread_context_free:
|
2001-12-28 20:20:26 +00:00
|
|
|
* @ctx: the cothread context to free
|
2001-12-20 02:41:34 +00:00
|
|
|
*
|
|
|
|
* Free the cothread context.
|
|
|
|
*/
|
2001-12-18 16:49:13 +00:00
|
|
|
void
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_context_free (cothread_context *ctx)
|
2001-12-18 16:49:13 +00:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
2001-12-23 14:27:48 +00:00
|
|
|
g_return_if_fail (ctx != NULL);
|
2002-12-04 00:07:13 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
2002-12-10 04:01:09 +00:00
|
|
|
g_assert (ctx->current == 0);
|
2001-12-23 14:27:48 +00:00
|
|
|
|
2001-12-20 20:03:10 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "free cothread context");
|
|
|
|
|
2002-12-10 04:05:14 +00:00
|
|
|
for (i = 1; i < COTHREAD_MAXTHREADS; i++) {
|
2002-09-12 18:56:31 +00:00
|
|
|
if (ctx->cothreads[i]) {
|
|
|
|
cothread_destroy (ctx->cothreads[i]);
|
2001-12-19 19:22:53 +00:00
|
|
|
}
|
2001-12-18 16:49:13 +00:00
|
|
|
}
|
2002-12-10 04:05:14 +00:00
|
|
|
if (ctx->cothreads[0]) {
|
|
|
|
g_free(ctx->cothreads[0]);
|
|
|
|
ctx->cothreads[0] = NULL;
|
|
|
|
}
|
2001-12-18 16:49:13 +00:00
|
|
|
g_hash_table_destroy (ctx->data);
|
2002-11-18 22:44:47 +00:00
|
|
|
/* make sure we free the private key for cothread context */
|
2002-12-10 04:01:09 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "setting private _cothread_ctx_key to NULL in thread %p",
|
2002-12-10 04:05:14 +00:00
|
|
|
g_thread_self());
|
2002-12-03 22:44:49 +00:00
|
|
|
g_static_private_set (&_cothread_ctx_key, NULL, NULL);
|
2001-12-18 16:49:13 +00:00
|
|
|
g_free (ctx);
|
|
|
|
}
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
/**
|
|
|
|
* cothread_create:
|
|
|
|
* @ctx: the cothread context
|
|
|
|
*
|
2001-01-04 22:16:06 +00:00
|
|
|
* Create a new cothread state in the given context
|
2000-11-11 15:13:50 +00:00
|
|
|
*
|
2001-05-16 07:16:47 +00:00
|
|
|
* Returns: the new cothread state or NULL on error
|
2000-11-11 15:13:50 +00:00
|
|
|
*/
|
2000-11-04 18:54:07 +00:00
|
|
|
cothread_state*
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_create (cothread_context *ctx)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2002-09-12 18:56:31 +00:00
|
|
|
cothread_state *cothread;
|
2002-11-14 13:35:13 +00:00
|
|
|
void *mmaped = 0;
|
2001-12-20 02:41:34 +00:00
|
|
|
gint slot = 0;
|
2002-11-19 02:25:52 +00:00
|
|
|
unsigned long page_size;
|
2001-12-20 02:41:34 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (ctx != NULL, NULL);
|
2002-12-04 00:07:13 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
if (ctx->ncothreads == COTHREAD_MAXTHREADS) {
|
2001-12-20 02:41:34 +00:00
|
|
|
/* this is pretty fatal */
|
|
|
|
g_warning ("cothread_create: attempt to create > COTHREAD_MAXTHREADS\n");
|
2001-05-16 07:16:47 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2001-12-23 14:27:48 +00:00
|
|
|
/* find a free spot in the stack, note slot 0 has the main thread */
|
2002-09-12 18:56:31 +00:00
|
|
|
for (slot = 1; slot < ctx->ncothreads; slot++) {
|
|
|
|
if (ctx->cothreads[slot] == NULL)
|
2001-12-20 02:41:34 +00:00
|
|
|
break;
|
2002-09-12 18:56:31 +00:00
|
|
|
else if (ctx->cothreads[slot]->flags & COTHREAD_DESTROYED &&
|
2001-12-22 23:19:17 +00:00
|
|
|
slot != ctx->current) {
|
2002-09-12 18:56:31 +00:00
|
|
|
cothread_destroy (ctx->cothreads[slot]);
|
2001-12-20 20:03:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-12-20 02:41:34 +00:00
|
|
|
}
|
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "Found free cothread slot %d", slot);
|
2002-06-25 12:08:10 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
/* cothread stack space of the thread is mapped in reverse, with cothread 0
|
|
|
|
* stack space at the top */
|
2002-11-15 09:51:41 +00:00
|
|
|
cothread = (cothread_state *) (ctx->stack_top - (slot + 1) * COTHREAD_STACKSIZE);
|
2002-11-19 02:25:52 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "cothread pointer is %p", cothread);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-11-19 02:25:52 +00:00
|
|
|
#if 0
|
|
|
|
/* This tests to see whether or not we can grow down the stack */
|
|
|
|
{
|
|
|
|
unsigned long ptr;
|
|
|
|
for(ptr=ctx->stack_top - 4096; ptr > (unsigned long)cothread; ptr -= 4096){
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "touching location 0x%08lx", ptr);
|
|
|
|
*(volatile unsigned int *)ptr = *(volatile unsigned int *)ptr;
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "ok (0x%08x)", *(unsigned int *)ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-12-05 01:50:31 +00:00
|
|
|
#ifdef _SC_PAGESIZE
|
|
|
|
page_size = sysconf(_SC_PAGESIZE);
|
|
|
|
#else
|
|
|
|
page_size = getpagesize();
|
|
|
|
#endif
|
|
|
|
|
2002-11-19 02:25:52 +00:00
|
|
|
/* The mmap is necessary on Linux/i386, and possibly others, since the
|
|
|
|
* kernel is picky about when we can expand our stack. */
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "mmaping %p, size 0x%08x", cothread,
|
|
|
|
COTHREAD_STACKSIZE);
|
2002-12-05 01:50:31 +00:00
|
|
|
/* Remap with a guard page. This decreases our stack size by 8 kB (for
|
|
|
|
* 4 kB pages) and also wastes almost 4 kB for the cothreads
|
|
|
|
* structure */
|
|
|
|
munmap((void *)cothread, COTHREAD_STACKSIZE);
|
|
|
|
mmaped = mmap ((void *) cothread, page_size,
|
|
|
|
PROT_READ | PROT_WRITE,
|
|
|
|
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
|
mmaped = mmap (((void *) cothread) + page_size * 2,
|
|
|
|
COTHREAD_STACKSIZE - page_size * 2,
|
2002-11-14 13:35:13 +00:00
|
|
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
|
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "coming out of mmap");
|
|
|
|
if (mmaped == MAP_FAILED) {
|
|
|
|
perror ("mmap'ing cothread stack space");
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-12-05 01:50:31 +00:00
|
|
|
if (mmaped != (void *)cothread + page_size * 2) {
|
2002-11-14 13:35:13 +00:00
|
|
|
g_warning ("could not mmap requested memory for cothread");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2002-11-18 22:44:47 +00:00
|
|
|
cothread->magic_number = COTHREAD_MAGIC_NUMBER;
|
2002-06-28 10:58:05 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "create cothread %d with magic number 0x%x",
|
2002-09-12 18:56:31 +00:00
|
|
|
slot, cothread->magic_number);
|
|
|
|
cothread->ctx = ctx;
|
|
|
|
cothread->cothreadnum = slot;
|
|
|
|
cothread->flags = 0;
|
|
|
|
cothread->priv = NULL;
|
|
|
|
cothread->sp = ((guchar *) cothread + COTHREAD_STACKSIZE);
|
2002-12-05 01:50:31 +00:00
|
|
|
cothread->stack_size = COTHREAD_STACKSIZE - page_size * 2;
|
|
|
|
cothread->stack_base = (void *)cothread + 2 * page_size;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-06-28 10:58:05 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS,
|
2002-07-08 19:10:11 +00:00
|
|
|
"created cothread #%d in slot %d: %p at sp:%p",
|
2002-09-12 18:56:31 +00:00
|
|
|
ctx->ncothreads, slot, cothread, cothread->sp);
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
ctx->cothreads[slot] = cothread;
|
|
|
|
ctx->ncothreads++;
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
return cothread;
|
2001-12-20 02:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* cothread_free:
|
2002-09-12 18:56:31 +00:00
|
|
|
* @cothread: the cothread state
|
2001-12-20 02:41:34 +00:00
|
|
|
*
|
|
|
|
* Free the given cothread state
|
|
|
|
*/
|
|
|
|
void
|
2002-09-12 18:56:31 +00:00
|
|
|
cothread_free (cothread_state *cothread)
|
2001-12-20 02:41:34 +00:00
|
|
|
{
|
2002-09-12 18:56:31 +00:00
|
|
|
g_return_if_fail (cothread != NULL);
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "flag cothread %d for destruction",
|
|
|
|
cothread->cothreadnum);
|
2001-12-20 20:03:10 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
/* we simply flag the cothread for destruction here */
|
2002-11-29 13:59:30 +00:00
|
|
|
if (cothread)
|
|
|
|
cothread->flags |= COTHREAD_DESTROYED;
|
|
|
|
else
|
|
|
|
g_warning ("somebody set up us the bomb");
|
2001-12-20 02:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-09-12 18:56:31 +00:00
|
|
|
cothread_destroy (cothread_state *cothread)
|
2001-12-20 02:41:34 +00:00
|
|
|
{
|
|
|
|
cothread_context *ctx;
|
2002-09-12 18:56:31 +00:00
|
|
|
gint cothreadnum;
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
g_return_if_fail (cothread != NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
cothreadnum = cothread->cothreadnum;
|
|
|
|
ctx = cothread->ctx;
|
2002-12-04 00:07:13 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
2002-12-10 04:01:09 +00:00
|
|
|
g_assert (ctx == cothread_get_current_context());
|
2001-12-23 14:27:48 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREADS, "destroy cothread %d %p %d",
|
|
|
|
cothreadnum, cothread, ctx->current);
|
2001-12-23 14:27:48 +00:00
|
|
|
|
2002-12-10 04:01:09 +00:00
|
|
|
/* cothread 0 needs to be destroyed specially */
|
|
|
|
g_assert(cothreadnum != 0);
|
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
/* we have to unlock here because we might be switched out
|
|
|
|
* with the lock held */
|
|
|
|
cothread_unlock (cothread);
|
2001-12-23 14:50:44 +00:00
|
|
|
|
2002-12-10 04:05:14 +00:00
|
|
|
/* doing cleanups of the cothread create */
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "destroy cothread %d with magic number 0x%x",
|
|
|
|
cothreadnum, cothread->magic_number);
|
|
|
|
g_assert (cothread->magic_number == COTHREAD_MAGIC_NUMBER);
|
|
|
|
|
|
|
|
g_assert (cothread->priv == NULL);
|
|
|
|
|
|
|
|
memset(cothread,0,sizeof(*cothread));
|
2001-12-23 14:27:48 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
ctx->cothreads[cothreadnum] = NULL;
|
|
|
|
ctx->ncothreads--;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
/**
|
|
|
|
* cothread_setfunc:
|
|
|
|
* @thread: the cothread state
|
|
|
|
* @func: the function to call
|
2001-01-04 22:16:06 +00:00
|
|
|
* @argc: argument count for the cothread function
|
|
|
|
* @argv: arguments for the cothread function
|
2000-11-11 15:13:50 +00:00
|
|
|
*
|
|
|
|
* Set the cothread function
|
|
|
|
*/
|
2001-12-20 02:41:34 +00:00
|
|
|
void
|
|
|
|
cothread_setfunc (cothread_state * thread, cothread_func func, int argc, char **argv)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
thread->func = func;
|
|
|
|
thread->argc = argc;
|
|
|
|
thread->argv = argv;
|
|
|
|
}
|
|
|
|
|
2001-12-28 20:20:26 +00:00
|
|
|
/**
|
|
|
|
* cothread_stop:
|
|
|
|
* @thread: the cothread to stop
|
|
|
|
*
|
|
|
|
* Stop the cothread and reset the stack and program counter.
|
|
|
|
*/
|
2001-12-25 02:15:46 +00:00
|
|
|
void
|
|
|
|
cothread_stop (cothread_state * thread)
|
|
|
|
{
|
|
|
|
thread->flags &= ~COTHREAD_STARTED;
|
|
|
|
}
|
|
|
|
|
2001-01-04 22:16:06 +00:00
|
|
|
/**
|
|
|
|
* cothread_main:
|
2002-09-12 18:56:31 +00:00
|
|
|
* @ctx: cothread context to find main cothread of.
|
2001-01-04 22:16:06 +00:00
|
|
|
*
|
2002-09-12 18:56:31 +00:00
|
|
|
* Gets the main thread.
|
2001-10-21 18:00:31 +00:00
|
|
|
*
|
2002-09-12 18:56:31 +00:00
|
|
|
* Returns: the #cothread_state of the main (0th) cothread.
|
2001-01-05 00:28:09 +00:00
|
|
|
*/
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_state *
|
|
|
|
cothread_main (cothread_context * ctx)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2002-12-10 04:01:09 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "returning %p, the 0th cothread",
|
|
|
|
ctx->cothreads[0]);
|
|
|
|
return ctx->cothreads[0];
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2001-05-25 21:00:07 +00:00
|
|
|
/**
|
2001-05-27 14:37:29 +00:00
|
|
|
* cothread_current_main:
|
2001-05-25 21:00:07 +00:00
|
|
|
*
|
2002-11-01 21:38:39 +00:00
|
|
|
* Get the main thread in the current GThread.
|
2001-10-21 18:00:31 +00:00
|
|
|
*
|
2002-11-01 21:38:39 +00:00
|
|
|
* Returns: the #cothread_state of the main (0th) thread in the current GThread
|
2001-05-25 21:00:07 +00:00
|
|
|
*/
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_state *
|
2001-10-21 18:00:31 +00:00
|
|
|
cothread_current_main (void)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
return ctx->cothreads[0];
|
2001-05-25 21:00:07 +00:00
|
|
|
}
|
|
|
|
|
2001-12-27 00:47:41 +00:00
|
|
|
/**
|
|
|
|
* cothread_current:
|
|
|
|
*
|
|
|
|
* Get the currenttly executing cothread
|
|
|
|
*
|
|
|
|
* Returns: the #cothread_state of the current cothread
|
|
|
|
*/
|
|
|
|
cothread_state *
|
|
|
|
cothread_current (void)
|
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2001-12-27 00:47:41 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
return ctx->cothreads[ctx->current];
|
2001-12-27 00:47:41 +00:00
|
|
|
}
|
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
static void
|
|
|
|
cothread_stub (void)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2002-12-10 04:05:14 +00:00
|
|
|
cothread_state *thread = ctx->cothreads[ctx->current];
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_DEBUG_ENTER ("");
|
2001-01-19 07:48:43 +00:00
|
|
|
|
2002-12-05 01:50:31 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "stack addr %p\n", &ctx);
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
thread->flags |= COTHREAD_STARTED;
|
2002-04-19 10:26:56 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
while (TRUE) {
|
|
|
|
thread->func (thread->argc, thread->argv);
|
2002-12-10 04:01:09 +00:00
|
|
|
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "cothread[%d] thread->func exited",ctx->current);
|
|
|
|
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "sp=%p",CURRENT_STACK_FRAME);
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "ctx=%p current=%p",ctx,cothread_get_current_context());
|
|
|
|
g_assert(ctx == cothread_get_current_context());
|
|
|
|
|
|
|
|
g_assert(ctx->current != 0);
|
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* we do this to avoid ever returning, we just switch to 0th thread */
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_switch (cothread_main (ctx));
|
2001-01-19 07:48:43 +00:00
|
|
|
}
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_DEBUG_LEAVE ("");
|
2000-12-03 00:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* cothread_getcurrent:
|
|
|
|
*
|
2001-10-21 18:00:31 +00:00
|
|
|
* Get the current cothread id
|
|
|
|
*
|
2000-12-03 00:17:52 +00:00
|
|
|
* Returns: the current cothread id
|
|
|
|
*/
|
2002-11-29 18:10:21 +00:00
|
|
|
int cothread_getcurrent (void) G_GNUC_NO_INSTRUMENT;
|
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
int
|
|
|
|
cothread_getcurrent (void)
|
2001-10-21 18:00:31 +00:00
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2001-12-20 02:41:34 +00:00
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return -1;
|
2000-12-03 00:17:52 +00:00
|
|
|
return ctx->current;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
/**
|
2002-03-31 14:04:50 +00:00
|
|
|
* cothread_set_private:
|
2000-11-11 15:13:50 +00:00
|
|
|
* @thread: the cothread state
|
|
|
|
* @data: the data
|
|
|
|
*
|
2002-03-31 14:04:50 +00:00
|
|
|
* set private data for the cothread.
|
2000-11-11 15:13:50 +00:00
|
|
|
*/
|
2000-11-06 00:15:51 +00:00
|
|
|
void
|
2002-02-23 13:41:17 +00:00
|
|
|
cothread_set_private (cothread_state *thread, gpointer data)
|
|
|
|
{
|
|
|
|
thread->priv = data;
|
|
|
|
}
|
|
|
|
|
2002-03-31 14:04:50 +00:00
|
|
|
/**
|
|
|
|
* cothread_context_set_data:
|
|
|
|
* @thread: the cothread state
|
|
|
|
* @key: a key for the data
|
|
|
|
* @data: the data
|
|
|
|
*
|
|
|
|
* adds data to a cothread
|
|
|
|
*/
|
2002-02-23 13:41:17 +00:00
|
|
|
void
|
|
|
|
cothread_context_set_data (cothread_state *thread, gchar *key, gpointer data)
|
2000-11-06 00:15:51 +00:00
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2000-11-06 00:15:51 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
g_hash_table_insert (ctx->data, key, data);
|
2000-11-06 00:15:51 +00:00
|
|
|
}
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
/**
|
2002-03-31 14:04:50 +00:00
|
|
|
* cothread_get_private:
|
2000-11-11 15:13:50 +00:00
|
|
|
* @thread: the cothread state
|
|
|
|
*
|
2002-03-31 14:04:50 +00:00
|
|
|
* get the private data from the cothread
|
2000-11-11 15:13:50 +00:00
|
|
|
*
|
2002-03-31 14:04:50 +00:00
|
|
|
* Returns: the private data of the cothread
|
2000-11-11 15:13:50 +00:00
|
|
|
*/
|
2000-11-06 00:15:51 +00:00
|
|
|
gpointer
|
2002-02-23 13:41:17 +00:00
|
|
|
cothread_get_private (cothread_state *thread)
|
|
|
|
{
|
|
|
|
return thread->priv;
|
|
|
|
}
|
|
|
|
|
2002-03-31 14:04:50 +00:00
|
|
|
/**
|
|
|
|
* cothread_context_get_data:
|
|
|
|
* @thread: the cothread state
|
|
|
|
* @key: a key for the data
|
|
|
|
*
|
|
|
|
* get data from the cothread
|
|
|
|
*
|
|
|
|
* Returns: the data associated with the key
|
|
|
|
*/
|
2002-02-23 13:41:17 +00:00
|
|
|
gpointer
|
|
|
|
cothread_context_get_data (cothread_state * thread, gchar * key)
|
2000-11-06 00:15:51 +00:00
|
|
|
{
|
2002-12-03 21:02:55 +00:00
|
|
|
cothread_context *ctx = cothread_get_current_context();
|
2000-11-06 00:15:51 +00:00
|
|
|
|
2001-12-20 02:41:34 +00:00
|
|
|
return g_hash_table_lookup (ctx->data, key);
|
2000-11-06 00:15:51 +00:00
|
|
|
}
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
/**
|
|
|
|
* cothread_switch:
|
2001-01-04 22:16:06 +00:00
|
|
|
* @thread: cothread state to switch to
|
2000-11-11 15:13:50 +00:00
|
|
|
*
|
2001-01-04 22:16:06 +00:00
|
|
|
* Switches to the given cothread state
|
2000-11-11 15:13:50 +00:00
|
|
|
*/
|
2001-12-20 02:41:34 +00:00
|
|
|
void
|
|
|
|
cothread_switch (cothread_state * thread)
|
2000-11-04 18:54:07 +00:00
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
cothread_context *ctx;
|
|
|
|
cothread_state *current;
|
2000-09-16 10:58:23 +00:00
|
|
|
int enter;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-29 10:05:47 +00:00
|
|
|
#ifdef COTHREAD_PARANOID
|
2001-12-20 02:41:34 +00:00
|
|
|
if (thread == NULL)
|
|
|
|
goto nothread;
|
2000-11-29 10:05:47 +00:00
|
|
|
#endif
|
2000-01-30 09:03:00 +00:00
|
|
|
ctx = thread->ctx;
|
2002-11-21 00:54:32 +00:00
|
|
|
|
|
|
|
/* paranoia check to make sure we're in the right thread */
|
2002-12-04 00:07:13 +00:00
|
|
|
g_assert (ctx->thread == g_thread_self());
|
2002-11-21 00:54:32 +00:00
|
|
|
|
2000-11-29 10:05:47 +00:00
|
|
|
#ifdef COTHREAD_PARANOID
|
2001-12-20 02:41:34 +00:00
|
|
|
if (ctx == NULL)
|
|
|
|
goto nocontext;
|
2000-11-29 10:05:47 +00:00
|
|
|
#endif
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-09-12 18:56:31 +00:00
|
|
|
current = ctx->cothreads[ctx->current];
|
2000-11-29 10:05:47 +00:00
|
|
|
#ifdef COTHREAD_PARANOID
|
2001-12-20 02:41:34 +00:00
|
|
|
if (current == NULL)
|
|
|
|
goto nocurrent;
|
2000-11-29 10:05:47 +00:00
|
|
|
#endif
|
2001-12-20 02:41:34 +00:00
|
|
|
if (current == thread)
|
|
|
|
goto selfswitch;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-12-14 22:59:21 +00:00
|
|
|
/* find the number of the thread to switch to */
|
2002-08-13 14:11:33 +00:00
|
|
|
GST_INFO (GST_CAT_COTHREAD_SWITCH,
|
|
|
|
"switching from cothread #%d to cothread #%d",
|
2002-09-12 18:56:31 +00:00
|
|
|
ctx->current, thread->cothreadnum);
|
|
|
|
ctx->current = thread->cothreadnum;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2002-12-10 03:59:15 +00:00
|
|
|
g_static_private_set (&_gst_debug_cothread_index, (void *)ctx->current, NULL);
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
/* save the current stack pointer, frame pointer, and pc */
|
2001-03-02 18:30:37 +00:00
|
|
|
#ifdef GST_ARCH_PRESETJMP
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_ARCH_PRESETJMP ();
|
2001-03-02 18:30:37 +00:00
|
|
|
#endif
|
2001-12-23 14:50:44 +00:00
|
|
|
enter = setjmp (current->jmp);
|
2000-09-16 10:58:23 +00:00
|
|
|
if (enter != 0) {
|
2002-08-13 14:11:33 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS,
|
2002-12-05 01:50:31 +00:00
|
|
|
"enter cothread #%d %d sp=%p jmpbuf=%p",
|
|
|
|
current->cothreadnum, enter, current->sp, current->jmp);
|
2000-01-30 09:03:00 +00:00
|
|
|
return;
|
2000-09-16 10:58:23 +00:00
|
|
|
}
|
2002-12-05 01:50:31 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "exit cothread #%d %d sp=%p jmpbuf=%p",
|
|
|
|
current->cothreadnum, enter, current->sp, current->jmp);
|
2000-01-30 09:03:00 +00:00
|
|
|
enter = 1;
|
|
|
|
|
2002-05-29 14:59:48 +00:00
|
|
|
if (current->flags & COTHREAD_DESTROYED) {
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_destroy (current);
|
2002-05-29 14:59:48 +00:00
|
|
|
}
|
2001-12-20 02:41:34 +00:00
|
|
|
|
2002-06-25 12:09:32 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "set stack to %p", thread->sp);
|
2000-01-30 09:03:00 +00:00
|
|
|
/* restore stack pointer and other stuff of new cothread */
|
|
|
|
if (thread->flags & COTHREAD_STARTED) {
|
2002-12-05 01:50:31 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "via longjmp() jmpbuf %p", thread->jmp);
|
2001-12-14 22:59:21 +00:00
|
|
|
/* switch to it */
|
2001-12-23 14:50:44 +00:00
|
|
|
longjmp (thread->jmp, 1);
|
2001-12-20 02:41:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2002-12-05 01:50:31 +00:00
|
|
|
#ifdef HAVE_MAKECONTEXT
|
|
|
|
ucontext_t ucp;
|
|
|
|
|
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "making context");
|
|
|
|
|
|
|
|
g_assert(thread != cothread_main(ctx));
|
|
|
|
|
|
|
|
getcontext(&ucp);
|
|
|
|
ucp.uc_stack.ss_sp = (void *)thread->stack_base;
|
|
|
|
ucp.uc_stack.ss_size = thread->stack_size;
|
|
|
|
makecontext(&ucp, cothread_stub, 0);
|
|
|
|
setcontext(&ucp);
|
|
|
|
#else
|
2001-12-23 14:27:48 +00:00
|
|
|
GST_ARCH_SETUP_STACK ((char*)thread->sp);
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_ARCH_SET_SP (thread->sp);
|
2001-12-14 22:59:21 +00:00
|
|
|
/* start it */
|
2001-12-20 02:41:34 +00:00
|
|
|
GST_ARCH_CALL (cothread_stub);
|
2002-12-05 01:50:31 +00:00
|
|
|
#endif
|
|
|
|
|
2002-06-25 12:09:32 +00:00
|
|
|
GST_DEBUG (GST_CAT_COTHREADS, "exit thread ");
|
2000-09-22 23:35:14 +00:00
|
|
|
ctx->current = 0;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2000-11-29 10:05:47 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef COTHREAD_PARANOID
|
|
|
|
nothread:
|
2002-07-28 01:04:33 +00:00
|
|
|
g_warning ("cothread: can't switch to NULL cothread!\n");
|
2000-11-29 10:05:47 +00:00
|
|
|
return;
|
|
|
|
nocontext:
|
2002-07-28 01:04:33 +00:00
|
|
|
g_warning ("cothread: there's no context, help!\n");
|
2001-12-20 02:41:34 +00:00
|
|
|
exit (2);
|
2000-11-29 10:05:47 +00:00
|
|
|
nocurrent:
|
2002-07-28 01:04:33 +00:00
|
|
|
g_warning ("cothread: there's no current thread, help!\n");
|
2001-12-20 02:41:34 +00:00
|
|
|
exit (2);
|
2000-11-29 10:05:47 +00:00
|
|
|
#endif /* COTHREAD_PARANOID */
|
|
|
|
selfswitch:
|
2002-07-28 01:04:33 +00:00
|
|
|
g_warning ("cothread: trying to switch to same thread, legal but not necessary\n");
|
2000-11-29 10:05:47 +00:00
|
|
|
return;
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
2001-05-25 21:00:07 +00:00
|
|
|
|
2001-05-27 14:37:29 +00:00
|
|
|
/**
|
|
|
|
* cothread_lock:
|
|
|
|
* @thread: cothread state to lock
|
|
|
|
*
|
|
|
|
* Locks the cothread state.
|
|
|
|
*/
|
2001-05-25 21:00:07 +00:00
|
|
|
void
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_lock (cothread_state * thread)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2001-05-27 14:37:29 +00:00
|
|
|
/**
|
|
|
|
* cothread_trylock:
|
|
|
|
* @thread: cothread state to try to lock
|
|
|
|
*
|
|
|
|
* Try to lock the cothread state
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the cothread could be locked.
|
|
|
|
*/
|
2001-05-25 21:00:07 +00:00
|
|
|
gboolean
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_trylock (cothread_state * thread)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
2002-07-08 19:10:11 +00:00
|
|
|
return TRUE;
|
2001-05-25 21:00:07 +00:00
|
|
|
}
|
|
|
|
|
2001-05-27 14:37:29 +00:00
|
|
|
/**
|
|
|
|
* cothread_unlock:
|
|
|
|
* @thread: cothread state to unlock
|
|
|
|
*
|
|
|
|
* Unlock the cothread state.
|
|
|
|
*/
|
2001-05-25 21:00:07 +00:00
|
|
|
void
|
2001-12-20 02:41:34 +00:00
|
|
|
cothread_unlock (cothread_state * thread)
|
2001-05-25 21:00:07 +00:00
|
|
|
{
|
|
|
|
}
|