* configure.in (_THREAD_SAFE): Define when pthreads are enabled in
[bpt/guile.git] / libguile / threads.c
CommitLineData
d823b11b 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002 Free Software Foundation, Inc.
7bfd3b9e
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program 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
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
7bfd3b9e
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
1bbd0b84 42
7bfd3b9e
JB
43\f
44
d823b11b
MV
45/* This file implements nice Scheme level threads on top of the gastly
46 C level threads.
7f0f3eaa
JB
47*/
48
d823b11b
MV
49#include <unistd.h>
50#include <stdio.h>
51#include <assert.h>
52#include <sys/time.h>
5f05c406 53
a0599745 54#include "libguile/_scm.h"
d823b11b
MV
55#include "libguile/validate.h"
56#include "libguile/root.h"
57#include "libguile/eval.h"
58#include "libguile/async.h"
59#include "libguile/ports.h"
60#include "libguile/threads.h"
a0599745 61#include "libguile/dynwind.h"
d823b11b 62#include "libguile/iselect.h"
7bfd3b9e 63
d823b11b 64/*** Queues */
7bfd3b9e 65
d823b11b
MV
66static SCM
67make_queue ()
68{
69 return scm_cons (SCM_EOL, SCM_EOL);
70}
7bfd3b9e 71
d823b11b
MV
72static SCM
73enqueue (SCM q, SCM t)
74{
75 SCM c = scm_cons (t, SCM_EOL);
76 if (SCM_NULLP (SCM_CDR (q)))
77 SCM_SETCDR (q, c);
78 else
79 SCM_SETCDR (SCM_CAR (q), c);
80 SCM_SETCAR (q, c);
81 return c;
82}
7bfd3b9e 83
d823b11b
MV
84static void
85remqueue (SCM q, SCM c)
86{
87 SCM p, prev = q;
88 for (p = SCM_CDR (q); !SCM_NULLP (p); p = SCM_CDR (p))
89 {
90 if (SCM_EQ_P (p, c))
91 {
92 if (SCM_EQ_P (c, SCM_CAR (q)))
93 SCM_SETCAR (q, SCM_CDR (c));
94 SCM_SETCDR (prev, SCM_CDR (c));
95 return;
96 }
97 prev = p;
98 }
99 abort ();
100}
101
102static SCM
103dequeue (SCM q)
104{
105 SCM c = SCM_CDR (q);
106 if (SCM_NULLP (c))
107 return SCM_BOOL_F;
108 else
109 {
110 SCM_SETCDR (q, SCM_CDR (c));
111 if (SCM_NULLP (SCM_CDR (q)))
112 SCM_SETCAR (q, SCM_EOL);
113 return SCM_CAR (c);
114 }
115}
7bfd3b9e 116
d823b11b
MV
117/*** Threads */
118
9bc4701c
MD
119#define THREAD_INITIALIZED_P(t) (t->base != NULL)
120
121struct scm_thread {
d823b11b
MV
122
123 /* Blocking.
124 */
125 scm_t_cond sleep_cond;
126 struct scm_thread *next_waiting;
127
9bc4701c
MD
128 /* This mutex represents this threads right to access the heap.
129 That right can temporarily be taken away by the GC. */
130 scm_t_mutex heap_mutex;
131 int clear_freelists_p; /* set if GC was done while thread was asleep */
132
d823b11b
MV
133 scm_root_state *root;
134 SCM handle;
135 scm_t_thread thread;
136 SCM result;
137 int exited;
138
139 SCM joining_threads;
140
141 /* For keeping track of the stack and registers. */
142 SCM_STACKITEM *base;
143 SCM_STACKITEM *top;
144 jmp_buf regs;
145
9bc4701c 146};
d823b11b
MV
147
148static SCM
149make_thread (SCM creation_protects)
150{
151 SCM z;
152 scm_thread *t;
153 z = scm_make_smob (scm_tc16_thread);
154 t = SCM_THREAD_DATA (z);
155 t->handle = z;
156 t->result = creation_protects;
157 t->base = NULL;
158 t->joining_threads = make_queue ();
9bc4701c
MD
159 scm_i_plugin_cond_init (&t->sleep_cond, 0);
160 scm_i_plugin_mutex_init (&t->heap_mutex, 0);
161 t->clear_freelists_p = 0;
d823b11b
MV
162 t->exited = 0;
163 return z;
164}
165
166static void
9bc4701c
MD
167init_thread_creatant (SCM thread,
168 SCM_STACKITEM *base)
d823b11b 169{
9bc4701c
MD
170 scm_thread *t = SCM_THREAD_DATA (thread);
171 t->thread = scm_thread_self ();
d823b11b
MV
172 t->base = base;
173 t->top = NULL;
174}
4079f87e 175
d823b11b
MV
176static SCM
177thread_mark (SCM obj)
178{
179 scm_thread *t = SCM_THREAD_DATA (obj);
180 scm_gc_mark (t->result);
181 scm_gc_mark (t->joining_threads);
9bc4701c 182 return t->root->handle; /* mark root-state of this thread */
d823b11b
MV
183}
184
185static int
186thread_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
187{
188 scm_thread *t = SCM_THREAD_DATA (exp);
189 scm_puts ("#<thread ", port);
190 scm_intprint ((unsigned long)t, 16, port);
191 scm_putc ('>', port);
192 return 1;
193}
194
195static size_t
196thread_free (SCM obj)
197{
198 scm_thread *t = SCM_THREAD_DATA (obj);
199 if (!t->exited)
200 abort ();
201 scm_gc_free (t, sizeof (*t), "thread");
202 return 0;
203}
204
d823b11b 205/*** Scheduling */
f7eca35d 206
9bc4701c
MD
207#define cur_thread (SCM_CURRENT_THREAD->handle)
208scm_t_key scm_i_thread_key;
209scm_t_key scm_i_root_state_key;
d823b11b
MV
210
211void
212scm_i_set_thread_data (void *data)
213{
9bc4701c
MD
214 scm_thread *t = SCM_CURRENT_THREAD;
215 scm_setspecific (scm_i_root_state_key, data);
d823b11b
MV
216 t->root = (scm_root_state *)data;
217}
218
219static void
220resume (scm_thread *t)
221{
d823b11b 222 t->top = NULL;
9bc4701c
MD
223 if (t->clear_freelists_p)
224 {
225 *SCM_FREELIST_LOC (scm_i_freelist) = SCM_EOL;
226 *SCM_FREELIST_LOC (scm_i_freelist2) = SCM_EOL;
227 t->clear_freelists_p = 0;
228 }
d823b11b
MV
229}
230
9bc4701c
MD
231void
232scm_i_enter_guile (scm_thread *t)
d823b11b 233{
9bc4701c 234 scm_i_plugin_mutex_lock (&t->heap_mutex);
d823b11b
MV
235 resume (t);
236}
237
238static scm_thread *
239suspend ()
240{
9bc4701c 241 scm_thread *c = SCM_CURRENT_THREAD;
d823b11b
MV
242
243 /* record top of stack for the GC */
244 c->top = (SCM_STACKITEM *)&c;
245 /* save registers. */
246 SCM_FLUSH_REGISTER_WINDOWS;
247 setjmp (c->regs);
248
249 return c;
250}
251
9bc4701c
MD
252scm_thread *
253scm_i_leave_guile ()
d823b11b 254{
9bc4701c
MD
255 scm_thread *t = suspend ();
256 scm_i_plugin_mutex_unlock (&t->heap_mutex);
257 return t;
d823b11b
MV
258}
259
260/* Put the current thread to sleep until it is explicitely unblocked.
261 */
262static int
263block ()
264{
265 int err;
266 scm_thread *t = suspend ();
9bc4701c 267 err = scm_i_plugin_cond_wait (&t->sleep_cond, &t->heap_mutex);
d823b11b
MV
268 resume (t);
269 return err;
270}
271
272/* Put the current thread to sleep until it is explicitely unblocked
273 or until a signal arrives or until time AT (absolute time) is
274 reached. Return 0 when it has been unblocked; errno otherwise.
275 */
276static int
9bc4701c 277timed_block (const struct timespec *at)
d823b11b
MV
278{
279 int err;
280 scm_thread *t = suspend ();
9bc4701c 281 err = scm_i_plugin_cond_timedwait (&t->sleep_cond, &t->heap_mutex, at);
d823b11b
MV
282 resume (t);
283 return err;
284}
285
286/* Unblock a sleeping thread.
287 */
288static void
289unblock (scm_thread *t)
290{
9bc4701c 291 scm_i_plugin_cond_signal (&t->sleep_cond);
d823b11b
MV
292}
293
294/*** Thread creation */
295
9bc4701c 296static scm_t_mutex thread_admin_mutex;
d823b11b
MV
297static SCM all_threads;
298static int thread_count;
299
300typedef struct launch_data {
301 SCM thread;
302 SCM rootcont;
303 scm_t_catch_body body;
304 void *body_data;
305 scm_t_catch_handler handler;
306 void *handler_data;
307} launch_data;
308
309static SCM
310body_bootstrip (launch_data* data)
311{
312 /* First save the new root continuation */
313 data->rootcont = scm_root->rootcont;
314 return (data->body) (data->body_data);
315}
316
317static SCM
318handler_bootstrip (launch_data* data, SCM tag, SCM throw_args)
319{
320 scm_root->rootcont = data->rootcont;
321 return (data->handler) (data->handler_data, tag, throw_args);
322}
323
324static void
325really_launch (SCM_STACKITEM *base, launch_data *data)
326{
9bc4701c
MD
327 SCM thread;
328 scm_thread *t;
329 thread = data->thread;
330 t = SCM_THREAD_DATA (thread);
331 SCM_FREELIST_CREATE (scm_i_freelist);
332 SCM_FREELIST_CREATE (scm_i_freelist2);
333 scm_setspecific (scm_i_thread_key, t);
334 scm_setspecific (scm_i_root_state_key, t->root);
335 scm_i_plugin_mutex_lock (&t->heap_mutex); /* ensure that we "own" the heap */
336 init_thread_creatant (thread, base); /* must own the heap */
337
d823b11b
MV
338 data->rootcont = SCM_BOOL_F;
339 t->result =
340 scm_internal_cwdr ((scm_t_catch_body) body_bootstrip,
341 data,
342 (scm_t_catch_handler) handler_bootstrip,
343 data, base);
094b640d 344 scm_i_leave_guile (); /* release the heap */
d823b11b
MV
345 free (data);
346
9bc4701c
MD
347 scm_i_plugin_mutex_lock (&thread_admin_mutex);
348 all_threads = scm_delq_x (thread, all_threads);
d823b11b
MV
349 t->exited = 1;
350 thread_count--;
9bc4701c
MD
351 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
352 /* We're leaving with heap_mutex still locked. */
c4c52ebe 353 scm_thread_detach (t->thread);
d823b11b
MV
354}
355
9bc4701c 356static void *
d823b11b
MV
357launch_thread (void *p)
358{
359 really_launch ((SCM_STACKITEM *)&p, (launch_data *)p);
9bc4701c 360 return 0;
d823b11b
MV
361}
362
363static SCM
364create_thread (scm_t_catch_body body, void *body_data,
365 scm_t_catch_handler handler, void *handler_data,
366 SCM protects)
367{
368 SCM thread;
369
370 /* Make new thread. The first thing the new thread will do is to
371 lock guile_mutex. Thus, we can safely complete its
372 initialization after creating it. While the new thread starts,
373 all its data is protected via all_threads.
374 */
375
376 {
377 scm_t_thread th;
c4c52ebe 378 SCM root, old_winds;
d823b11b 379 launch_data *data;
9bc4701c 380 scm_thread *t;
d823b11b
MV
381 int err;
382
383 /* Unwind wind chain. */
384 old_winds = scm_dynwinds;
385 scm_dowinds (SCM_EOL, scm_ilength (scm_root->dynwinds));
386
387 /* Allocate thread locals. */
388 root = scm_make_root (scm_root->handle);
389 data = scm_malloc (sizeof (launch_data));
390
391 /* Make thread. */
392 thread = make_thread (protects);
393 data->thread = thread;
394 data->body = body;
395 data->body_data = body_data;
396 data->handler = handler;
397 data->handler_data = handler_data;
9bc4701c
MD
398 t = SCM_THREAD_DATA (thread);
399 /* must initialize root state pointer before the thread is linked
400 into all_threads */
401 t->root = SCM_ROOT_STATE (root);
402
403 /* In order to avoid the need of synchronization between parent
404 and child thread, we need to insert the child into all_threads
405 before creation. */
c4c52ebe
MD
406 {
407 SCM new_threads = scm_cons (thread, SCM_BOOL_F); /* could cause GC */
408 scm_thread *parent = scm_i_leave_guile (); /* to prevent deadlock */
409 scm_i_plugin_mutex_lock (&thread_admin_mutex);
410 SCM_SETCDR (new_threads, all_threads);
411 all_threads = new_threads;
412 thread_count++;
413 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
414 scm_i_enter_guile (parent);
415 }
9bc4701c
MD
416
417 err = scm_i_plugin_thread_create (&th, 0, launch_thread, (void *) data);
418 if (err != 0)
d823b11b 419 {
9bc4701c
MD
420 scm_i_plugin_mutex_lock (&thread_admin_mutex);
421 all_threads = scm_delq_x (thread, all_threads);
422 ((scm_thread *) SCM_THREAD_DATA(thread))->exited = 1;
423 thread_count--;
424 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
d823b11b 425 }
d823b11b
MV
426
427 /* Return to old dynamic context. */
428 scm_dowinds (old_winds, - scm_ilength (old_winds));
429
430 if (err)
431 {
432 errno = err;
433 scm_syserror ("create-thread");
434 }
435 }
436
437 return thread;
438}
439
440SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 2, 0, 0,
441 (SCM thunk, SCM handler),
442"Evaluate @var{(thunk)} in a new thread, and new dynamic context, "
443"returning a new thread object representing the thread. "
444"If an error occurs during evaluation, call error-thunk, passing it an "
445"error code describing the condition. "
446"If this happens, the error-thunk is called outside the scope of the new "
447"root -- it is called in the same dynamic context in which "
448"with-new-thread was evaluated, but not in the callers thread. "
449"All the evaluation rules for dynamic roots apply to threads.")
450#define FUNC_NAME s_scm_call_with_new_thread
451{
452 SCM_ASSERT (SCM_NFALSEP (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
453 SCM_ASSERT (SCM_NFALSEP (scm_procedure_p (handler)), handler, SCM_ARG2,
454 FUNC_NAME);
455
456 return create_thread ((scm_t_catch_body) scm_call_0, thunk,
457 (scm_t_catch_handler) scm_apply_1, handler,
458 scm_cons (thunk, handler));
459}
460#undef FUNC_NAME
461
d823b11b 462SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
5f05c406 463 (SCM thread),
d823b11b
MV
464"Suspend execution of the calling thread until the target @var{thread} "
465"terminates, unless the target @var{thread} has already terminated. ")
466#define FUNC_NAME s_scm_join_thread
5f05c406 467{
d823b11b
MV
468 scm_thread *t;
469 SCM res;
470
471 SCM_VALIDATE_THREAD (1, thread);
472 if (SCM_EQ_P (cur_thread, thread))
473 SCM_MISC_ERROR ("can not join the current thread", SCM_EOL);
474
475 t = SCM_THREAD_DATA (thread);
476 if (!t->exited)
477 {
9bc4701c
MD
478 scm_thread *c = scm_i_leave_guile ();
479 while (!THREAD_INITIALIZED_P (t))
480 SCM_TICK;
481 scm_thread_join (t->thread, 0);
482 scm_i_enter_guile (c);
d823b11b
MV
483 }
484 res = t->result;
485 t->result = SCM_BOOL_F;
486 return res;
5f05c406
MV
487}
488#undef FUNC_NAME
489
9bc4701c 490/*** Fair mutexes */
4079f87e 491
d823b11b
MV
492/* We implement our own mutex type since we want them to be 'fair', we
493 want to do fancy things while waiting for them (like running
494 asyncs) and we want to support waiting on many things at once.
495 Also, we might add things that are nice for debugging.
496*/
4079f87e 497
9bc4701c 498typedef struct fair_mutex {
d823b11b 499 /* the thread currently owning the mutex, or SCM_BOOL_F. */
9bc4701c
MD
500 scm_t_mutex lock;
501 int lockedp;
d823b11b
MV
502 SCM owner;
503 /* how much the owner owns us. */
504 int level;
505 /* the threads waiting for this mutex. */
506 SCM waiting;
9bc4701c 507} fair_mutex;
5f05c406 508
d823b11b 509static SCM
9bc4701c 510fair_mutex_mark (SCM mx)
d823b11b 511{
9bc4701c 512 fair_mutex *m = SCM_MUTEX_DATA (mx);
d823b11b
MV
513 scm_gc_mark (m->owner);
514 return m->waiting;
515}
4079f87e 516
9bc4701c 517SCM_DEFINE (scm_make_fair_mutex, "make-fair-mutex", 0, 0, 0,
d823b11b 518 (void),
9bc4701c
MD
519 "Create a new fair mutex object. ")
520#define FUNC_NAME s_scm_make_fair_mutex
d823b11b 521{
9bc4701c
MD
522 SCM mx = scm_make_smob (scm_tc16_fair_mutex);
523 fair_mutex *m = SCM_MUTEX_DATA (mx);
524 scm_i_plugin_mutex_init (&m->lock, 0);
525 m->lockedp = 0;
d823b11b
MV
526 m->owner = SCM_BOOL_F;
527 m->level = 0;
528 m->waiting = make_queue ();
529 return mx;
530}
531#undef FUNC_NAME
4079f87e 532
9bc4701c
MD
533static int
534fair_mutex_lock (fair_mutex *m)
d823b11b 535{
9bc4701c
MD
536 scm_i_plugin_mutex_lock (&m->lock);
537#if 0
538 /* Need to wait if another thread is just temporarily unlocking.
539 This is happens very seldom and only when the other thread is
540 between scm_mutex_unlock and scm_i_plugin_mutex_lock below. */
541 while (m->lockedp)
542 SCM_TICK;
543 m->lockedp = 1;
544#endif
545
d823b11b
MV
546 if (m->owner == SCM_BOOL_F)
547 m->owner = cur_thread;
548 else if (m->owner == cur_thread)
549 m->level++;
550 else
551 {
552 while (1)
553 {
554 SCM c = enqueue (m->waiting, cur_thread);
9bc4701c
MD
555 int err;
556 /* Note: It's important that m->lock is never locked for
557 any longer amount of time since that could prevent GC */
558 scm_i_plugin_mutex_unlock (&m->lock);
559 err = block ();
d823b11b 560 if (m->owner == cur_thread)
9bc4701c
MD
561 return 0;
562 scm_i_plugin_mutex_lock (&m->lock);
d823b11b 563 remqueue (m->waiting, c);
9bc4701c 564 scm_i_plugin_mutex_unlock (&m->lock);
d823b11b 565 if (err)
9bc4701c 566 return err;
d823b11b 567 SCM_ASYNC_TICK;
9bc4701c 568 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
569 }
570 }
9bc4701c
MD
571 scm_i_plugin_mutex_unlock (&m->lock);
572 return 0;
d823b11b 573}
7bfd3b9e 574
9bc4701c
MD
575static int
576fair_mutex_trylock (fair_mutex *m)
d823b11b 577{
9bc4701c 578 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
579 if (m->owner == SCM_BOOL_F)
580 m->owner = cur_thread;
581 else if (m->owner == cur_thread)
582 m->level++;
583 else
9bc4701c
MD
584 {
585 scm_i_plugin_mutex_unlock (&m->lock);
586 return EBUSY;
587 }
588 scm_i_plugin_mutex_unlock (&m->lock);
589 return 0;
d823b11b 590}
d823b11b 591
9bc4701c
MD
592static int
593fair_mutex_unlock (fair_mutex *m)
5f05c406 594{
9bc4701c 595 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
596 if (m->owner != cur_thread)
597 {
9bc4701c
MD
598 scm_i_plugin_mutex_unlock (&m->lock);
599 return EPERM;
d823b11b
MV
600 }
601 else if (m->level > 0)
602 m->level--;
603 else
604 {
605 SCM next = dequeue (m->waiting);
606 if (!SCM_FALSEP (next))
607 {
608 m->owner = next;
609 unblock (SCM_THREAD_DATA (next));
d823b11b
MV
610 }
611 else
612 m->owner = SCM_BOOL_F;
613 }
9bc4701c
MD
614 scm_i_plugin_mutex_unlock (&m->lock);
615 return 0;
5f05c406
MV
616}
617
9bc4701c 618/*** Fair condition variables */
7bfd3b9e 619
d823b11b
MV
620/* Like mutexes, we implement our own condition variables using the
621 primitives above.
622*/
5f05c406 623
9bc4701c
MD
624typedef struct fair_cond {
625 scm_t_mutex lock;
d823b11b
MV
626 /* the threads waiting for this condition. */
627 SCM waiting;
9bc4701c 628} fair_cond;
5f05c406 629
d823b11b 630static SCM
9bc4701c 631fair_cond_mark (SCM cv)
5f05c406 632{
9bc4701c 633 fair_cond *c = SCM_CONDVAR_DATA (cv);
d823b11b 634 return c->waiting;
5f05c406
MV
635}
636
9bc4701c
MD
637SCM_DEFINE (scm_make_fair_condition_variable, "make-fair-condition-variable", 0, 0, 0,
638 (void),
639 "Make a new fair condition variable.")
640#define FUNC_NAME s_scm_make_fair_condition_variable
641{
642 SCM cv = scm_make_smob (scm_tc16_fair_condvar);
643 fair_cond *c = SCM_CONDVAR_DATA (cv);
644 scm_i_plugin_mutex_init (&c->lock, 0);
645 c->waiting = make_queue ();
646 return cv;
647}
648#undef FUNC_NAME
649
650static int
651fair_cond_timedwait (fair_cond *c,
652 fair_mutex *m,
653 const struct timespec *waittime)
654{
655 int err;
656 scm_i_plugin_mutex_lock (&c->lock);
657
658 while (1)
659 {
660 enqueue (c->waiting, cur_thread);
661 scm_i_plugin_mutex_unlock (&c->lock);
662 fair_mutex_unlock (m); /*fixme* - not thread safe */
663 if (waittime == NULL)
664 err = block ();
665 else
666 err = timed_block (waittime);
667 fair_mutex_lock (m);
668 if (err)
669 return err;
670 /* XXX - check whether we have been signalled. */
671 break;
672 }
673 return err;
674}
675
676static int
677fair_cond_signal (fair_cond *c)
678{
679 SCM th;
680 scm_i_plugin_mutex_lock (&c->lock);
681 if (!SCM_FALSEP (th = dequeue (c->waiting)))
682 unblock (SCM_THREAD_DATA (th));
683 scm_i_plugin_mutex_unlock (&c->lock);
684 return 0;
685}
686
687static int
688fair_cond_broadcast (fair_cond *c)
689{
690 SCM th;
691 scm_i_plugin_mutex_lock (&c->lock);
692 while (!SCM_FALSEP (th = dequeue (c->waiting)))
693 unblock (SCM_THREAD_DATA (th));
694 scm_i_plugin_mutex_unlock (&c->lock);
695 return 0;
696}
697
698/*** Mutexes */
699
700SCM_DEFINE (scm_make_mutex, "make-mutex", 0, 0, 0,
701 (void),
702 "Create a new mutex object. ")
703#define FUNC_NAME s_scm_make_mutex
704{
705 SCM mx = scm_make_smob (scm_tc16_mutex);
706 scm_i_plugin_mutex_init (SCM_MUTEX_DATA (mx), 0);
707 return mx;
708}
709#undef FUNC_NAME
710
711/*fixme* change documentation */
712SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
713 (SCM mx),
714"Lock @var{mutex}. If the mutex is already locked, the calling thread "
715"blocks until the mutex becomes available. The function returns when "
716"the calling thread owns the lock on @var{mutex}. Locking a mutex that "
717"a thread already owns will succeed right away and will not block the "
718"thread. That is, Guile's mutexes are @emph{recursive}. ")
719#define FUNC_NAME s_scm_lock_mutex
720{
721 int err;
722 SCM_VALIDATE_MUTEX (1, mx);
723
724 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
725 err = fair_mutex_lock (SCM_MUTEX_DATA (mx));
726 else
727 {
728 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
729 scm_thread *t = scm_i_leave_guile ();
730 err = scm_i_plugin_mutex_lock (m);
731 scm_i_enter_guile (t);
732 }
733
734 if (err)
735 {
736 errno = err;
737 SCM_SYSERROR;
738 }
739 return SCM_BOOL_T;
740}
741#undef FUNC_NAME
742
743SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
744 (SCM mx),
745"Try to lock @var{mutex}. If the mutex is already locked by someone "
746"else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
747#define FUNC_NAME s_scm_try_mutex
748{
749 int err;
750 SCM_VALIDATE_MUTEX (1, mx);
751
752 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
753 err = fair_mutex_trylock (SCM_MUTEX_DATA (mx));
754 else
755 {
756 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
757 scm_thread *t = scm_i_leave_guile ();
758 err = scm_i_plugin_mutex_trylock (m);
759 scm_i_enter_guile (t);
760 }
761
762 if (err == EBUSY)
763 return SCM_BOOL_F;
764
765 if (err)
766 {
767 errno = err;
768 SCM_SYSERROR;
769 }
770
771 return SCM_BOOL_T;
772}
773#undef FUNC_NAME
774
775SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
776 (SCM mx),
777"Unlocks @var{mutex} if the calling thread owns the lock on "
778"@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
779"thread results in undefined behaviour. Once a mutex has been unlocked, "
780"one thread blocked on @var{mutex} is awakened and grabs the mutex "
781"lock. Every call to @code{lock-mutex} by this thread must be matched "
782"with a call to @code{unlock-mutex}. Only the last call to "
783"@code{unlock-mutex} will actually unlock the mutex. ")
784#define FUNC_NAME s_scm_unlock_mutex
785{
786 int err;
787 SCM_VALIDATE_MUTEX (1, mx);
788
789 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
790 {
791 err = fair_mutex_unlock (SCM_MUTEX_DATA (mx));
792 if (err == EPERM)
793 {
794 fair_mutex *m = SCM_MUTEX_DATA (mx);
795 if (m->owner != cur_thread)
796 {
797 if (m->owner == SCM_BOOL_F)
798 SCM_MISC_ERROR ("mutex not locked", SCM_EOL);
799 else
800 SCM_MISC_ERROR ("mutex not locked by this thread", SCM_EOL);
801 }
802 }
803 }
804 else
805 {
806 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
807 err = scm_i_plugin_mutex_unlock (m);
808 }
809
810 if (err)
811 {
812 errno = err;
813 SCM_SYSERROR;
814 }
815 return SCM_BOOL_T;
816}
817#undef FUNC_NAME
818
819/*** Condition variables */
820
d823b11b
MV
821SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
822 (void),
823 "Make a new condition variable.")
824#define FUNC_NAME s_scm_make_condition_variable
5f05c406 825{
d823b11b 826 SCM cv = scm_make_smob (scm_tc16_condvar);
9bc4701c 827 scm_i_plugin_cond_init (SCM_CONDVAR_DATA (cv), 0);
d823b11b 828 return cv;
5f05c406 829}
d823b11b 830#undef FUNC_NAME
5f05c406 831
d823b11b
MV
832SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
833 (SCM cv, SCM mx, SCM t),
834"Wait until @var{cond-var} has been signalled. While waiting, "
835"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
836"is locked again when this function returns. When @var{time} is given, "
837"it specifies a point in time where the waiting should be aborted. It "
838"can be either a integer as returned by @code{current-time} or a pair "
839"as returned by @code{gettimeofday}. When the waiting is aborted the "
840"mutex is locked and @code{#f} is returned. When the condition "
841"variable is in fact signalled, the mutex is also locked and @code{#t} "
842"is returned. ")
843#define FUNC_NAME s_scm_timed_wait_condition_variable
5f05c406 844{
d823b11b
MV
845 struct timespec waittime;
846 int err;
847
848 SCM_VALIDATE_CONDVAR (1, cv);
849 SCM_VALIDATE_MUTEX (2, mx);
9bc4701c
MD
850 if (!((SCM_TYP16 (cv) == scm_tc16_condvar
851 && SCM_TYP16 (mx) == scm_tc16_mutex)
852 || (SCM_TYP16 (cv) == scm_tc16_fair_condvar
853 && SCM_TYP16 (mx) == scm_tc16_fair_mutex)))
854 SCM_MISC_ERROR ("Condition variable and mutex are of different kinds.",
855 SCM_EOL);
856
d823b11b
MV
857 if (!SCM_UNBNDP (t))
858 {
859 if (SCM_CONSP (t))
860 {
9bc4701c
MD
861 SCM_VALIDATE_UINT_COPY (3, SCM_CAR (t), waittime.tv_sec);
862 SCM_VALIDATE_UINT_COPY (3, SCM_CDR (t), waittime.tv_nsec);
d823b11b
MV
863 waittime.tv_nsec *= 1000;
864 }
865 else
866 {
867 SCM_VALIDATE_UINT_COPY (3, t, waittime.tv_sec);
868 waittime.tv_nsec = 0;
869 }
870 }
871
9bc4701c
MD
872 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
873 err = fair_cond_timedwait (SCM_CONDVAR_DATA (cv),
874 SCM_MUTEX_DATA (mx),
875 SCM_UNBNDP (t) ? NULL : &waittime);
876 else
877 {
878 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
879 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
880 scm_thread *t = scm_i_leave_guile ();
881 err = scm_i_plugin_cond_wait (c, m);
882 scm_i_enter_guile (t);
883 }
d823b11b 884
9bc4701c 885 if (err)
d823b11b 886 {
9bc4701c
MD
887 errno = err;
888 SCM_SYSERROR;
d823b11b 889 }
9bc4701c 890 return SCM_BOOL_T;
5f05c406 891}
d823b11b 892#undef FUNC_NAME
5f05c406 893
d823b11b
MV
894SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
895 (SCM cv),
896 "Wake up one thread that is waiting for @var{cv}")
897#define FUNC_NAME s_scm_signal_condition_variable
5f05c406 898{
d823b11b 899 SCM_VALIDATE_CONDVAR (1, cv);
9bc4701c
MD
900 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
901 fair_cond_signal (SCM_CONDVAR_DATA (cv));
902 else
903 {
904 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
905 scm_i_plugin_cond_signal (c);
906 }
d823b11b 907 return SCM_BOOL_T;
5f05c406 908}
d823b11b 909#undef FUNC_NAME
5f05c406 910
d823b11b
MV
911SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
912 (SCM cv),
913 "Wake up all threads that are waiting for @var{cv}. ")
914#define FUNC_NAME s_scm_broadcast_condition_variable
5f05c406 915{
d823b11b 916 SCM_VALIDATE_CONDVAR (1, cv);
9bc4701c
MD
917 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
918 fair_cond_broadcast (SCM_CONDVAR_DATA (cv));
919 else
920 {
921 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
922 scm_i_plugin_cond_broadcast (c);
923 }
d823b11b 924 return SCM_BOOL_T;
5f05c406 925}
d823b11b 926#undef FUNC_NAME
5f05c406 927
d823b11b
MV
928/*** Marking stacks */
929
930/* XXX - what to do with this? Do we need to handle this for blocked
931 threads as well?
932*/
933#ifdef __ia64__
934# define SCM_MARK_BACKING_STORE() do { \
935 ucontext_t ctx; \
936 SCM_STACKITEM * top, * bot; \
937 getcontext (&ctx); \
938 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
939 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
940 / sizeof (SCM_STACKITEM))); \
941 bot = (SCM_STACKITEM *) __libc_ia64_register_backing_store_base; \
942 top = (SCM_STACKITEM *) ctx.uc_mcontext.sc_ar_bsp; \
943 scm_mark_locations (bot, top - bot); } while (0)
944#else
945# define SCM_MARK_BACKING_STORE()
946#endif
947
948void
949scm_threads_mark_stacks (void)
5f05c406 950{
d823b11b
MV
951 volatile SCM c;
952 for (c = all_threads; !SCM_NULLP (c); c = SCM_CDR (c))
953 {
954 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (c));
9bc4701c 955 if (!THREAD_INITIALIZED_P (t))
d823b11b
MV
956 {
957 /* Not fully initialized yet. */
958 continue;
959 }
960 if (t->top == NULL)
961 {
9bc4701c
MD
962 long stack_len;
963#ifdef SCM_DEBUG
964 if (t->thread != scm_thread_self ())
965 abort ();
966#endif
d823b11b
MV
967 /* Active thread */
968 /* stack_len is long rather than sizet in order to guarantee
969 that &stack_len is long aligned */
970#ifdef STACK_GROWS_UP
9bc4701c
MD
971 stack_len = ((SCM_STACKITEM *) (&t) -
972 (SCM_STACKITEM *) thread->base);
d823b11b
MV
973
974 /* Protect from the C stack. This must be the first marking
975 * done because it provides information about what objects
976 * are "in-use" by the C code. "in-use" objects are those
977 * for which the information about length and base address must
978 * remain usable. This requirement is stricter than a liveness
979 * requirement -- in particular, it constrains the implementation
980 * of scm_resizuve.
981 */
982 SCM_FLUSH_REGISTER_WINDOWS;
983 /* This assumes that all registers are saved into the jmp_buf */
984 setjmp (scm_save_regs_gc_mark);
985 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
986 ((size_t) sizeof scm_save_regs_gc_mark
987 / sizeof (SCM_STACKITEM)));
988
989 scm_mark_locations (((size_t) t->base,
990 (sizet) stack_len));
991#else
9bc4701c
MD
992 stack_len = ((SCM_STACKITEM *) t->base -
993 (SCM_STACKITEM *) (&t));
d823b11b
MV
994
995 /* Protect from the C stack. This must be the first marking
996 * done because it provides information about what objects
997 * are "in-use" by the C code. "in-use" objects are those
998 * for which the information about length and base address must
999 * remain usable. This requirement is stricter than a liveness
1000 * requirement -- in particular, it constrains the implementation
1001 * of scm_resizuve.
1002 */
1003 SCM_FLUSH_REGISTER_WINDOWS;
1004 /* This assumes that all registers are saved into the jmp_buf */
1005 setjmp (scm_save_regs_gc_mark);
1006 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
1007 ((size_t) sizeof scm_save_regs_gc_mark
1008 / sizeof (SCM_STACKITEM)));
1009
1010 scm_mark_locations ((SCM_STACKITEM *) &t,
1011 stack_len);
1012#endif
1013 }
1014 else
1015 {
1016 /* Suspended thread */
1017#ifdef STACK_GROWS_UP
1018 long stack_len = t->top - t->base;
1019 scm_mark_locations (t->base, stack_len);
1020#else
1021 long stack_len = t->base - t->top;
1022 scm_mark_locations (t->top, stack_len);
1023#endif
1024 scm_mark_locations ((SCM_STACKITEM *) t->regs,
1025 ((size_t) sizeof(t->regs)
1026 / sizeof (SCM_STACKITEM)));
1027 }
1028 }
5f05c406
MV
1029}
1030
d823b11b
MV
1031/*** Select */
1032
911782b7 1033int
d823b11b
MV
1034scm_internal_select (int nfds,
1035 SELECT_TYPE *readfds,
1036 SELECT_TYPE *writefds,
1037 SELECT_TYPE *exceptfds,
1038 struct timeval *timeout)
5f05c406 1039{
d823b11b 1040 int res, eno;
9bc4701c
MD
1041 scm_thread *c = scm_i_leave_guile ();
1042 res = scm_i_plugin_select (nfds, readfds, writefds, exceptfds, timeout);
d823b11b 1043 eno = errno;
9bc4701c 1044 scm_i_enter_guile (c);
d823b11b
MV
1045 SCM_ASYNC_TICK;
1046 errno = eno;
1047 return res;
5f05c406
MV
1048}
1049
9bc4701c
MD
1050/* Low-level C API */
1051
1052SCM
1053scm_spawn_thread (scm_t_catch_body body, void *body_data,
1054 scm_t_catch_handler handler, void *handler_data)
1055{
1056 return create_thread (body, body_data, handler, handler_data, SCM_BOOL_F);
1057}
1058
9bc4701c
MD
1059int
1060scm_mutex_lock (scm_t_mutex *m)
1061{
1062 scm_thread *t = scm_i_leave_guile ();
1063 int res = scm_i_plugin_mutex_lock (m);
1064 scm_i_enter_guile (t);
1065 return res;
1066}
1067
1068int
1069scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
1070{
1071 scm_thread *t = scm_i_leave_guile ();
1072 scm_i_plugin_cond_wait (c, m);
1073 scm_i_enter_guile (t);
1074 return 0;
1075}
1076
1077int
06babecc 1078scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, const struct timespec *wt)
9bc4701c
MD
1079{
1080 scm_thread *t = scm_i_leave_guile ();
06babecc 1081 int res = scm_i_plugin_cond_timedwait (c, m, wt);
9bc4701c
MD
1082 scm_i_enter_guile (t);
1083 return res;
1084}
9bc4701c
MD
1085
1086void
1087scm_enter_guile ()
1088{
1089 scm_i_enter_guile (SCM_CURRENT_THREAD);
1090}
1091
1092void
1093scm_leave_guile ()
1094{
1095 scm_i_leave_guile ();
1096}
1097
d823b11b
MV
1098unsigned long
1099scm_thread_usleep (unsigned long usecs)
5f05c406 1100{
d823b11b
MV
1101 struct timeval tv;
1102 tv.tv_usec = usecs % 1000000;
1103 tv.tv_sec = usecs / 1000000;
1104 scm_internal_select (0, NULL, NULL, NULL, &tv);
1105 return tv.tv_usec + tv.tv_sec*1000000;
5f05c406
MV
1106}
1107
d823b11b
MV
1108unsigned long
1109scm_thread_sleep (unsigned long secs)
6c214b62 1110{
d823b11b
MV
1111 struct timeval tv;
1112 tv.tv_usec = 0;
1113 tv.tv_sec = secs;
1114 scm_internal_select (0, NULL, NULL, NULL, &tv);
1115 return tv.tv_sec;
6c214b62
MD
1116}
1117
d823b11b
MV
1118/*** Misc */
1119
1120SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1121 (void),
1122 "Return the thread that called this function.")
1123#define FUNC_NAME s_scm_current_thread
1124{
1125 return cur_thread;
1126}
1127#undef FUNC_NAME
1128
1129SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1130 (void),
1131 "Return a list of all threads.")
9bc4701c 1132#define FUNC_NAME s_scm_all_threads
d823b11b
MV
1133{
1134 return all_threads;
1135}
1136#undef FUNC_NAME
1137
1138scm_root_state *
1139scm_i_thread_root (SCM thread)
1140{
9bc4701c 1141 return ((scm_thread *) SCM_THREAD_DATA (thread))->root;
d823b11b
MV
1142}
1143
1144SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1145 (SCM thread),
1146 "Return @code{#t} iff @var{thread} has exited.\n")
1147#define FUNC_NAME s_scm_thread_exited_p
1148{
1149 return SCM_BOOL (scm_c_thread_exited_p (thread));
1150}
1151#undef FUNC_NAME
1152
911782b7 1153int
d823b11b
MV
1154scm_c_thread_exited_p (SCM thread)
1155#define FUNC_NAME s_scm_thread_exited_p
5f05c406 1156{
d823b11b
MV
1157 scm_thread *t;
1158 SCM_VALIDATE_THREAD (1, thread);
1159 t = SCM_THREAD_DATA (thread);
1160 return t->exited;
5f05c406 1161}
d823b11b 1162#undef FUNC_NAME
5f05c406 1163
9bc4701c
MD
1164static scm_t_cond wake_up_cond;
1165int scm_i_thread_go_to_sleep;
9bc4701c
MD
1166static scm_t_mutex gc_section_mutex;
1167static scm_thread *gc_section_owner;
1168static int gc_section_count = 0;
1169static int threads_initialized_p = 0;
1170
1171void
1172scm_i_thread_put_to_sleep ()
1173{
1174 SCM_REC_CRITICAL_SECTION_START (gc_section);
1175 if (threads_initialized_p && gc_section_count == 1)
1176 {
c4c52ebe
MD
1177 SCM threads;
1178 scm_i_plugin_mutex_lock (&thread_admin_mutex);
1179 threads = all_threads;
9bc4701c
MD
1180 /* Signal all threads to go to sleep */
1181 scm_i_thread_go_to_sleep = 1;
1182 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1183 if (SCM_CAR (threads) != cur_thread)
1184 {
1185 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
9bc4701c
MD
1186 scm_i_plugin_mutex_lock (&t->heap_mutex);
1187 }
9bc4701c 1188 scm_i_thread_go_to_sleep = 0;
c4c52ebe 1189 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
9bc4701c
MD
1190 }
1191}
1192
b0dc3d71
MD
1193void
1194scm_i_thread_invalidate_freelists ()
1195{
c4c52ebe 1196 /* Don't need to lock thread_admin_mutex here since we are sinle threaded */
b0dc3d71
MD
1197 SCM threads = all_threads;
1198 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1199 if (SCM_CAR (threads) != cur_thread)
1200 {
1201 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1202 t->clear_freelists_p = 1;
1203 }
1204}
1205
9bc4701c
MD
1206void
1207scm_i_thread_wake_up ()
1208{
1209 if (threads_initialized_p && gc_section_count == 1)
1210 {
c4c52ebe
MD
1211 SCM threads;
1212 /* Need to lock since woken threads can die and be deleted from list */
1213 scm_i_plugin_mutex_lock (&thread_admin_mutex);
1214 threads = all_threads;
9bc4701c
MD
1215 scm_i_plugin_cond_broadcast (&wake_up_cond);
1216 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1217 if (SCM_CAR (threads) != cur_thread)
1218 {
1219 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1220 scm_i_plugin_mutex_unlock (&t->heap_mutex);
1221 }
c4c52ebe 1222 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
9bc4701c
MD
1223 }
1224 SCM_REC_CRITICAL_SECTION_END (gc_section);
1225}
1226
1227void
1228scm_i_thread_sleep_for_gc ()
1229{
1230 scm_thread *t;
1231 t = suspend ();
9bc4701c 1232 scm_i_plugin_cond_wait (&wake_up_cond, &t->heap_mutex);
b0dc3d71 1233 resume (t);
9bc4701c
MD
1234}
1235
1236/* The mother of all recursive critical sections */
1237scm_t_mutex scm_i_section_mutex;
1238
1239scm_t_mutex scm_i_critical_section_mutex;
1240scm_t_mutex scm_i_defer_mutex;
1241int scm_i_defer_count = 0;
1242scm_thread *scm_i_defer_owner = 0;
1243
d823b11b 1244/*** Initialization */
7bfd3b9e 1245
9bc4701c
MD
1246void
1247scm_threads_prehistory ()
1248{
1249 scm_thread *t;
1250 scm_i_plugin_mutex_init (&thread_admin_mutex, 0);
1251 scm_i_plugin_mutex_init (&gc_section_mutex, 0);
1252 scm_i_plugin_cond_init (&wake_up_cond, 0);
1253 scm_i_plugin_mutex_init (&scm_i_critical_section_mutex, 0);
1254 thread_count = 1;
1255 scm_i_plugin_key_create (&scm_i_thread_key, 0);
1256 scm_i_plugin_key_create (&scm_i_root_state_key, 0);
1257 scm_i_plugin_mutex_init (&scm_i_defer_mutex, 0);
1258 scm_i_plugin_mutex_init (&scm_i_section_mutex, 0);
1259 /* Allocate a fake thread object to be used during bootup. */
1260 t = malloc (sizeof (scm_thread));
1261 t->base = NULL;
1262 t->clear_freelists_p = 0;
1263 scm_setspecific (scm_i_thread_key, t);
1264}
1265
d823b11b
MV
1266scm_t_bits scm_tc16_thread;
1267scm_t_bits scm_tc16_mutex;
9bc4701c 1268scm_t_bits scm_tc16_fair_mutex;
d823b11b 1269scm_t_bits scm_tc16_condvar;
9bc4701c 1270scm_t_bits scm_tc16_fair_condvar;
7bfd3b9e 1271
7bfd3b9e 1272void
d823b11b 1273scm_init_threads (SCM_STACKITEM *base)
7bfd3b9e 1274{
9bc4701c 1275 SCM thread;
d823b11b 1276 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_thread));
9bc4701c
MD
1277 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (scm_t_mutex));
1278 scm_tc16_fair_mutex = scm_make_smob_type ("fair-mutex",
1279 sizeof (fair_mutex));
d823b11b 1280 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
9bc4701c
MD
1281 sizeof (scm_t_cond));
1282 scm_tc16_fair_condvar = scm_make_smob_type ("fair-condition-variable",
1283 sizeof (fair_cond));
d823b11b 1284
9bc4701c
MD
1285 thread = make_thread (SCM_BOOL_F);
1286 /* Replace initial fake thread with a real thread object */
1287 free (SCM_CURRENT_THREAD);
1288 scm_setspecific (scm_i_thread_key, SCM_THREAD_DATA (thread));
1289 scm_i_enter_guile (SCM_CURRENT_THREAD);
d823b11b 1290
d823b11b 1291 /* root is set later from init.c */
9bc4701c 1292 init_thread_creatant (thread, base);
d823b11b
MV
1293 thread_count = 1;
1294 scm_gc_register_root (&all_threads);
9bc4701c 1295 all_threads = scm_cons (thread, SCM_EOL);
d823b11b
MV
1296
1297 scm_set_smob_mark (scm_tc16_thread, thread_mark);
1298 scm_set_smob_print (scm_tc16_thread, thread_print);
1299 scm_set_smob_free (scm_tc16_thread, thread_free);
1300
9bc4701c
MD
1301 scm_set_smob_mark (scm_tc16_fair_mutex, fair_mutex_mark);
1302
1303 scm_set_smob_mark (scm_tc16_fair_condvar, fair_cond_mark);
d823b11b 1304
9bc4701c 1305 threads_initialized_p = 1;
7bfd3b9e 1306}
89e00824 1307
5f05c406
MV
1308void
1309scm_init_thread_procs ()
1310{
1311#include "libguile/threads.x"
1312}
1313
d823b11b
MV
1314/* XXX */
1315
1316void
1317scm_init_iselect ()
1318{
1319}
1320
89e00824
ML
1321/*
1322 Local Variables:
1323 c-file-style: "gnu"
1324 End:
1325*/