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