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