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