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