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