cothreads.c 17.6 KB
Newer Older
Wim Taymans's avatar
Wim Taymans committed
1
/* GStreamer
2
3
4
5
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *
 * cothreads.c: Cothreading routines
Wim Taymans's avatar
Wim Taymans committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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.
 */

23
24
#include <glib.h>

Wim Taymans's avatar
Wim Taymans committed
25
#include <stdio.h>
Erik Walthinsen's avatar
Erik Walthinsen committed
26
#include <stdlib.h>
Wim Taymans's avatar
Wim Taymans committed
27
#include <signal.h>
Erik Walthinsen's avatar
Erik Walthinsen committed
28
29
#include <setjmp.h>
#include <unistd.h>
30
#include <errno.h>
Erik Walthinsen's avatar
Erik Walthinsen committed
31
32
#include <sys/mman.h>

33
#include "gst_private.h"
34

35
36
#include "cothreads.h"
#include "gstarch.h"
Wim Taymans's avatar
Wim Taymans committed
37
#include "gstlog.h"
38
#include "gstutils.h"
Erik Walthinsen's avatar
Erik Walthinsen committed
39

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
40
41
42
43
/* older glibc's have MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
44

45
46
#define STACK_SIZE 0x200000

47
48
#define COTHREAD_MAGIC_NUMBER 0xabcdef

49
#define COTHREAD_MAXTHREADS 16
50
#define COTHREAD_STACKSIZE (STACK_SIZE/COTHREAD_MAXTHREADS)
51

52
53
static void 	cothread_destroy 	(cothread_state *thread);

Wim Taymans's avatar
Wim Taymans committed
54
55
struct _cothread_context
{
56
57
  cothread_state *cothreads[COTHREAD_MAXTHREADS]; /* array of cothread states */
  int ncothreads;
58
59
60
61
62
  int current;
  GHashTable *data;
};


63
64
/* 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
65
66
67
 * (ie. private) for each thread.  The key itself is shared among threads,
 * so it only needs to be initialized once.
 */
68
static GPrivate *_cothread_ctx_key;
Erik Walthinsen's avatar
Erik Walthinsen committed
69

70
/* Disabling this define allows you to shut off a few checks in
71
 * cothread_switch.  This likely will speed things up fractionally */
72
/* #define COTHREAD_PARANOID */
73

74
/**
Wim Taymans's avatar
Wim Taymans committed
75
 * cothread_context_init:
76
 *
Erik Walthinsen's avatar
Erik Walthinsen committed
77
 * Create and initialize a new cothread context 
78
79
80
 *
 * Returns: the new cothread context
 */
