* modules.c (scm_export): Inserted a return statement.
[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);
344 free (data);
345
346 scm_thread_detach (t->thread);
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. */
d823b11b
MV
353}
354
9bc4701c 355static void *
d823b11b
MV
356launch_thread (void *p)
357{
358 really_launch ((SCM_STACKITEM *)&p, (launch_data *)p);
9bc4701c 359 return 0;
d823b11b
MV
360}
361
362static SCM
363create_thread (scm_t_catch_body body, void *body_data,
364 scm_t_catch_handler handler, void *handler_data,
365 SCM protects)
366{
367 SCM thread;
368
369 /* Make new thread. The first thing the new thread will do is to
370 lock guile_mutex. Thus, we can safely complete its
371 initialization after creating it. While the new thread starts,
372 all its data is protected via all_threads.
373 */
374
375 {
376 scm_t_thread th;
9bc4701c 377 SCM root, old_winds, new_threads;
d823b11b 378 launch_data *data;
9bc4701c 379 scm_thread *t;
d823b11b
MV
380 int err;
381
382 /* Unwind wind chain. */
383 old_winds = scm_dynwinds;
384 scm_dowinds (SCM_EOL, scm_ilength (scm_root->dynwinds));
385
386 /* Allocate thread locals. */
387 root = scm_make_root (scm_root->handle);
388 data = scm_malloc (sizeof (launch_data));
389
390 /* Make thread. */
391 thread = make_thread (protects);
392 data->thread = thread;
393 data->body = body;
394 data->body_data = body_data;
395 data->handler = handler;
396 data->handler_data = handler_data;
9bc4701c
MD
397 t = SCM_THREAD_DATA (thread);
398 /* must initialize root state pointer before the thread is linked
399 into all_threads */
400 t->root = SCM_ROOT_STATE (root);
401
402 /* In order to avoid the need of synchronization between parent
403 and child thread, we need to insert the child into all_threads
404 before creation. */
405 new_threads = scm_cons (thread, SCM_BOOL_F); /* could cause GC */
406 scm_i_plugin_mutex_lock (&thread_admin_mutex);
407 SCM_SETCDR (new_threads, all_threads);
408 all_threads = new_threads;
409 thread_count++;
410 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
411
412 err = scm_i_plugin_thread_create (&th, 0, launch_thread, (void *) data);
413 if (err != 0)
d823b11b 414 {
9bc4701c
MD
415 scm_i_plugin_mutex_lock (&thread_admin_mutex);
416 all_threads = scm_delq_x (thread, all_threads);
417 ((scm_thread *) SCM_THREAD_DATA(thread))->exited = 1;
418 thread_count--;
419 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
d823b11b 420 }
d823b11b
MV
421
422 /* Return to old dynamic context. */
423 scm_dowinds (old_winds, - scm_ilength (old_winds));
424
425 if (err)
426 {
427 errno = err;
428 scm_syserror ("create-thread");
429 }
430 }
431
432 return thread;
433}
434
435SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 2, 0, 0,
436 (SCM thunk, SCM handler),
437"Evaluate @var{(thunk)} in a new thread, and new dynamic context, "
438"returning a new thread object representing the thread. "
439"If an error occurs during evaluation, call error-thunk, passing it an "
440"error code describing the condition. "
441"If this happens, the error-thunk is called outside the scope of the new "
442"root -- it is called in the same dynamic context in which "
443"with-new-thread was evaluated, but not in the callers thread. "
444"All the evaluation rules for dynamic roots apply to threads.")
445#define FUNC_NAME s_scm_call_with_new_thread
446{
447 SCM_ASSERT (SCM_NFALSEP (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
448 SCM_ASSERT (SCM_NFALSEP (scm_procedure_p (handler)), handler, SCM_ARG2,
449 FUNC_NAME);
450
451 return create_thread ((scm_t_catch_body) scm_call_0, thunk,
452 (scm_t_catch_handler) scm_apply_1, handler,
453 scm_cons (thunk, handler));
454}
455#undef FUNC_NAME
456
d823b11b 457SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
5f05c406 458 (SCM thread),
d823b11b
MV
459"Suspend execution of the calling thread until the target @var{thread} "
460"terminates, unless the target @var{thread} has already terminated. ")
461#define FUNC_NAME s_scm_join_thread
5f05c406 462{
d823b11b
MV
463 scm_thread *t;
464 SCM res;
465
466 SCM_VALIDATE_THREAD (1, thread);
467 if (SCM_EQ_P (cur_thread, thread))
468 SCM_MISC_ERROR ("can not join the current thread", SCM_EOL);
469
470 t = SCM_THREAD_DATA (thread);
471 if (!t->exited)
472 {
9bc4701c
MD
473 scm_thread *c = scm_i_leave_guile ();
474 while (!THREAD_INITIALIZED_P (t))
475 SCM_TICK;
476 scm_thread_join (t->thread, 0);
477 scm_i_enter_guile (c);
d823b11b
MV
478 }
479 res = t->result;
480 t->result = SCM_BOOL_F;
481 return res;
5f05c406
MV
482}
483#undef FUNC_NAME
484
9bc4701c 485/*** Fair mutexes */
4079f87e 486
d823b11b
MV
487/* We implement our own mutex type since we want them to be 'fair', we
488 want to do fancy things while waiting for them (like running
489 asyncs) and we want to support waiting on many things at once.
490 Also, we might add things that are nice for debugging.
491*/
4079f87e 492
9bc4701c 493typedef struct fair_mutex {
d823b11b 494 /* the thread currently owning the mutex, or SCM_BOOL_F. */
9bc4701c
MD
495 scm_t_mutex lock;
496 int lockedp;
d823b11b
MV
497 SCM owner;
498 /* how much the owner owns us. */
499 int level;
500 /* the threads waiting for this mutex. */
501 SCM waiting;
9bc4701c 502} fair_mutex;
5f05c406 503
d823b11b 504static SCM
9bc4701c 505fair_mutex_mark (SCM mx)
d823b11b 506{
9bc4701c 507 fair_mutex *m = SCM_MUTEX_DATA (mx);
d823b11b
MV
508 scm_gc_mark (m->owner);
509 return m->waiting;
510}
4079f87e 511
9bc4701c 512SCM_DEFINE (scm_make_fair_mutex, "make-fair-mutex", 0, 0, 0,
d823b11b 513 (void),
9bc4701c
MD
514 "Create a new fair mutex object. ")
515#define FUNC_NAME s_scm_make_fair_mutex
d823b11b 516{
9bc4701c
MD
517 SCM mx = scm_make_smob (scm_tc16_fair_mutex);
518 fair_mutex *m = SCM_MUTEX_DATA (mx);
519 scm_i_plugin_mutex_init (&m->lock, 0);
520 m->lockedp = 0;
d823b11b
MV
521 m->owner = SCM_BOOL_F;
522 m->level = 0;
523 m->waiting = make_queue ();
524 return mx;
525}
526#undef FUNC_NAME
4079f87e 527
9bc4701c
MD
528static int
529fair_mutex_lock (fair_mutex *m)
d823b11b 530{
9bc4701c
MD
531 scm_i_plugin_mutex_lock (&m->lock);
532#if 0
533 /* Need to wait if another thread is just temporarily unlocking.
534 This is happens very seldom and only when the other thread is
535 between scm_mutex_unlock and scm_i_plugin_mutex_lock below. */
536 while (m->lockedp)
537 SCM_TICK;
538 m->lockedp = 1;
539#endif
540
d823b11b
MV
541 if (m->owner == SCM_BOOL_F)
542 m->owner = cur_thread;
543 else if (m->owner == cur_thread)
544 m->level++;
545 else
546 {
547 while (1)
548 {
549 SCM c = enqueue (m->waiting, cur_thread);
9bc4701c
MD
550 int err;
551 /* Note: It's important that m->lock is never locked for
552 any longer amount of time since that could prevent GC */
553 scm_i_plugin_mutex_unlock (&m->lock);
554 err = block ();
d823b11b 555 if (m->owner == cur_thread)
9bc4701c
MD
556 return 0;
557 scm_i_plugin_mutex_lock (&m->lock);
d823b11b 558 remqueue (m->waiting, c);
9bc4701c 559 scm_i_plugin_mutex_unlock (&m->lock);
d823b11b 560 if (err)
9bc4701c 561 return err;
d823b11b 562 SCM_ASYNC_TICK;
9bc4701c 563 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
564 }
565 }
9bc4701c
MD
566 scm_i_plugin_mutex_unlock (&m->lock);
567 return 0;
d823b11b 568}
7bfd3b9e 569
9bc4701c
MD
570static int
571fair_mutex_trylock (fair_mutex *m)
d823b11b 572{
9bc4701c 573 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
574 if (m->owner == SCM_BOOL_F)
575 m->owner = cur_thread;
576 else if (m->owner == cur_thread)
577 m->level++;
578 else
9bc4701c
MD
579 {
580 scm_i_plugin_mutex_unlock (&m->lock);
581 return EBUSY;
582 }
583 scm_i_plugin_mutex_unlock (&m->lock);
584 return 0;
d823b11b 585}
d823b11b 586
9bc4701c
MD
587static int
588fair_mutex_unlock (fair_mutex *m)
5f05c406 589{
9bc4701c 590 scm_i_plugin_mutex_lock (&m->lock);
d823b11b
MV
591 if (m->owner != cur_thread)
592 {
9bc4701c
MD
593 scm_i_plugin_mutex_unlock (&m->lock);
594 return EPERM;
d823b11b
MV
595 }
596 else if (m->level > 0)
597 m->level--;
598 else
599 {
600 SCM next = dequeue (m->waiting);
601 if (!SCM_FALSEP (next))
602 {
603 m->owner = next;
604 unblock (SCM_THREAD_DATA (next));
d823b11b
MV
605 }
606 else
607 m->owner = SCM_BOOL_F;
608 }
9bc4701c
MD
609 scm_i_plugin_mutex_unlock (&m->lock);
610 return 0;
5f05c406
MV
611}
612
9bc4701c 613/*** Fair condition variables */
7bfd3b9e 614
d823b11b
MV
615/* Like mutexes, we implement our own condition variables using the
616 primitives above.
617*/
5f05c406 618
9bc4701c
MD
619typedef struct fair_cond {
620 scm_t_mutex lock;
d823b11b
MV
621 /* the threads waiting for this condition. */
622 SCM waiting;
9bc4701c 623} fair_cond;
5f05c406 624
d823b11b 625static SCM
9bc4701c 626fair_cond_mark (SCM cv)
5f05c406 627{
9bc4701c 628 fair_cond *c = SCM_CONDVAR_DATA (cv);
d823b11b 629 return c->waiting;
5f05c406
MV
630}
631
9bc4701c
MD
632SCM_DEFINE (scm_make_fair_condition_variable, "make-fair-condition-variable", 0, 0, 0,
633 (void),
634 "Make a new fair condition variable.")
635#define FUNC_NAME s_scm_make_fair_condition_variable
636{
637 SCM cv = scm_make_smob (scm_tc16_fair_condvar);
638 fair_cond *c = SCM_CONDVAR_DATA (cv);
639 scm_i_plugin_mutex_init (&c->lock, 0);
640 c->waiting = make_queue ();
641 return cv;
642}
643#undef FUNC_NAME
644
645static int
646fair_cond_timedwait (fair_cond *c,
647 fair_mutex *m,
648 const struct timespec *waittime)
649{
650 int err;
651 scm_i_plugin_mutex_lock (&c->lock);
652
653 while (1)
654 {
655 enqueue (c->waiting, cur_thread);
656 scm_i_plugin_mutex_unlock (&c->lock);
657 fair_mutex_unlock (m); /*fixme* - not thread safe */
658 if (waittime == NULL)
659 err = block ();
660 else
661 err = timed_block (waittime);
662 fair_mutex_lock (m);
663 if (err)
664 return err;
665 /* XXX - check whether we have been signalled. */
666 break;
667 }
668 return err;
669}
670
671static int
672fair_cond_signal (fair_cond *c)
673{
674 SCM th;
675 scm_i_plugin_mutex_lock (&c->lock);
676 if (!SCM_FALSEP (th = dequeue (c->waiting)))
677 unblock (SCM_THREAD_DATA (th));
678 scm_i_plugin_mutex_unlock (&c->lock);
679 return 0;
680}
681
682static int
683fair_cond_broadcast (fair_cond *c)
684{
685 SCM th;
686 scm_i_plugin_mutex_lock (&c->lock);
687 while (!SCM_FALSEP (th = dequeue (c->waiting)))
688 unblock (SCM_THREAD_DATA (th));
689 scm_i_plugin_mutex_unlock (&c->lock);
690 return 0;
691}
692
693/*** Mutexes */
694
695SCM_DEFINE (scm_make_mutex, "make-mutex", 0, 0, 0,
696 (void),
697 "Create a new mutex object. ")
698#define FUNC_NAME s_scm_make_mutex
699{
700 SCM mx = scm_make_smob (scm_tc16_mutex);
701 scm_i_plugin_mutex_init (SCM_MUTEX_DATA (mx), 0);
702 return mx;
703}
704#undef FUNC_NAME
705
706/*fixme* change documentation */
707SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
708 (SCM mx),
709"Lock @var{mutex}. If the mutex is already locked, the calling thread "
710"blocks until the mutex becomes available. The function returns when "
711"the calling thread owns the lock on @var{mutex}. Locking a mutex that "
712"a thread already owns will succeed right away and will not block the "
713"thread. That is, Guile's mutexes are @emph{recursive}. ")
714#define FUNC_NAME s_scm_lock_mutex
715{
716 int err;
717 SCM_VALIDATE_MUTEX (1, mx);
718
719 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
720 err = fair_mutex_lock (SCM_MUTEX_DATA (mx));
721 else
722 {
723 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
724 scm_thread *t = scm_i_leave_guile ();
725 err = scm_i_plugin_mutex_lock (m);
726 scm_i_enter_guile (t);
727 }
728
729 if (err)
730 {
731 errno = err;
732 SCM_SYSERROR;
733 }
734 return SCM_BOOL_T;
735}
736#undef FUNC_NAME
737
738SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
739 (SCM mx),
740"Try to lock @var{mutex}. If the mutex is already locked by someone "
741"else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
742#define FUNC_NAME s_scm_try_mutex
743{
744 int err;
745 SCM_VALIDATE_MUTEX (1, mx);
746
747 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
748 err = fair_mutex_trylock (SCM_MUTEX_DATA (mx));
749 else
750 {
751 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
752 scm_thread *t = scm_i_leave_guile ();
753 err = scm_i_plugin_mutex_trylock (m);
754 scm_i_enter_guile (t);
755 }
756
757 if (err == EBUSY)
758 return SCM_BOOL_F;
759
760 if (err)
761 {
762 errno = err;
763 SCM_SYSERROR;
764 }
765
766 return SCM_BOOL_T;
767}
768#undef FUNC_NAME
769
770SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
771 (SCM mx),
772"Unlocks @var{mutex} if the calling thread owns the lock on "
773"@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
774"thread results in undefined behaviour. Once a mutex has been unlocked, "
775"one thread blocked on @var{mutex} is awakened and grabs the mutex "
776"lock. Every call to @code{lock-mutex} by this thread must be matched "
777"with a call to @code{unlock-mutex}. Only the last call to "
778"@code{unlock-mutex} will actually unlock the mutex. ")
779#define FUNC_NAME s_scm_unlock_mutex
780{
781 int err;
782 SCM_VALIDATE_MUTEX (1, mx);
783
784 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
785 {
786 err = fair_mutex_unlock (SCM_MUTEX_DATA (mx));
787 if (err == EPERM)
788 {
789 fair_mutex *m = SCM_MUTEX_DATA (mx);
790 if (m->owner != cur_thread)
791 {
792 if (m->owner == SCM_BOOL_F)
793 SCM_MISC_ERROR ("mutex not locked", SCM_EOL);
794 else
795 SCM_MISC_ERROR ("mutex not locked by this thread", SCM_EOL);
796 }
797 }
798 }
799 else
800 {
801 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
802 err = scm_i_plugin_mutex_unlock (m);
803 }
804
805 if (err)
806 {
807 errno = err;
808 SCM_SYSERROR;
809 }
810 return SCM_BOOL_T;
811}
812#undef FUNC_NAME
813
814/*** Condition variables */
815
d823b11b
MV
816SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
817 (void),
818 "Make a new condition variable.")
819#define FUNC_NAME s_scm_make_condition_variable
5f05c406 820{
d823b11b 821 SCM cv = scm_make_smob (scm_tc16_condvar);
9bc4701c 822 scm_i_plugin_cond_init (SCM_CONDVAR_DATA (cv), 0);
d823b11b 823 return cv;
5f05c406 824}
d823b11b 825#undef FUNC_NAME
5f05c406 826
d823b11b
MV
827SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
828 (SCM cv, SCM mx, SCM t),
829"Wait until @var{cond-var} has been signalled. While waiting, "
830"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
831"is locked again when this function returns. When @var{time} is given, "
832"it specifies a point in time where the waiting should be aborted. It "
833"can be either a integer as returned by @code{current-time} or a pair "
834"as returned by @code{gettimeofday}. When the waiting is aborted the "
835"mutex is locked and @code{#f} is returned. When the condition "
836"variable is in fact signalled, the mutex is also locked and @code{#t} "
837"is returned. ")
838#define FUNC_NAME s_scm_timed_wait_condition_variable
5f05c406 839{
d823b11b
MV
840 struct timespec waittime;
841 int err;
842
843 SCM_VALIDATE_CONDVAR (1, cv);
844 SCM_VALIDATE_MUTEX (2, mx);
9bc4701c
MD
845 if (!((SCM_TYP16 (cv) == scm_tc16_condvar
846 && SCM_TYP16 (mx) == scm_tc16_mutex)
847 || (SCM_TYP16 (cv) == scm_tc16_fair_condvar
848 && SCM_TYP16 (mx) == scm_tc16_fair_mutex)))
849 SCM_MISC_ERROR ("Condition variable and mutex are of different kinds.",
850 SCM_EOL);
851
d823b11b
MV
852 if (!SCM_UNBNDP (t))
853 {
854 if (SCM_CONSP (t))
855 {
9bc4701c
MD
856 SCM_VALIDATE_UINT_COPY (3, SCM_CAR (t), waittime.tv_sec);
857 SCM_VALIDATE_UINT_COPY (3, SCM_CDR (t), waittime.tv_nsec);
d823b11b
MV
858 waittime.tv_nsec *= 1000;
859 }
860 else
861 {
862 SCM_VALIDATE_UINT_COPY (3, t, waittime.tv_sec);
863 waittime.tv_nsec = 0;
864 }
865 }
866
9bc4701c
MD
867 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
868 err = fair_cond_timedwait (SCM_CONDVAR_DATA (cv),
869 SCM_MUTEX_DATA (mx),
870 SCM_UNBNDP (t) ? NULL : &waittime);
871 else
872 {
873 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
874 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
875 scm_thread *t = scm_i_leave_guile ();
876 err = scm_i_plugin_cond_wait (c, m);
877 scm_i_enter_guile (t);
878 }
d823b11b 879
9bc4701c 880 if (err)
d823b11b 881 {
9bc4701c
MD
882 errno = err;
883 SCM_SYSERROR;
d823b11b 884 }
9bc4701c 885 return SCM_BOOL_T;
5f05c406 886}
d823b11b 887#undef FUNC_NAME
5f05c406 888
d823b11b
MV
889SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
890 (SCM cv),
891 "Wake up one thread that is waiting for @var{cv}")
892#define FUNC_NAME s_scm_signal_condition_variable
5f05c406 893{
d823b11b 894 SCM_VALIDATE_CONDVAR (1, cv);
9bc4701c
MD
895 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
896 fair_cond_signal (SCM_CONDVAR_DATA (cv));
897 else
898 {
899 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
900 scm_i_plugin_cond_signal (c);
901 }
d823b11b 902 return SCM_BOOL_T;
5f05c406 903}
d823b11b 904#undef FUNC_NAME
5f05c406 905
d823b11b
MV
906SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
907 (SCM cv),
908 "Wake up all threads that are waiting for @var{cv}. ")
909#define FUNC_NAME s_scm_broadcast_condition_variable
5f05c406 910{
d823b11b 911 SCM_VALIDATE_CONDVAR (1, cv);
9bc4701c
MD
912 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
913 fair_cond_broadcast (SCM_CONDVAR_DATA (cv));
914 else
915 {
916 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
917 scm_i_plugin_cond_broadcast (c);
918 }
d823b11b 919 return SCM_BOOL_T;
5f05c406 920}
d823b11b 921#undef FUNC_NAME
5f05c406 922
d823b11b
MV
923/*** Marking stacks */
924
925/* XXX - what to do with this? Do we need to handle this for blocked
926 threads as well?
927*/
928#ifdef __ia64__
929# define SCM_MARK_BACKING_STORE() do { \
930 ucontext_t ctx; \
931 SCM_STACKITEM * top, * bot; \
932 getcontext (&ctx); \
933 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
934 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
935 / sizeof (SCM_STACKITEM))); \
936 bot = (SCM_STACKITEM *) __libc_ia64_register_backing_store_base; \
937 top = (SCM_STACKITEM *) ctx.uc_mcontext.sc_ar_bsp; \
938 scm_mark_locations (bot, top - bot); } while (0)
939#else
940# define SCM_MARK_BACKING_STORE()
941#endif
942
943void
944scm_threads_mark_stacks (void)
5f05c406 945{
d823b11b
MV
946 volatile SCM c;
947 for (c = all_threads; !SCM_NULLP (c); c = SCM_CDR (c))
948 {
949 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (c));
9bc4701c 950 if (!THREAD_INITIALIZED_P (t))
d823b11b
MV
951 {
952 /* Not fully initialized yet. */
953 continue;
954 }
955 if (t->top == NULL)
956 {
9bc4701c
MD
957 long stack_len;
958#ifdef SCM_DEBUG
959 if (t->thread != scm_thread_self ())
960 abort ();
961#endif
d823b11b
MV
962 /* Active thread */
963 /* stack_len is long rather than sizet in order to guarantee
964 that &stack_len is long aligned */
965#ifdef STACK_GROWS_UP
9bc4701c
MD
966 stack_len = ((SCM_STACKITEM *) (&t) -
967 (SCM_STACKITEM *) thread->base);
d823b11b
MV
968
969 /* Protect from the C stack. This must be the first marking
970 * done because it provides information about what objects
971 * are "in-use" by the C code. "in-use" objects are those
972 * for which the information about length and base address must
973 * remain usable. This requirement is stricter than a liveness
974 * requirement -- in particular, it constrains the implementation
975 * of scm_resizuve.
976 */
977 SCM_FLUSH_REGISTER_WINDOWS;
978 /* This assumes that all registers are saved into the jmp_buf */
979 setjmp (scm_save_regs_gc_mark);
980 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
981 ((size_t) sizeof scm_save_regs_gc_mark
982 / sizeof (SCM_STACKITEM)));
983
984 scm_mark_locations (((size_t) t->base,
985 (sizet) stack_len));
986#else
9bc4701c
MD
987 stack_len = ((SCM_STACKITEM *) t->base -
988 (SCM_STACKITEM *) (&t));
d823b11b
MV
989
990 /* Protect from the C stack. This must be the first marking
991 * done because it provides information about what objects
992 * are "in-use" by the C code. "in-use" objects are those
993 * for which the information about length and base address must
994 * remain usable. This requirement is stricter than a liveness
995 * requirement -- in particular, it constrains the implementation
996 * of scm_resizuve.
997 */
998 SCM_FLUSH_REGISTER_WINDOWS;
999 /* This assumes that all registers are saved into the jmp_buf */
1000 setjmp (scm_save_regs_gc_mark);
1001 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
1002 ((size_t) sizeof scm_save_regs_gc_mark
1003 / sizeof (SCM_STACKITEM)));
1004
1005 scm_mark_locations ((SCM_STACKITEM *) &t,
1006 stack_len);
1007#endif
1008 }
1009 else
1010 {
1011 /* Suspended thread */
1012#ifdef STACK_GROWS_UP
1013 long stack_len = t->top - t->base;
1014 scm_mark_locations (t->base, stack_len);
1015#else
1016 long stack_len = t->base - t->top;
1017 scm_mark_locations (t->top, stack_len);
1018#endif
1019 scm_mark_locations ((SCM_STACKITEM *) t->regs,
1020 ((size_t) sizeof(t->regs)
1021 / sizeof (SCM_STACKITEM)));
1022 }
1023 }
5f05c406
MV
1024}
1025
d823b11b
MV
1026/*** Select */
1027
911782b7 1028int
d823b11b
MV
1029scm_internal_select (int nfds,
1030 SELECT_TYPE *readfds,
1031 SELECT_TYPE *writefds,
1032 SELECT_TYPE *exceptfds,
1033 struct timeval *timeout)
5f05c406 1034{
d823b11b 1035 int res, eno;
9bc4701c
MD
1036 scm_thread *c = scm_i_leave_guile ();
1037 res = scm_i_plugin_select (nfds, readfds, writefds, exceptfds, timeout);
d823b11b 1038 eno = errno;
9bc4701c 1039 scm_i_enter_guile (c);
d823b11b
MV
1040 SCM_ASYNC_TICK;
1041 errno = eno;
1042 return res;
5f05c406
MV
1043}
1044
9bc4701c
MD
1045/* Low-level C API */
1046
1047SCM
1048scm_spawn_thread (scm_t_catch_body body, void *body_data,
1049 scm_t_catch_handler handler, void *handler_data)
1050{
1051 return create_thread (body, body_data, handler, handler_data, SCM_BOOL_F);
1052}
1053
9bc4701c
MD
1054int
1055scm_mutex_lock (scm_t_mutex *m)
1056{
1057 scm_thread *t = scm_i_leave_guile ();
1058 int res = scm_i_plugin_mutex_lock (m);
1059 scm_i_enter_guile (t);
1060 return res;
1061}
1062
1063int
1064scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
1065{
1066 scm_thread *t = scm_i_leave_guile ();
1067 scm_i_plugin_cond_wait (c, m);
1068 scm_i_enter_guile (t);
1069 return 0;
1070}
1071
1072int
06babecc 1073scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, const struct timespec *wt)
9bc4701c
MD
1074{
1075 scm_thread *t = scm_i_leave_guile ();
06babecc 1076 int res = scm_i_plugin_cond_timedwait (c, m, wt);
9bc4701c
MD
1077 scm_i_enter_guile (t);
1078 return res;
1079}
9bc4701c
MD
1080
1081void
1082scm_enter_guile ()
1083{
1084 scm_i_enter_guile (SCM_CURRENT_THREAD);
1085}
1086
1087void
1088scm_leave_guile ()
1089{
1090 scm_i_leave_guile ();
1091}
1092
d823b11b
MV
1093unsigned long
1094scm_thread_usleep (unsigned long usecs)
5f05c406 1095{
d823b11b
MV
1096 struct timeval tv;
1097 tv.tv_usec = usecs % 1000000;
1098 tv.tv_sec = usecs / 1000000;
1099 scm_internal_select (0, NULL, NULL, NULL, &tv);
1100 return tv.tv_usec + tv.tv_sec*1000000;
5f05c406
MV
1101}
1102
d823b11b
MV
1103unsigned long
1104scm_thread_sleep (unsigned long secs)
6c214b62 1105{
d823b11b
MV
1106 struct timeval tv;
1107 tv.tv_usec = 0;
1108 tv.tv_sec = secs;
1109 scm_internal_select (0, NULL, NULL, NULL, &tv);
1110 return tv.tv_sec;
6c214b62
MD
1111}
1112
d823b11b
MV
1113/*** Misc */
1114
1115SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1116 (void),
1117 "Return the thread that called this function.")
1118#define FUNC_NAME s_scm_current_thread
1119{
1120 return cur_thread;
1121}
1122#undef FUNC_NAME
1123
1124SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1125 (void),
1126 "Return a list of all threads.")
9bc4701c 1127#define FUNC_NAME s_scm_all_threads
d823b11b
MV
1128{
1129 return all_threads;
1130}
1131#undef FUNC_NAME
1132
1133scm_root_state *
1134scm_i_thread_root (SCM thread)
1135{
9bc4701c 1136 return ((scm_thread *) SCM_THREAD_DATA (thread))->root;
d823b11b
MV
1137}
1138
1139SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1140 (SCM thread),
1141 "Return @code{#t} iff @var{thread} has exited.\n")
1142#define FUNC_NAME s_scm_thread_exited_p
1143{
1144 return SCM_BOOL (scm_c_thread_exited_p (thread));
1145}
1146#undef FUNC_NAME
1147
911782b7 1148int
d823b11b
MV
1149scm_c_thread_exited_p (SCM thread)
1150#define FUNC_NAME s_scm_thread_exited_p
5f05c406 1151{
d823b11b
MV
1152 scm_thread *t;
1153 SCM_VALIDATE_THREAD (1, thread);
1154 t = SCM_THREAD_DATA (thread);
1155 return t->exited;
5f05c406 1156}
d823b11b 1157#undef FUNC_NAME
5f05c406 1158
9bc4701c
MD
1159static scm_t_cond wake_up_cond;
1160int scm_i_thread_go_to_sleep;
1161static scm_thread *gc_thread;
1162static scm_t_mutex gc_section_mutex;
1163static scm_thread *gc_section_owner;
1164static int gc_section_count = 0;
1165static int threads_initialized_p = 0;
1166
1167void
1168scm_i_thread_put_to_sleep ()
1169{
1170 SCM_REC_CRITICAL_SECTION_START (gc_section);
1171 if (threads_initialized_p && gc_section_count == 1)
1172 {
1173 SCM threads = all_threads;
1174 /* Signal all threads to go to sleep */
1175 scm_i_thread_go_to_sleep = 1;
1176 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1177 if (SCM_CAR (threads) != cur_thread)
1178 {
1179 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1180 t->clear_freelists_p = 1;
1181 scm_i_plugin_mutex_lock (&t->heap_mutex);
1182 }
1183 gc_thread = suspend ();
1184 scm_i_thread_go_to_sleep = 0;
1185 }
1186}
1187
1188void
1189scm_i_thread_wake_up ()
1190{
1191 if (threads_initialized_p && gc_section_count == 1)
1192 {
1193 SCM threads = all_threads;
1194 resume (gc_thread);
1195 scm_i_plugin_cond_broadcast (&wake_up_cond);
1196 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1197 if (SCM_CAR (threads) != cur_thread)
1198 {
1199 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1200 scm_i_plugin_mutex_unlock (&t->heap_mutex);
1201 }
1202 }
1203 SCM_REC_CRITICAL_SECTION_END (gc_section);
1204}
1205
1206void
1207scm_i_thread_sleep_for_gc ()
1208{
1209 scm_thread *t;
1210 t = suspend ();
1211 *SCM_FREELIST_LOC (scm_i_freelist) = SCM_EOL;
1212 *SCM_FREELIST_LOC (scm_i_freelist2) = SCM_EOL;
1213 scm_i_plugin_cond_wait (&wake_up_cond, &t->heap_mutex);
1214 t->clear_freelists_p = 0;
1215 t->top = NULL; /* resume (t); but don't clear freelists */
1216}
1217
1218/* The mother of all recursive critical sections */
1219scm_t_mutex scm_i_section_mutex;
1220
1221scm_t_mutex scm_i_critical_section_mutex;
1222scm_t_mutex scm_i_defer_mutex;
1223int scm_i_defer_count = 0;
1224scm_thread *scm_i_defer_owner = 0;
1225
d823b11b 1226/*** Initialization */
7bfd3b9e 1227
9bc4701c
MD
1228void
1229scm_threads_prehistory ()
1230{
1231 scm_thread *t;
1232 scm_i_plugin_mutex_init (&thread_admin_mutex, 0);
1233 scm_i_plugin_mutex_init (&gc_section_mutex, 0);
1234 scm_i_plugin_cond_init (&wake_up_cond, 0);
1235 scm_i_plugin_mutex_init (&scm_i_critical_section_mutex, 0);
1236 thread_count = 1;
1237 scm_i_plugin_key_create (&scm_i_thread_key, 0);
1238 scm_i_plugin_key_create (&scm_i_root_state_key, 0);
1239 scm_i_plugin_mutex_init (&scm_i_defer_mutex, 0);
1240 scm_i_plugin_mutex_init (&scm_i_section_mutex, 0);
1241 /* Allocate a fake thread object to be used during bootup. */
1242 t = malloc (sizeof (scm_thread));
1243 t->base = NULL;
1244 t->clear_freelists_p = 0;
1245 scm_setspecific (scm_i_thread_key, t);
1246}
1247
d823b11b
MV
1248scm_t_bits scm_tc16_thread;
1249scm_t_bits scm_tc16_mutex;
9bc4701c 1250scm_t_bits scm_tc16_fair_mutex;
d823b11b 1251scm_t_bits scm_tc16_condvar;
9bc4701c 1252scm_t_bits scm_tc16_fair_condvar;
7bfd3b9e 1253
7bfd3b9e 1254void
d823b11b 1255scm_init_threads (SCM_STACKITEM *base)
7bfd3b9e 1256{
9bc4701c 1257 SCM thread;
d823b11b 1258 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_thread));
9bc4701c
MD
1259 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (scm_t_mutex));
1260 scm_tc16_fair_mutex = scm_make_smob_type ("fair-mutex",
1261 sizeof (fair_mutex));
d823b11b 1262 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
9bc4701c
MD
1263 sizeof (scm_t_cond));
1264 scm_tc16_fair_condvar = scm_make_smob_type ("fair-condition-variable",
1265 sizeof (fair_cond));
d823b11b 1266
9bc4701c
MD
1267 thread = make_thread (SCM_BOOL_F);
1268 /* Replace initial fake thread with a real thread object */
1269 free (SCM_CURRENT_THREAD);
1270 scm_setspecific (scm_i_thread_key, SCM_THREAD_DATA (thread));
1271 scm_i_enter_guile (SCM_CURRENT_THREAD);
d823b11b 1272
d823b11b 1273 /* root is set later from init.c */
9bc4701c 1274 init_thread_creatant (thread, base);
d823b11b
MV
1275 thread_count = 1;
1276 scm_gc_register_root (&all_threads);
9bc4701c 1277 all_threads = scm_cons (thread, SCM_EOL);
d823b11b
MV
1278
1279 scm_set_smob_mark (scm_tc16_thread, thread_mark);
1280 scm_set_smob_print (scm_tc16_thread, thread_print);
1281 scm_set_smob_free (scm_tc16_thread, thread_free);
1282
9bc4701c
MD
1283 scm_set_smob_mark (scm_tc16_fair_mutex, fair_mutex_mark);
1284
1285 scm_set_smob_mark (scm_tc16_fair_condvar, fair_cond_mark);
d823b11b 1286
9bc4701c 1287 threads_initialized_p = 1;
7bfd3b9e 1288}
89e00824 1289
5f05c406
MV
1290void
1291scm_init_thread_procs ()
1292{
1293#include "libguile/threads.x"
1294}
1295
d823b11b
MV
1296/* XXX */
1297
1298void
1299scm_init_iselect ()
1300{
1301}
1302
89e00824
ML
1303/*
1304 Local Variables:
1305 c-file-style: "gnu"
1306 End:
1307*/