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