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