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