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