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