Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / libguile / coop.c
CommitLineData
2b829bbb 1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
7bfd3b9e 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7bfd3b9e 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
7bfd3b9e 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
7bfd3b9e
JB
17\f
18
2b829bbb 19/* $Id: coop.c,v 1.39 2006-04-17 00:05:38 kryde Exp $ */
7bfd3b9e
JB
20
21/* Cooperative thread library, based on QuickThreads */
22
dbb605f5 23#ifdef HAVE_CONFIG_H
fd291a5c
RB
24# include <config.h>
25#endif
26
e75341b3
MD
27#include <stdio.h>
28
6d71500e
JB
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32
df26ebfd
MD
33#include <errno.h>
34
a0599745
MD
35#include "qt/qt.h"
36#include "libguile/eval.h"
7bfd3b9e 37
6d71500e 38\f/* #define COOP_STKSIZE (0x10000) */
a74145b8 39#define COOP_STKSIZE (scm_eval_stack)
7bfd3b9e
JB
40
41/* `alignment' must be a power of 2. */
42#define COOP_STKALIGN(sp, alignment) \
43((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
44
45\f
46
47/* Queue access functions. */
48
7bfd3b9e
JB
49static void
50coop_qinit (coop_q_t *q)
7bfd3b9e
JB
51{
52 q->t.next = q->tail = &q->t;
53
54 q->t.all_prev = NULL;
55 q->t.all_next = NULL;
44e8413c
MD
56 q->t.nfds = 0;
57 q->t.readfds = NULL;
58 q->t.writefds = NULL;
59 q->t.exceptfds = NULL;
60 q->t.timeoutp = 0;
7bfd3b9e
JB
61}
62
63
44e8413c 64coop_t *
7bfd3b9e 65coop_qget (coop_q_t *q)
7bfd3b9e
JB
66{
67 coop_t *t;
68
69 t = q->t.next;
70 q->t.next = t->next;
f85a9bcf
MD
71 if (t->next == &q->t)
72 {
73 if (t == &q->t)
74 { /* If it was already empty .. */
75 return NULL; /* .. say so. */
76 }
77 q->tail = &q->t; /* Else now it is empty. */
7bfd3b9e 78 }
7bfd3b9e
JB
79 return (t);
80}
81
82
44e8413c 83void
7bfd3b9e 84coop_qput (coop_q_t *q, coop_t *t)
7bfd3b9e
JB
85{
86 q->tail->next = t;
87 t->next = &q->t;
88 q->tail = t;
89}
90
7bfd3b9e
JB
91static void
92coop_all_qput (coop_q_t *q, coop_t *t)
7bfd3b9e
JB
93{
94 if (q->t.all_next)
95 q->t.all_next->all_prev = t;
96 t->all_prev = NULL;
97 t->all_next = q->t.all_next;
98 q->t.all_next = t;
99}
100
7bfd3b9e
JB
101static void
102coop_all_qremove (coop_q_t *q, coop_t *t)
7bfd3b9e
JB
103{
104 if (t->all_prev)
105 t->all_prev->all_next = t->all_next;
106 else
107 q->t.all_next = t->all_next;
108 if (t->all_next)
109 t->all_next->all_prev = t->all_prev;
110}
111
df26ebfd
MD
112/* Insert thread t into the ordered queue q.
113 q is ordered after wakeup_time. Threads which aren't sleeping but
114 waiting for I/O go last into the queue. */
115void
116coop_timeout_qinsert (coop_q_t *q, coop_t *t)
117{
118 coop_t *pred = &q->t;
119 int sec = t->wakeup_time.tv_sec;
120 int usec = t->wakeup_time.tv_usec;
121 while (pred->next != &q->t
122 && pred->next->timeoutp
123 && (pred->next->wakeup_time.tv_sec < sec
124 || (pred->next->wakeup_time.tv_sec == sec
125 && pred->next->wakeup_time.tv_usec < usec)))
126 pred = pred->next;
127 t->next = pred->next;
128 pred->next = t;
129 if (t->next == &q->t)
130 q->tail = t;
131}
df26ebfd 132
3d7f708f 133\f
7bfd3b9e 134
3d7f708f 135/* Thread routines. */
7bfd3b9e 136
44e8413c
MD
137coop_q_t coop_global_runq; /* A queue of runable threads. */
138coop_q_t coop_global_sleepq; /* A queue of sleeping threads. */
139coop_q_t coop_tmp_queue; /* A temp working queue */
140coop_q_t coop_global_allq; /* A queue of all threads. */
141static coop_t coop_global_main; /* Thread for the process. */
142coop_t *coop_global_curr; /* Currently-executing thread. */
7bfd3b9e 143
f85a9bcf
MD
144#ifdef GUILE_PTHREAD_COMPAT
145static coop_q_t coop_deadq;
6219b5eb
MD
146static int coop_quitting_p = -1;
147static pthread_cond_t coop_cond_quit;
148static pthread_cond_t coop_cond_create;
149static pthread_mutex_t coop_mutex_create;
150static pthread_t coop_mother;
152812c0 151static int mother_awake_p = 0;
6219b5eb 152static coop_t *coop_child;
f85a9bcf
MD
153#endif
154
7bfd3b9e
JB
155static void *coop_starthelp (qt_t *old, void *ignore0, void *ignore1);
156static void coop_only (void *pu, void *pt, qt_userf_t *f);
157static void *coop_aborthelp (qt_t *sp, void *old, void *null);
158static void *coop_yieldhelp (qt_t *sp, void *old, void *blockq);
159
160
f85a9bcf
MD
161/* called on process termination. */
162#ifdef HAVE_ATEXIT
163static void
164coop_finish (void)
165#else
166#ifdef HAVE_ON_EXIT
167extern int on_exit (void (*procp) (), int arg);
168
169static void
170coop_finish (int status, void *arg)
171#else
172#error Dont know how to setup a cleanup handler on your system.
173#endif
174#endif
175{
176#ifdef GUILE_PTHREAD_COMPAT
6219b5eb
MD
177 coop_quitting_p = 1;
178 pthread_cond_signal (&coop_cond_create);
f85a9bcf
MD
179 pthread_cond_broadcast (&coop_cond_quit);
180#endif
181}
182
7bfd3b9e 183void
f85a9bcf 184coop_init ()
7bfd3b9e
JB
185{
186 coop_qinit (&coop_global_runq);
187 coop_qinit (&coop_global_sleepq);
44e8413c 188 coop_qinit (&coop_tmp_queue);
7bfd3b9e
JB
189 coop_qinit (&coop_global_allq);
190 coop_global_curr = &coop_global_main;
f85a9bcf
MD
191#ifdef GUILE_PTHREAD_COMPAT
192 coop_qinit (&coop_deadq);
193 pthread_cond_init (&coop_cond_quit, NULL);
6219b5eb
MD
194 pthread_cond_init (&coop_cond_create, NULL);
195 pthread_mutex_init (&coop_mutex_create, NULL);
f85a9bcf
MD
196#endif
197#ifdef HAVE_ATEXIT
198 atexit (coop_finish);
199#else
200#ifdef HAVE_ON_EXIT
201 on_exit (coop_finish, 0);
202#endif
203#endif
7bfd3b9e
JB
204}
205
7bfd3b9e
JB
206void
207coop_start()
7bfd3b9e
JB
208{
209 coop_t *next;
210
211 while ((next = coop_qget (&coop_global_runq)) != NULL) {
212 coop_global_curr = next;
213 QT_BLOCK (coop_starthelp, 0, 0, next->sp);
214 }
215}
216
217
7bfd3b9e
JB
218static void *
219coop_starthelp (qt_t *old, void *ignore0, void *ignore1)
7bfd3b9e
JB
220{
221 coop_global_main.sp = old;
222 coop_global_main.joining = NULL;
223 coop_qput (&coop_global_runq, &coop_global_main);
224 return NULL; /* not used, but keeps compiler happy */
225}
226
c8bf4ecd 227int
7bfd3b9e 228coop_mutex_init (coop_m *m)
df26ebfd
MD
229{
230 return coop_new_mutex_init (m, NULL);
231}
232
233int
234coop_new_mutex_init (coop_m *m, coop_mattr *attr)
7bfd3b9e
JB
235{
236 m->owner = NULL;
79cd5b8e 237 m->level = 0;
7bfd3b9e 238 coop_qinit(&(m->waiting));
c8bf4ecd 239 return 0;
7bfd3b9e
JB
240}
241
df26ebfd
MD
242int
243coop_mutex_trylock (coop_m *m)
244{
245 if (m->owner == NULL)
246 {
247 m->owner = coop_global_curr;
248 return 0;
249 }
79cd5b8e
MV
250 else if (m->owner == coop_global_curr)
251 {
252 m->level++;
253 return 0;
254 }
df26ebfd
MD
255 else
256 return EBUSY;
257}
258
c8bf4ecd 259int
7bfd3b9e 260coop_mutex_lock (coop_m *m)
7bfd3b9e
JB
261{
262 if (m->owner == NULL)
263 {
264 m->owner = coop_global_curr;
265 }
79cd5b8e
MV
266 else if (m->owner == coop_global_curr)
267 {
268 m->level++;
269 }
7bfd3b9e
JB
270 else
271 {
272 coop_t *old, *newthread;
273
274 /* Record the current top-of-stack before going to sleep */
275 coop_global_curr->top = &old;
276
44e8413c 277 newthread = coop_wait_for_runnable_thread();
d186aac6
MD
278 if (newthread == coop_global_curr)
279 coop_abort ();
7bfd3b9e
JB
280 old = coop_global_curr;
281 coop_global_curr = newthread;
282 QT_BLOCK (coop_yieldhelp, old, &(m->waiting), newthread->sp);
283 }
c8bf4ecd 284 return 0;
7bfd3b9e
JB
285}
286
287
c8bf4ecd 288int
7bfd3b9e 289coop_mutex_unlock (coop_m *m)
7bfd3b9e
JB
290{
291 coop_t *old, *newthread;
292
79cd5b8e 293 if (m->level == 0)
7bfd3b9e 294 {
79cd5b8e
MV
295 newthread = coop_qget (&(m->waiting));
296 if (newthread != NULL)
297 {
298 /* Record the current top-of-stack before going to sleep */
299 coop_global_curr->top = &old;
300
301 old = coop_global_curr;
302 coop_global_curr = newthread;
303 /* The new thread came into m->waiting through a lock operation.
304 It now owns this mutex. */
305 m->owner = coop_global_curr;
306 QT_BLOCK (coop_yieldhelp, old, &coop_global_runq, newthread->sp);
307 }
308 else
309 {
310 m->owner = NULL;
311 }
7bfd3b9e 312 }
79cd5b8e
MV
313 else if (m->level > 0)
314 m->level--;
7bfd3b9e 315 else
79cd5b8e
MV
316 abort (); /* XXX */
317
c8bf4ecd 318 return 0;
7bfd3b9e
JB
319}
320
321
c8bf4ecd
MD
322int
323coop_mutex_destroy (coop_m *m)
c8bf4ecd
MD
324{
325 return 0;
326}
327
328
c8bf4ecd 329int
7bfd3b9e 330coop_condition_variable_init (coop_c *c)
df26ebfd
MD
331{
332 return coop_new_condition_variable_init (c, NULL);
333}
334
335int
336coop_new_condition_variable_init (coop_c *c, coop_cattr *a)
7bfd3b9e
JB
337{
338 coop_qinit(&(c->waiting));
c8bf4ecd 339 return 0;
7bfd3b9e
JB
340}
341
b322f09a
MD
342int
343coop_condition_variable_wait_mutex (coop_c *c, coop_m *m)
7bfd3b9e
JB
344{
345 coop_t *old, *newthread;
346
b322f09a
MD
347 /* coop_mutex_unlock (m); */
348 newthread = coop_qget (&(m->waiting));
349 if (newthread != NULL)
350 {
351 m->owner = newthread;
352 }
353 else
354 {
355 m->owner = NULL;
df26ebfd 356 /*fixme* Should we really wait here? Isn't it OK just to proceed? */
b322f09a
MD
357 newthread = coop_wait_for_runnable_thread();
358 if (newthread == coop_global_curr)
359 coop_abort ();
b322f09a
MD
360 }
361 coop_global_curr->top = &old;
7bfd3b9e
JB
362 old = coop_global_curr;
363 coop_global_curr = newthread;
364 QT_BLOCK (coop_yieldhelp, old, &(c->waiting), newthread->sp);
c8bf4ecd 365
c8bf4ecd
MD
366 coop_mutex_lock (m);
367 return 0;
7bfd3b9e
JB
368}
369
df26ebfd
MD
370int
371coop_condition_variable_timed_wait_mutex (coop_c *c,
372 coop_m *m,
fd291a5c 373 const scm_t_timespec *abstime)
df26ebfd
MD
374{
375 coop_t *old, *t;
8f99e3f3 376#ifdef ETIMEDOUT
bc5329cc 377 int res = ETIMEDOUT;
8f99e3f3
SJ
378#elif defined (WSAETIMEDOUT)
379 int res = WSAETIMEDOUT;
380#else
381 int res = 0;
382#endif
df26ebfd
MD
383
384 /* coop_mutex_unlock (m); */
385 t = coop_qget (&(m->waiting));
386 if (t != NULL)
387 {
388 m->owner = t;
389 }
390 else
391 {
392 m->owner = NULL;
df26ebfd
MD
393 coop_global_curr->timeoutp = 1;
394 coop_global_curr->wakeup_time.tv_sec = abstime->tv_sec;
395 coop_global_curr->wakeup_time.tv_usec = abstime->tv_nsec / 1000;
396 coop_timeout_qinsert (&coop_global_sleepq, coop_global_curr);
397 t = coop_wait_for_runnable_thread();
df26ebfd
MD
398 }
399 if (t != coop_global_curr)
400 {
401 coop_global_curr->top = &old;
402 old = coop_global_curr;
403 coop_global_curr = t;
404 QT_BLOCK (coop_yieldhelp, old, &(c->waiting), t->sp);
405
406 /* Are we still in the sleep queue? */
407 old = &coop_global_sleepq.t;
408 for (t = old->next; t != &coop_global_sleepq.t; old = t, t = t->next)
409 if (t == coop_global_curr)
410 {
411 old->next = t->next; /* unlink */
412 res = 0;
413 break;
414 }
415 }
416 coop_mutex_lock (m);
417 return res;
418}
c8bf4ecd 419
c8bf4ecd 420int
79cd5b8e 421coop_condition_variable_broadcast (coop_c *c)
7bfd3b9e
JB
422{
423 coop_t *newthread;
424
425 while ((newthread = coop_qget (&(c->waiting))) != NULL)
426 {
427 coop_qput (&coop_global_runq, newthread);
428 }
c8bf4ecd
MD
429 return 0;
430}
431
79cd5b8e
MV
432int
433coop_condition_variable_signal (coop_c *c)
434{
435 return coop_condition_variable_broadcast (c);
436}
437
438
df26ebfd
MD
439/* {Keys}
440 */
441
442static int n_keys = 0;
443static int max_keys = 0;
444static void (**destructors) (void *) = 0;
445
446int
447coop_key_create (coop_k *keyp, void (*destructor) (void *value))
448{
449 if (n_keys >= max_keys)
450 {
451 int i;
452 max_keys = max_keys ? max_keys * 3 / 2 : 10;
453 destructors = realloc (destructors, sizeof (void *) * max_keys);
454 if (destructors == 0)
455 {
456 fprintf (stderr, "Virtual memory exceeded in coop_key_create\n");
457 exit (1);
458 }
459 for (i = n_keys; i < max_keys; ++i)
460 destructors[i] = NULL;
461 }
462 destructors[n_keys] = destructor;
463 *keyp = n_keys++;
464 return 0;
465}
466
467int
468coop_setspecific (coop_k key, const void *value)
469{
470 int n_keys = coop_global_curr->n_keys;
471 if (key >= n_keys)
472 {
473 int i;
474 coop_global_curr->n_keys = max_keys;
475 coop_global_curr->specific = realloc (n_keys
476 ? coop_global_curr->specific
477 : NULL,
478 sizeof (void *) * max_keys);
479 if (coop_global_curr->specific == 0)
480 {
481 fprintf (stderr, "Virtual memory exceeded in coop_setspecific\n");
482 exit (1);
483 }
484 for (i = n_keys; i < max_keys; ++i)
485 coop_global_curr->specific[i] = NULL;
486 }
487 coop_global_curr->specific[key] = (void *) value;
488 return 0;
489}
490
491void *
492coop_getspecific (coop_k key)
493{
494 return (key < coop_global_curr->n_keys
495 ? coop_global_curr->specific[key]
496 : NULL);
497}
498
499int
500coop_key_delete (coop_k key)
501{
502 return 0;
503}
504
c8bf4ecd 505
c8bf4ecd
MD
506int
507coop_condition_variable_destroy (coop_c *c)
c8bf4ecd
MD
508{
509 return 0;
7bfd3b9e
JB
510}
511
df26ebfd 512#ifdef GUILE_PTHREAD_COMPAT
f85a9bcf 513
e7bca227
LC
514#include "libguile/boehm-gc.h"
515
f85a9bcf 516/* 1K room for the cond wait routine */
e7dd0639
RB
517#if SCM_STACK_GROWS_UP
518# define COOP_STACK_ROOM (256)
f85a9bcf 519#else
e7dd0639 520# define COOP_STACK_ROOM (-256)
f85a9bcf
MD
521#endif
522
df26ebfd
MD
523static void *
524dummy_start (void *coop_thread)
525{
526 coop_t *t = (coop_t *) coop_thread;
3da01fa3 527 int res;
f85a9bcf 528 t->sp = (qt_t *) (&t + COOP_STACK_ROOM);
6219b5eb 529 pthread_mutex_init (&t->dummy_mutex, NULL);
df26ebfd 530 pthread_mutex_lock (&t->dummy_mutex);
6219b5eb 531 coop_child = 0;
3da01fa3
MD
532 do
533 res = pthread_cond_wait (&coop_cond_quit, &t->dummy_mutex);
534 while (res == EINTR);
df26ebfd
MD
535 return 0;
536}
6219b5eb
MD
537
538static void *
539mother (void *dummy)
540{
541 pthread_mutex_lock (&coop_mutex_create);
542 while (!coop_quitting_p)
543 {
51523cd1 544 int res;
6219b5eb
MD
545 pthread_create (&coop_child->dummy_thread,
546 NULL,
547 dummy_start,
548 coop_child);
152812c0 549 mother_awake_p = 0;
51523cd1
MD
550 do
551 res = pthread_cond_wait (&coop_cond_create, &coop_mutex_create);
552 while (res == EINTR);
6219b5eb
MD
553 }
554 return 0;
555}
556
df26ebfd 557#endif
7bfd3b9e 558
7bfd3b9e
JB
559coop_t *
560coop_create (coop_userf_t *f, void *pu)
7bfd3b9e
JB
561{
562 coop_t *t;
f85a9bcf 563#ifndef GUILE_PTHREAD_COMPAT
7bfd3b9e 564 void *sto;
f85a9bcf 565#endif
7bfd3b9e 566
f85a9bcf
MD
567#ifdef GUILE_PTHREAD_COMPAT
568 t = coop_qget (&coop_deadq);
569 if (t)
ac1aca35
MD
570 {
571 t->sp = t->base;
572 t->specific = 0;
573 t->n_keys = 0;
574 }
f85a9bcf
MD
575 else
576#endif
577 {
d900cd6d 578 t = scm_malloc (sizeof (coop_t));
ac1aca35 579 t->specific = NULL;
f85a9bcf 580 t->n_keys = 0;
df26ebfd 581#ifdef GUILE_PTHREAD_COMPAT
6219b5eb 582 coop_child = t;
152812c0 583 mother_awake_p = 1;
6219b5eb
MD
584 if (coop_quitting_p < 0)
585 {
586 coop_quitting_p = 0;
587 /* We can't create threads ourselves since the pthread
588 * corresponding to this stack might be sleeping.
589 */
590 pthread_create (&coop_mother, NULL, mother, NULL);
591 }
592 else
593 {
594 pthread_cond_signal (&coop_cond_create);
595 }
596 /* We can't use a pthreads condition variable since "this"
597 * pthread could already be asleep. We can't use a COOP
598 * condition variable because they are not safe against
599 * pre-emptive switching.
600 */
152812c0 601 while (coop_child || mother_awake_p)
6219b5eb 602 usleep (0);
df26ebfd 603#else
67329a9e 604 t->sto = scm_malloc (COOP_STKSIZE);
f85a9bcf
MD
605 sto = COOP_STKALIGN (t->sto, QT_STKALIGN);
606 t->sp = QT_SP (sto, COOP_STKSIZE - QT_STKALIGN);
df26ebfd 607#endif
f85a9bcf
MD
608 t->base = t->sp;
609 }
7bfd3b9e
JB
610 t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, coop_only);
611 t->joining = NULL;
612 coop_qput (&coop_global_runq, t);
613 coop_all_qput (&coop_global_allq, t);
614
615 return t;
616}
617
618
7bfd3b9e
JB
619static void
620coop_only (void *pu, void *pt, qt_userf_t *f)
7bfd3b9e
JB
621{
622 coop_global_curr = (coop_t *)pt;
623 (*(coop_userf_t *)f)(pu);
624 coop_abort();
625 /* NOTREACHED */
626}
627
628
7bfd3b9e
JB
629void
630coop_abort ()
7bfd3b9e
JB
631{
632 coop_t *old, *newthread;
633
634 /* Wake up any threads that are waiting to join this one */
635 if (coop_global_curr->joining)
636 {
637 while ((newthread = coop_qget ((coop_q_t *)(coop_global_curr->joining)))
638 != NULL)
639 {
640 coop_qput (&coop_global_runq, newthread);
641 }
f85a9bcf 642 free (coop_global_curr->joining);
7bfd3b9e
JB
643 }
644
d186aac6
MD
645 scm_I_am_dead = 1;
646 do {
647 newthread = coop_wait_for_runnable_thread();
648 } while (newthread == coop_global_curr);
649 scm_I_am_dead = 0;
f85a9bcf 650 coop_all_qremove (&coop_global_allq, coop_global_curr);
7bfd3b9e
JB
651 old = coop_global_curr;
652 coop_global_curr = newthread;
f85a9bcf 653 QT_ABORT (coop_aborthelp, old, (void *) NULL, newthread->sp);
7bfd3b9e
JB
654}
655
656
7bfd3b9e
JB
657static void *
658coop_aborthelp (qt_t *sp, void *old, void *null)
7bfd3b9e
JB
659{
660 coop_t *oldthread = (coop_t *) old;
661
ac1aca35
MD
662 if (oldthread->specific)
663 free (oldthread->specific);
f85a9bcf
MD
664#ifndef GUILE_PTHREAD_COMPAT
665 free (oldthread->sto);
666 free (oldthread);
667#else
f85a9bcf
MD
668 coop_qput (&coop_deadq, oldthread);
669#endif
670
7bfd3b9e
JB
671 return NULL;
672}
673
674
7bfd3b9e
JB
675void
676coop_join(coop_t *t)
7bfd3b9e
JB
677{
678 coop_t *old, *newthread;
679
7bfd3b9e
JB
680 /* Create a join list if necessary */
681 if (t->joining == NULL)
682 {
67329a9e 683 t->joining = scm_malloc(sizeof(coop_q_t));
7bfd3b9e
JB
684 coop_qinit((coop_q_t *) t->joining);
685 }
686
44e8413c 687 newthread = coop_wait_for_runnable_thread();
d186aac6
MD
688 if (newthread == coop_global_curr)
689 return;
7bfd3b9e
JB
690 old = coop_global_curr;
691 coop_global_curr = newthread;
692 QT_BLOCK (coop_yieldhelp, old, (coop_q_t *) t->joining, newthread->sp);
693}
694
7bfd3b9e
JB
695void
696coop_yield()
7bfd3b9e
JB
697{
698 coop_t *old = NULL;
699 coop_t *newthread;
700
701 newthread = coop_next_runnable_thread();
702
703 /* There may be no other runnable threads. Return if this is the
704 case. */
d186aac6
MD
705 if (newthread == coop_global_curr)
706 return;
7bfd3b9e
JB
707
708 old = coop_global_curr;
709
710 coop_global_curr = newthread;
711 QT_BLOCK (coop_yieldhelp, old, &coop_global_runq, newthread->sp);
712}
713
714
7bfd3b9e
JB
715static void *
716coop_yieldhelp (qt_t *sp, void *old, void *blockq)
7bfd3b9e
JB
717{
718 ((coop_t *)old)->sp = sp;
719 coop_qput ((coop_q_t *)blockq, (coop_t *)old);
720 return NULL;
721}
722
723/* Replacement for the system's sleep() function. Does the right thing
724 for the process - but not for the system (it busy-waits) */
725
44e8413c 726void *
7bfd3b9e 727coop_sleephelp (qt_t *sp, void *old, void *blockq)
7bfd3b9e
JB
728{
729 ((coop_t *)old)->sp = sp;
730 /* old is already on the sleep queue - so there's no need to
731 do anything extra here */
732 return NULL;
733}
734
6aa9316d
JB
735unsigned long
736scm_thread_usleep (unsigned long usec)
44e8413c
MD
737{
738 struct timeval timeout;
739 timeout.tv_sec = 0;
740 timeout.tv_usec = usec;
741 scm_internal_select (0, NULL, NULL, NULL, &timeout);
2c4e1a34
MD
742 return 0; /* Maybe we should calculate actual time slept,
743 but this is faster... :) */
44e8413c
MD
744}
745
6aa9316d
JB
746unsigned long
747scm_thread_sleep (unsigned long sec)
44e8413c
MD
748{
749 time_t now = time (NULL);
750 struct timeval timeout;
6aa9316d 751 unsigned long slept;
44e8413c
MD
752 timeout.tv_sec = sec;
753 timeout.tv_usec = 0;
754 scm_internal_select (0, NULL, NULL, NULL, &timeout);
755 slept = time (NULL) - now;
756 return slept > sec ? 0 : sec - slept;
757}
758
89e00824
ML
759/*
760 Local Variables:
761 c-file-style: "gnu"
762 End:
763*/