Wim Taymans's avatar
Wim Taymans committed
81
82
cothread_context *
cothread_context_init (void)
83
{
84
85
86
  /*
   * initalize the whole of the cothreads context 
   */
87
88
89
90
91
92
93
94
  cothread_context *ctx;
  
  /* if there already is a cotread context for this thread,
   * just return it */
  ctx = g_private_get (_cothread_ctx_key);
  if(ctx) return ctx;

  ctx = (cothread_context *) g_malloc (sizeof (cothread_context));
95

96
  /* we consider the initiating process to be cothread 0 */
97
  ctx->ncothreads = 1;
98
  ctx->current = 0;
Wim Taymans's avatar
Wim Taymans committed
99
  ctx->data = g_hash_table_new (g_str_hash, g_str_equal);
100

Wim Taymans's avatar
Wim Taymans committed
101
  GST_INFO (GST_CAT_COTHREADS, "initializing cothreads");
102

103
104
105
106
107
108
  /* initialize the cothread key (for GThread space) if not done yet */
  /* FIXME this should be done in cothread_init() */
  if (_cothread_ctx_key == NULL) {
    _cothread_ctx_key = g_private_new (NULL);
    if (_cothread_ctx_key == NULL) {
      perror ("g_private_new");
109
110
111
112
      return NULL;
    }
  }

113
  /* set this thread's context pointer */
114
  g_private_set (_cothread_ctx_key, ctx);
115
116

  /* clear the cothread data */
117

118
  memset (ctx->cothreads, 0, sizeof (ctx->cothreads));
119

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  /*
   * 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;
  ctx->cothreads[0]->pc = 0;

  GST_INFO (GST_CAT_COTHREADS, "0th cothread is %p at sp:%p", 
            ctx->cothreads[0], ctx->cothreads[0]->sp);
136
137
138
139

  return ctx;
}

Wim Taymans's avatar
Wim Taymans committed
140
141
/**
 * cothread_context_free:
142
 * @ctx: the cothread context to free
Wim Taymans's avatar
Wim Taymans committed
143
144
145
 *
 * Free the cothread context.
 */
146
void
Wim Taymans's avatar
Wim Taymans committed
147
cothread_context_free (cothread_context *ctx)
148
149
150
{
  gint i;

Wim Taymans's avatar
Wim Taymans committed
151
152
  g_return_if_fail (ctx != NULL);

153
154
  GST_INFO (GST_CAT_COTHREADS, "free cothread context");

Wim Taymans's avatar
Wim Taymans committed
155
  for (i = 0; i < COTHREAD_MAXTHREADS; i++) {
156
157
    if (ctx->cothreads[i]) {
      cothread_destroy (ctx->cothreads[i]);
Wim Taymans's avatar
Wim Taymans committed
158
    }
159
160
161
162
163
  }
  g_hash_table_destroy (ctx->data);
  g_free (ctx);
}

Wim Taymans's avatar
Wim Taymans committed
164
165
166
167
/**
 * cothread_create:
 * @ctx: the cothread context
 *
Erik Walthinsen's avatar
Erik Walthinsen committed
168
 * Create a new cothread state in the given context
Wim Taymans's avatar
Wim Taymans committed
169
 *
170
 * Returns: the new cothread state or NULL on error
Wim Taymans's avatar
Wim Taymans committed
171
 */
172
cothread_state*
Wim Taymans's avatar
Wim Taymans committed
173
cothread_create (cothread_context *ctx)
174
{
175
  cothread_state *cothread;
176
177
  void *sp;
  void *mmaped = 0;
Wim Taymans's avatar
Wim Taymans committed
178
179
180
181
  guchar *stack_end;
  gint slot = 0;

  g_return_val_if_fail (ctx != NULL, NULL);
Erik Walthinsen's avatar
Erik Walthinsen committed
182

183
  if (ctx->ncothreads == COTHREAD_MAXTHREADS) {
Wim Taymans's avatar
Wim Taymans committed
184
185
    /* this is pretty fatal */
    g_warning ("cothread_create: attempt to create > COTHREAD_MAXTHREADS\n");
186
187
    return NULL;
  }
Wim Taymans's avatar
Wim Taymans committed
188
  /* find a free spot in the stack, note slot 0 has the main thread */
189
190
  for (slot = 1; slot < ctx->ncothreads; slot++) {
    if (ctx->cothreads[slot] == NULL)
Wim Taymans's avatar
Wim Taymans committed
191
      break;
192
    else if (ctx->cothreads[slot]->flags & COTHREAD_DESTROYED &&
193
		    slot != ctx->current) {
194
      cothread_destroy (ctx->cothreads[slot]);
195
196
      break;
    }
Wim Taymans's avatar
Wim Taymans committed
197
198
  }

199
  GST_DEBUG (GST_CAT_COTHREADS, "Found free cothread slot %d", slot);
200

Wim Taymans's avatar
Wim Taymans committed
201
  sp = CURRENT_STACK_FRAME;
202
printf("stack pointer %p\n",sp);
Wim Taymans's avatar
Wim Taymans committed
203
204
205
206
  /* FIXME this may not be 64bit clean
   *       could use casts to uintptr_t from inttypes.h
   *       if only all platforms had inttypes.h
   */
207
  /* FIXME: a little explanation on what this REALLY means would be nice ;) */
Wim Taymans's avatar
Wim Taymans committed
208
209
  stack_end = (guchar *) ((gulong) sp & ~(STACK_SIZE - 1));

210
211
212
  /* cothread stack space of the thread is mapped in reverse, with cothread 0
   * stack space at the top */
  cothread = (cothread_state *) (stack_end + ((slot - 1) * COTHREAD_STACKSIZE));
213
  GST_DEBUG (GST_CAT_COTHREADS, 
214
             "mmap   cothread slot stack from %p to %p (size 0x%lx)", 
215
	     cothread, cothread + COTHREAD_STACKSIZE, 
216
	     (long) COTHREAD_STACKSIZE);
Wim Taymans's avatar
Wim Taymans committed
217

Thomas Vander Stichele's avatar
hahaha    
Thomas Vander Stichele committed
218
  GST_DEBUG (GST_CAT_COTHREADS, "going into mmap");
219
220
  /* the mmap is used to reserve part of the stack
   * ie. we state explicitly that we are going to use it */
221
  mmaped = mmap ((void *) cothread, COTHREAD_STACKSIZE,
222
223
	          PROT_READ | PROT_WRITE | PROT_EXEC, 
		  MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Thomas Vander Stichele's avatar
hahaha    
Thomas Vander Stichele committed
224
  GST_DEBUG (GST_CAT_COTHREADS, "coming out of mmap");
225
  if (mmaped == MAP_FAILED) {
Wim Taymans's avatar
Wim Taymans committed
226
227
    perror ("mmap'ing cothread stack space");
    return NULL;
Erik Walthinsen's avatar
Erik Walthinsen committed
228
  }
229
230
  if (mmaped != cothread) {
    g_warning ("could not mmap requested memory for cothread");
231
232
    return NULL;
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
233

234
  cothread->magic_number = COTHREAD_MAGIC_NUMBER;
235
  GST_DEBUG (GST_CAT_COTHREADS, "create  cothread %d with magic number 0x%x",
236
237
238
239
240
241
242
243
             slot, cothread->magic_number);
  cothread->ctx = ctx;
  cothread->cothreadnum = slot;
  cothread->flags = 0;
  cothread->priv = NULL;
  cothread->sp = ((guchar *) cothread + COTHREAD_STACKSIZE);
  cothread->top_sp = cothread->sp; /* for debugging purposes 
				      to detect stack overruns */
Erik Walthinsen's avatar
Erik Walthinsen committed
244

245
  GST_INFO (GST_CAT_COTHREADS, 
246
            "created cothread #%d in slot %d: %p at sp:%p", 
247
	    ctx->ncothreads, slot, cothread, cothread->sp);
Wim Taymans's avatar
Wim Taymans committed
248

249
250
  ctx->cothreads[slot] = cothread;
  ctx->ncothreads++;
Wim Taymans's avatar
Wim Taymans committed
251

252
  return cothread;
Wim Taymans's avatar
Wim Taymans committed
253
254
255
256
}

/**
 * cothread_free:
257
 * @cothread: the cothread state
Wim Taymans's avatar
Wim Taymans committed
258
259
260
261
 *
 * Free the given cothread state
 */
void
262
cothread_free (cothread_state *cothread)
Wim Taymans's avatar
Wim Taymans committed
263
{
264
  g_return_if_fail (cothread != NULL);
Wim Taymans's avatar
Wim Taymans committed
265

266
267
  GST_INFO (GST_CAT_COTHREADS, "flag cothread %d for destruction", 
            cothread->cothreadnum);
268

Wim Taymans's avatar
Wim Taymans committed
269
  /* we simply flag the cothread for destruction here */
270
  cothread->flags |= COTHREAD_DESTROYED;
Wim Taymans's avatar
Wim Taymans committed
271
272
273
}

static void
274
cothread_destroy (cothread_state *cothread)
Wim Taymans's avatar
Wim Taymans committed
275
276
{
  cothread_context *ctx;
277
  gint cothreadnum;
Wim Taymans's avatar
Wim Taymans committed
278

279
  g_return_if_fail (cothread != NULL);
Erik Walthinsen's avatar
Erik Walthinsen committed
280

281
282
  cothreadnum = cothread->cothreadnum;
  ctx = cothread->ctx;
Wim Taymans's avatar
Wim Taymans committed
283

284
285
  GST_INFO (GST_CAT_COTHREADS, "destroy cothread %d %p %d", 
            cothreadnum, cothread, ctx->current);
Wim Taymans's avatar
Wim Taymans committed
286

287
288
289
  /* we have to unlock here because we might be switched out 
   * with the lock held */
  cothread_unlock (cothread);
Wim Taymans's avatar
Wim Taymans committed
290

291
  if (cothreadnum == 0) 
292
293
294
  {
    GST_INFO (GST_CAT_COTHREADS,
	      "trying to destroy cothread 0 with %d cothreads left", 
295
296
	     ctx->ncothreads);
    if (ctx->ncothreads > 1)
297
298
299
300
301
302
303
    {
      /* we're trying to destroy cothread 0 when there are still cothreads
       * active, so kill those first */
      int i;

      for (i = 1; i < COTHREAD_MAXTHREADS; ++i)
      {
304
	if (ctx->cothreads[i] != NULL)
305
	{
306
	  cothread_destroy (ctx->cothreads[i]);
307
308
	  GST_INFO (GST_CAT_COTHREADS,
	            "destroyed cothread %d, %d cothreads left\n", 
309
		    i, ctx->ncothreads);
310
311
312
	}
      }
    }
313
314
    g_assert (ctx->ncothreads == 1);
    g_free (cothread);
Wim Taymans's avatar
Wim Taymans committed
315
316
  }
  else {
317
318
  /*  int res; 
   *  Replaced with version below until cothreads issues solved */
319
   int res = 0;
320
321
322
    
    /* doing cleanups of the cothread create */
    GST_DEBUG (GST_CAT_COTHREADS, "destroy cothread %d with magic number 0x%x",
323
324
             cothreadnum, cothread->magic_number);
    g_assert (cothread->magic_number == COTHREAD_MAGIC_NUMBER);
325

326
    g_assert (cothread->priv == NULL);
327
328

    GST_DEBUG (GST_CAT_COTHREADS, 
329
               "munmap cothread slot stack from %p to %p (size 0x%lx)", 
330
  	       cothread, cothread + COTHREAD_STACKSIZE, 
331
	       (long) COTHREAD_STACKSIZE);
332
333
/*    res = munmap (thread, COTHREAD_STACKSIZE);
 *    Commented out waiting for resolution for cothread issue */
334
335
336
337
338
339
    if (res != 0)
    {
      switch (res)
      {
	case EINVAL:
	  g_warning ("munmap doesn't like start %p or length %d\n",
340
	             cothread, COTHREAD_STACKSIZE);
341
342
	  break;
	default:
343
344
	  g_warning ("Thomas was too lazy to check for all errors, "
	             "so I can't tell you what is wrong.\n");
345
346
347
	  break;
      }
    }
Wim Taymans's avatar
Wim Taymans committed
348
  }
349
  GST_DEBUG (GST_CAT_COTHREADS, "munmap done\n");
Wim Taymans's avatar
Wim Taymans committed
350

351
352
  ctx->cothreads[cothreadnum] = NULL;
  ctx->ncothreads--;
Erik Walthinsen's avatar
Erik Walthinsen committed
353
354
}

Wim Taymans's avatar
Wim Taymans committed
355
356
357
358
/**
 * cothread_setfunc:
 * @thread: the cothread state
 * @func: the function to call
Erik Walthinsen's avatar
Erik Walthinsen committed
359
360
 * @argc: argument count for the cothread function
 * @argv: arguments for the cothread function
Wim Taymans's avatar
Wim Taymans committed
361
362
363
 *
 * Set the cothread function
 */
Wim Taymans's avatar
Wim Taymans committed
364
365
void
cothread_setfunc (cothread_state * thread, cothread_func func, int argc, char **argv)
366
{
Erik Walthinsen's avatar
Erik Walthinsen committed
367
368
369
  thread->func = func;
  thread->argc = argc;
  thread->argv = argv;
Wim Taymans's avatar
Wim Taymans committed
370
  thread->pc = (void *) func;
Erik Walthinsen's avatar
Erik Walthinsen committed
371
372
}

373
374
375
376
377
378
/**
 * cothread_stop:
 * @thread: the cothread to stop
 *
 * Stop the cothread and reset the stack and program counter.
 */
379
380
381
382
383
384
385
386
void
cothread_stop (cothread_state * thread)
{
  thread->flags &= ~COTHREAD_STARTED;
  thread->pc = 0;
  thread->sp = thread->top_sp;
}

Erik Walthinsen's avatar
Erik Walthinsen committed
387
388
/**
 * cothread_main:
389
 * @ctx: cothread context to find main cothread of.
Erik Walthinsen's avatar
Erik Walthinsen committed
390
 *
391
 * Gets the main thread.
392
 *
393
 * Returns: the #cothread_state of the main (0th) cothread.
394
 */
Wim Taymans's avatar
Wim Taymans committed
395
396
cothread_state *
cothread_main (cothread_context * ctx)
397
{
398
399
400
  GST_DEBUG (GST_CAT_COTHREADS, "returning %p, the 0th cothread", 
             ctx->cothreads[0]);
  return ctx->cothreads[0];
Erik Walthinsen's avatar
Erik Walthinsen committed
401
402
}

403
/**
Wim Taymans's avatar
Wim Taymans committed
404
 * cothread_current_main:
405
 *
406
 * Get the main thread in the current GThread.
407
 *
408
 * Returns: the #cothread_state of the main (0th) thread in the current GThread
409
 */
Wim Taymans's avatar
Wim Taymans committed
410
cothread_state *
411
cothread_current_main (void)
412
{
413
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
Wim Taymans's avatar
Wim Taymans committed
414

415
  return ctx->cothreads[0];
416
417
}

418
419
420
421
422
423
424
425
426
427
/**
 * cothread_current:
 *
 * Get the currenttly executing cothread
 *
 * Returns: the #cothread_state of the current cothread
 */
cothread_state *
cothread_current (void)
{
428
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
429

430
  return ctx->cothreads[ctx->current];
431
432
}

Wim Taymans's avatar
Wim Taymans committed
433
434
static void
cothread_stub (void)
435
{
436
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
437
  register cothread_state *thread = ctx->cothreads[ctx->current];
Erik Walthinsen's avatar
Erik Walthinsen committed
438

Wim Taymans's avatar
Wim Taymans committed
439
  GST_DEBUG_ENTER ("");
440

Erik Walthinsen's avatar
Erik Walthinsen committed
441
  thread->flags |= COTHREAD_STARTED;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
442

Wim Taymans's avatar
Wim Taymans committed
443
444
  while (TRUE) {
    thread->func (thread->argc, thread->argv);
445
    /* we do this to avoid ever returning, we just switch to 0th thread */
Wim Taymans's avatar
Wim Taymans committed
446
    cothread_switch (cothread_main (ctx));
447
  }
Wim Taymans's avatar
Wim Taymans committed
448
  GST_DEBUG_LEAVE ("");
449
450
451
452
453
}

/**
 * cothread_getcurrent:
 *
454
455
 * Get the current cothread id
 *
456
457
 * Returns: the current cothread id
 */
458
int cothread_getcurrent (void) __attribute__ ((no_instrument_function));
Wim Taymans's avatar
Wim Taymans committed
459
460
int
cothread_getcurrent (void)
461
{
462
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
Wim Taymans's avatar
Wim Taymans committed
463
464
465

  if (!ctx)
    return -1;
466
  return ctx->current;
Erik Walthinsen's avatar
Erik Walthinsen committed
467
468
}

Wim Taymans's avatar
Wim Taymans committed
469
/**
Wim Taymans's avatar
Wim Taymans committed
470
 * cothread_set_private:
Wim Taymans's avatar
Wim Taymans committed
471
472
473
 * @thread: the cothread state
 * @data: the data
 *
Wim Taymans's avatar
Wim Taymans committed
474
 * set private data for the cothread.
Wim Taymans's avatar
Wim Taymans committed
475
 */
476
void
477
478
479
480
481
cothread_set_private (cothread_state *thread, gpointer data)
{
  thread->priv = data;
}

Wim Taymans's avatar
Wim Taymans committed
482
483
484
485
486
487
488
489
/**
 * cothread_context_set_data:
 * @thread: the cothread state
 * @key: a key for the data
 * @data: the data
 *
 * adds data to a cothread
 */
490
491
void
cothread_context_set_data (cothread_state *thread, gchar *key, gpointer data)
492
{
493
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
494

Wim Taymans's avatar
Wim Taymans committed
495
  g_hash_table_insert (ctx->data, key, data);
496
497
}

Wim Taymans's avatar
Wim Taymans committed
498
/**
Wim Taymans's avatar
Wim Taymans committed
499
 * cothread_get_private:
Wim Taymans's avatar
Wim Taymans committed
500
501
 * @thread: the cothread state
 *
Wim Taymans's avatar
Wim Taymans committed
502
 * get the private data from the cothread
Wim Taymans's avatar
Wim Taymans committed
503
 *
Wim Taymans's avatar
Wim Taymans committed
504
 * Returns: the private data of the cothread
Wim Taymans's avatar
Wim Taymans committed
505
 */
506
gpointer
507
508
509
510
511
cothread_get_private (cothread_state *thread)
{
  return thread->priv;
}

Wim Taymans's avatar
Wim Taymans committed
512
513
514
515
516
517
518
519
520
/**
 * 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
 */
521
522
gpointer
cothread_context_get_data (cothread_state * thread, gchar * key)
523
{
524
  cothread_context *ctx = g_private_get (_cothread_ctx_key);
525

Wim Taymans's avatar
Wim Taymans committed
526
  return g_hash_table_lookup (ctx->data, key);
527
528
}

529
530
531
532
533
534
535
536
537
538
/**
 * cothreads_stackquery:
 * @stack: Will be set to point to the allocated stack location
 * @stacksize: Will be set to the size of the allocated stack
 *
 *  Returns: #TRUE on success, #FALSE otherwise.
 */
gboolean
cothread_stackquery (void **stack, glong* stacksize)
{
539
540
541
542
543
544
545
  /* use either
   * - posix_memalign to allocate a 2M-aligned, 2M stack 
   * or
   * - valloc 
   *
   * memory allocated by either of these two can be freed using free () 
   * FIXME: define how the stack grows */
546

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
547
#ifdef HAVE_POSIX_MEMALIGN
548
  int retval = posix_memalign (stack, STACK_SIZE, STACK_SIZE);
549
550
551
  if (retval != 0)
  {
    g_warning ("Could not posix_memalign stack !\n");
552
553
554
555
556
557
    if (retval == EINVAL)
      g_warning ("The alignment parameter %d was not a power of two !\n",
	         STACK_SIZE);
    if (retval == ENOMEM)
      g_warning ("Insufficient memory to allocate the request of %d !\n",
	         STACK_SIZE);
558
559
560
    *stacksize = 0;
    return FALSE;
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
561
  GST_DEBUG (GST_CAT_THREAD, "have  posix_memalign at %p of size %d",
562
             (void *) *stack, STACK_SIZE);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
563
564
565
566
567
568
569
#else
  if ((*stack = valloc (STACK_SIZE)) != 0)
  {
    g_warning ("Could not valloc stack !\n");
    return FALSE;
  }
  GST_DEBUG (GST_CAT_THREAD, "have  valloc at %p of size %d",
570
             (void *) *stack, STACK_SIZE);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
571
572
#endif

573
  GST_DEBUG (GST_CAT_COTHREADS, 
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
574
             "Got new cothread stack from %p to %p (size %ld)",
575
576
577
578
579
             *stack, *stack + STACK_SIZE - 1, (long) STACK_SIZE);
  *stacksize = STACK_SIZE;
  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
580
581
/**
 * cothread_switch:
Erik Walthinsen's avatar
Erik Walthinsen committed
582
 * @thread: cothread state to switch to
Wim Taymans's avatar
Wim Taymans committed
583
 *
Erik Walthinsen's avatar
Erik Walthinsen committed
584
 * Switches to the given cothread state
Wim Taymans's avatar
Wim Taymans committed
585
 */
Wim Taymans's avatar
Wim Taymans committed
586
587
void
cothread_switch (cothread_state * thread)
588
{
Erik Walthinsen's avatar
Erik Walthinsen committed
589
590
  cothread_context *ctx;
  cothread_state *current;
591
  int enter;
Erik Walthinsen's avatar
Erik Walthinsen committed
592

593
#ifdef COTHREAD_PARANOID
Wim Taymans's avatar
Wim Taymans committed
594
595
  if (thread == NULL)
    goto nothread;
596
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
597
  ctx = thread->ctx;
598
#ifdef COTHREAD_PARANOID
Wim Taymans's avatar
Wim Taymans committed
599
600
  if (ctx == NULL)
    goto nocontext;
601
#endif
Erik Walthinsen's avatar
Erik Walthinsen committed
602

603
  current = ctx->cothreads[ctx->current];
604
#ifdef COTHREAD_PARANOID
Wim Taymans's avatar
Wim Taymans committed
605
606
  if (current == NULL)
    goto nocurrent;
607
#endif
Wim Taymans's avatar
Wim Taymans committed
608
609
  if (current == thread)
    goto selfswitch;
Erik Walthinsen's avatar
Erik Walthinsen committed
610

611

612
  /* find the number of the thread to switch to */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
613
614
  GST_INFO (GST_CAT_COTHREAD_SWITCH, 
            "switching from cothread #%d to cothread #%d",
615
616
	    ctx->current, thread->cothreadnum);
  ctx->current = thread->cothreadnum;
Erik Walthinsen's avatar
Erik Walthinsen committed
617
618

  /* save the current stack pointer, frame pointer, and pc */
Erik Walthinsen's avatar
Erik Walthinsen committed
619
#ifdef GST_ARCH_PRESETJMP
Wim Taymans's avatar
Wim Taymans committed
620
  GST_ARCH_PRESETJMP ();
Erik Walthinsen's avatar
Erik Walthinsen committed
621
#endif
Wim Taymans's avatar
Wim Taymans committed
622
  enter = setjmp (current->jmp);
623
  if (enter != 0) {
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
624
    GST_DEBUG (GST_CAT_COTHREADS, 
625
626
	       "enter cothread #%d %d %p<->%p (%d) %p", 
	       current->cothreadnum, enter, current->sp, current->top_sp, 
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
627
	       (char*) current->top_sp - (char*) current->sp, current->jmp);
Erik Walthinsen's avatar
Erik Walthinsen committed
628
    return;
629
  }
630
631
632
  GST_DEBUG (GST_CAT_COTHREADS, "exit cothread #%d %d %p<->%p (%d) %p", 
             current->cothreadnum, enter, current->sp, current->top_sp, 
	     (char *) current->top_sp - (char *) current->sp, current->jmp);
Erik Walthinsen's avatar
Erik Walthinsen committed
633
634
  enter = 1;

635
  if (current->flags & COTHREAD_DESTROYED) {
Wim Taymans's avatar
Wim Taymans committed
636
    cothread_destroy (current);
637
  }
Wim Taymans's avatar
Wim Taymans committed
638

Thomas Vander Stichele's avatar
hahaha    
Thomas Vander Stichele committed
639
  GST_DEBUG (GST_CAT_COTHREADS, "set stack to %p", thread->sp);
Erik Walthinsen's avatar
Erik Walthinsen committed
640
641
  /* restore stack pointer and other stuff of new cothread */
  if (thread->flags & COTHREAD_STARTED) {
Thomas Vander Stichele's avatar
hahaha    
Thomas Vander Stichele committed
642
    GST_DEBUG (GST_CAT_COTHREADS, "in thread %p", thread->jmp);
643
    /* switch to it */
Wim Taymans's avatar
Wim Taymans committed
644
    longjmp (thread->jmp, 1);
Wim Taymans's avatar
Wim Taymans committed
645
646
  }
  else {
Wim Taymans's avatar
Wim Taymans committed
647
    GST_ARCH_SETUP_STACK ((char*)thread->sp);
Wim Taymans's avatar
Wim Taymans committed
648
    GST_ARCH_SET_SP (thread->sp);
649
    /* start it */
Wim Taymans's avatar
Wim Taymans committed
650
    GST_ARCH_CALL (cothread_stub);
Thomas Vander Stichele's avatar
hahaha    
Thomas Vander Stichele committed
651
    GST_DEBUG (GST_CAT_COTHREADS, "exit thread ");
652
    ctx->current = 0;
Erik Walthinsen's avatar
Erik Walthinsen committed
653
  }
654
655
656
657
658

  return;

#ifdef COTHREAD_PARANOID
nothread:
659
  g_warning ("cothread: can't switch to NULL cothread!\n");
660
661
  return;
nocontext:
662
  g_warning ("cothread: there's no context, help!\n");
Wim Taymans's avatar
Wim Taymans committed
663
  exit (2);
664
nocurrent:
665
  g_warning ("cothread: there's no current thread, help!\n");
Wim Taymans's avatar
Wim Taymans committed
666
  exit (2);
667
668
#endif /* COTHREAD_PARANOID */
selfswitch:
669
  g_warning ("cothread: trying to switch to same thread, legal but not necessary\n");
670
  return;
Erik Walthinsen's avatar
Erik Walthinsen committed
671
}
672

Wim Taymans's avatar
Wim Taymans committed
673
674
675
676
677
678
/**
 * cothread_lock:
 * @thread: cothread state to lock
 *
 * Locks the cothread state.
 */
679
void
Wim Taymans's avatar
Wim Taymans committed
680
cothread_lock (cothread_state * thread)
681
682
683
{
}

Wim Taymans's avatar
Wim Taymans committed
684
685
686
687
688
689
690
691
/**
 * cothread_trylock:
 * @thread: cothread state to try to lock
 *
 * Try to lock the cothread state
 *
 * Returns: TRUE if the cothread could be locked.
 */
692
gboolean
Wim Taymans's avatar
Wim Taymans committed
693
cothread_trylock (cothread_state * thread)
694
{
695
  return TRUE;
696
697
}

Wim Taymans's avatar
Wim Taymans committed
698
699
700
701
702
703
/**
 * cothread_unlock:
 * @thread: cothread state to unlock
 *
 * Unlock the cothread state.
 */
704
void
Wim Taymans's avatar
Wim Taymans committed
705
cothread_unlock (cothread_state * thread)
706
707
{
}