Regenerate `psyntax-pp.scm'.
[bpt/guile.git] / libguile / threads.c
CommitLineData
cde24ce1 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
74926120 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7bfd3b9e 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
7bfd3b9e 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
7bfd3b9e 24
1c44468d 25#include "libguile/bdw-gc.h"
1810dc4e
RB
26#include "libguile/_scm.h"
27
fcc5d734 28#if HAVE_UNISTD_H
d823b11b 29#include <unistd.h>
fcc5d734 30#endif
d823b11b 31#include <stdio.h>
8ab3d8a0
KR
32
33#ifdef HAVE_STRING_H
34#include <string.h> /* for memset used by FD_ZERO on Solaris 10 */
35#endif
36
fcc5d734 37#if HAVE_SYS_TIME_H
d823b11b 38#include <sys/time.h>
fcc5d734 39#endif
5f05c406 40
c1d5d6d7
AW
41#if HAVE_PTHREAD_NP_H
42# include <pthread_np.h>
43#endif
44
f57fdf07 45#include <assert.h>
32f94bf2 46#include <fcntl.h>
d20912e6 47#include <nproc.h>
f57fdf07 48
d823b11b
MV
49#include "libguile/validate.h"
50#include "libguile/root.h"
51#include "libguile/eval.h"
52#include "libguile/async.h"
53#include "libguile/ports.h"
54#include "libguile/threads.h"
a0599745 55#include "libguile/dynwind.h"
d823b11b 56#include "libguile/iselect.h"
9de87eea
MV
57#include "libguile/fluids.h"
58#include "libguile/continuations.h"
2b829bbb 59#include "libguile/gc.h"
9de87eea 60#include "libguile/init.h"
2e77f720 61#include "libguile/scmsigs.h"
6180e336 62#include "libguile/strings.h"
a0faf7dd 63#include "libguile/weaks.h"
7bfd3b9e 64
634aa8de
LC
65#include <full-read.h>
66
cde24ce1
AW
67
68\f
69
70/* First some libgc shims. */
71
72/* Make sure GC_fn_type is defined; it is missing from the public
73 headers of GC 7.1 and earlier. */
74#ifndef HAVE_GC_FN_TYPE
75typedef void * (* GC_fn_type) (void *);
76#endif
77
78
5f0d2951
AW
79#ifndef GC_SUCCESS
80#define GC_SUCCESS 0
81#endif
82
83#ifndef GC_UNIMPLEMENTED
84#define GC_UNIMPLEMENTED 3
85#endif
86
87/* Likewise struct GC_stack_base is missing before 7.1. */
88#ifndef HAVE_GC_STACK_BASE
12c1d861
AW
89struct GC_stack_base {
90 void * mem_base; /* Base of memory stack. */
91#ifdef __ia64__
92 void * reg_base; /* Base of separate register stack. */
93#endif
94};
5f0d2951
AW
95
96static int
987b8160 97GC_register_my_thread (struct GC_stack_base *stack_base)
5f0d2951
AW
98{
99 return GC_UNIMPLEMENTED;
100}
101
102static void
103GC_unregister_my_thread ()
104{
105}
106
12c1d861
AW
107#if !SCM_USE_PTHREAD_THREADS
108/* No threads; we can just use GC_stackbottom. */
5f0d2951 109static void *
12c1d861
AW
110get_thread_stack_base ()
111{
112 return GC_stackbottom;
113}
114
115#elif defined HAVE_PTHREAD_ATTR_GETSTACK && defined HAVE_PTHREAD_GETATTR_NP \
116 && defined PTHREAD_ATTR_GETSTACK_WORKS
117/* This method for GNU/Linux and perhaps some other systems.
118 It's not for MacOS X or Solaris 10, since pthread_getattr_np is not
119 available on them. */
120static void *
121get_thread_stack_base ()
122{
123 pthread_attr_t attr;
124 void *start, *end;
125 size_t size;
126
127 pthread_getattr_np (pthread_self (), &attr);
128 pthread_attr_getstack (&attr, &start, &size);
129 end = (char *)start + size;
130
131#if SCM_STACK_GROWS_UP
132 return start;
133#else
134 return end;
135#endif
136}
137
138#elif defined HAVE_PTHREAD_GET_STACKADDR_NP
139/* This method for MacOS X.
140 It'd be nice if there was some documentation on pthread_get_stackaddr_np,
141 but as of 2006 there's nothing obvious at apple.com. */
142static void *
143get_thread_stack_base ()
144{
145 return pthread_get_stackaddr_np (pthread_self ());
146}
147
c1d5d6d7
AW
148#elif HAVE_PTHREAD_ATTR_GET_NP
149/* This one is for FreeBSD 9. */
150static void *
151get_thread_stack_base ()
152{
153 pthread_attr_t attr;
154 void *start, *end;
155 size_t size;
156
157 pthread_attr_init (&attr);
158 pthread_attr_get_np (pthread_self (), &attr);
159 pthread_attr_getstack (&attr, &start, &size);
160 pthread_attr_destroy (&attr);
161
162 end = (char *)start + size;
163
164#if SCM_STACK_GROWS_UP
165 return start;
166#else
167 return end;
168#endif
169}
170
12c1d861
AW
171#else
172#error Threads enabled with old BDW-GC, but missing get_thread_stack_base impl. Please upgrade to libgc >= 7.1.
173#endif
174
175static int
987b8160 176GC_get_stack_base (struct GC_stack_base *stack_base)
5f0d2951 177{
12c1d861
AW
178 stack_base->mem_base = get_thread_stack_base ();
179#ifdef __ia64__
180 /* Calculate and store off the base of this thread's register
181 backing store (RBS). Unfortunately our implementation(s) of
182 scm_ia64_register_backing_store_base are only reliable for the
183 main thread. For other threads, therefore, find out the current
184 top of the RBS, and use that as a maximum. */
185 stack_base->reg_base = scm_ia64_register_backing_store_base ();
186 {
187 ucontext_t ctx;
188 void *bsp;
189 getcontext (&ctx);
190 bsp = scm_ia64_ar_bsp (&ctx);
191 if (stack_base->reg_base > bsp)
192 stack_base->reg_base = bsp;
193 }
194#endif
195 return GC_SUCCESS;
5f0d2951 196}
12c1d861
AW
197
198static void *
199GC_call_with_stack_base(void * (*fn) (struct GC_stack_base*, void*), void *arg)
200{
201 struct GC_stack_base stack_base;
202
203 stack_base.mem_base = (void*)&stack_base;
204#ifdef __ia64__
205 /* FIXME: Untested. */
206 {
207 ucontext_t ctx;
208 getcontext (&ctx);
209 stack_base.reg_base = scm_ia64_ar_bsp (&ctx);
210 }
5f0d2951
AW
211#endif
212
12c1d861
AW
213 return fn (&stack_base, arg);
214}
215#endif /* HAVE_GC_STACK_BASE */
216
5f0d2951 217
cde24ce1
AW
218/* Now define with_gc_active and with_gc_inactive. */
219
220#if (defined(HAVE_GC_DO_BLOCKING) && defined (HAVE_DECL_GC_DO_BLOCKING) && defined (HAVE_GC_CALL_WITH_GC_ACTIVE))
221
222/* We have a sufficiently new libgc (7.2 or newer). */
223
224static void*
225with_gc_inactive (GC_fn_type func, void *data)
226{
227 return GC_do_blocking (func, data);
228}
229
230static void*
231with_gc_active (GC_fn_type func, void *data)
232{
233 return GC_call_with_gc_active (func, data);
234}
235
236#else
237
238/* libgc not new enough, so never actually deactivate GC.
239
240 Note that though GC 7.1 does have a GC_do_blocking, it doesn't have
241 GC_call_with_gc_active. */
242
243static void*
244with_gc_inactive (GC_fn_type func, void *data)
245{
246 return func (data);
247}
248
249static void*
250with_gc_active (GC_fn_type func, void *data)
251{
252 return func (data);
253}
254
255#endif /* HAVE_GC_DO_BLOCKING */
256
257
634aa8de 258\f
6180e336
NJ
259static void
260to_timespec (SCM t, scm_t_timespec *waittime)
261{
262 if (scm_is_pair (t))
263 {
264 waittime->tv_sec = scm_to_ulong (SCM_CAR (t));
265 waittime->tv_nsec = scm_to_ulong (SCM_CDR (t)) * 1000;
266 }
267 else
268 {
269 double time = scm_to_double (t);
270 double sec = scm_c_truncate (time);
271
272 waittime->tv_sec = (long) sec;
2a1d0688 273 waittime->tv_nsec = (long) ((time - sec) * 1000000000);
6180e336
NJ
274 }
275}
276
c058db8a 277\f
d823b11b 278/*** Queues */
7bfd3b9e 279
c058db8a
LC
280/* Note: We annotate with "GC-robust" assignments whose purpose is to avoid
281 the risk of false references leading to unbounded retained space as
282 described in "Bounding Space Usage of Conservative Garbage Collectors",
283 H.J. Boehm, 2001. */
284
9de87eea
MV
285/* Make an empty queue data structure.
286 */
d823b11b
MV
287static SCM
288make_queue ()
289{
290 return scm_cons (SCM_EOL, SCM_EOL);
291}
7bfd3b9e 292
9de87eea
MV
293/* Put T at the back of Q and return a handle that can be used with
294 remqueue to remove T from Q again.
295 */
d823b11b
MV
296static SCM
297enqueue (SCM q, SCM t)
298{
299 SCM c = scm_cons (t, SCM_EOL);
d2a51087 300 SCM_CRITICAL_SECTION_START;
d2e53ed6 301 if (scm_is_null (SCM_CDR (q)))
d823b11b
MV
302 SCM_SETCDR (q, c);
303 else
304 SCM_SETCDR (SCM_CAR (q), c);
305 SCM_SETCAR (q, c);
d2a51087 306 SCM_CRITICAL_SECTION_END;
d823b11b
MV
307 return c;
308}
7bfd3b9e 309
9de87eea
MV
310/* Remove the element that the handle C refers to from the queue Q. C
311 must have been returned from a call to enqueue. The return value
312 is zero when the element referred to by C has already been removed.
313 Otherwise, 1 is returned.
314*/
315static int
d823b11b
MV
316remqueue (SCM q, SCM c)
317{
318 SCM p, prev = q;
d2a51087 319 SCM_CRITICAL_SECTION_START;
d2e53ed6 320 for (p = SCM_CDR (q); !scm_is_null (p); p = SCM_CDR (p))
d823b11b 321 {
bc36d050 322 if (scm_is_eq (p, c))
d823b11b 323 {
bc36d050 324 if (scm_is_eq (c, SCM_CAR (q)))
d823b11b
MV
325 SCM_SETCAR (q, SCM_CDR (c));
326 SCM_SETCDR (prev, SCM_CDR (c));
c058db8a
LC
327
328 /* GC-robust */
329 SCM_SETCDR (c, SCM_EOL);
330
d2a51087 331 SCM_CRITICAL_SECTION_END;
9de87eea 332 return 1;
d823b11b
MV
333 }
334 prev = p;
335 }
d2a51087 336 SCM_CRITICAL_SECTION_END;
9de87eea 337 return 0;
d823b11b
MV
338}
339
9de87eea
MV
340/* Remove the front-most element from the queue Q and return it.
341 Return SCM_BOOL_F when Q is empty.
342*/
d823b11b
MV
343static SCM
344dequeue (SCM q)
345{
d2a51087
NJ
346 SCM c;
347 SCM_CRITICAL_SECTION_START;
348 c = SCM_CDR (q);
d2e53ed6 349 if (scm_is_null (c))
d2a51087
NJ
350 {
351 SCM_CRITICAL_SECTION_END;
352 return SCM_BOOL_F;
353 }
d823b11b
MV
354 else
355 {
356 SCM_SETCDR (q, SCM_CDR (c));
d2e53ed6 357 if (scm_is_null (SCM_CDR (q)))
d823b11b 358 SCM_SETCAR (q, SCM_EOL);
d2a51087 359 SCM_CRITICAL_SECTION_END;
c058db8a
LC
360
361 /* GC-robust */
362 SCM_SETCDR (c, SCM_EOL);
363
d823b11b
MV
364 return SCM_CAR (c);
365 }
366}
7bfd3b9e 367
9de87eea 368/*** Thread smob routines */
76da80e7 369
d823b11b
MV
370
371static int
372thread_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
373{
23d72566
KR
374 /* On a Gnu system pthread_t is an unsigned long, but on mingw it's a
375 struct. A cast like "(unsigned long) t->pthread" is a syntax error in
376 the struct case, hence we go via a union, and extract according to the
377 size of pthread_t. */
378 union {
379 scm_i_pthread_t p;
380 unsigned short us;
381 unsigned int ui;
382 unsigned long ul;
383 scm_t_uintmax um;
384 } u;
9de87eea 385 scm_i_thread *t = SCM_I_THREAD_DATA (exp);
23d72566
KR
386 scm_i_pthread_t p = t->pthread;
387 scm_t_uintmax id;
388 u.p = p;
389 if (sizeof (p) == sizeof (unsigned short))
390 id = u.us;
391 else if (sizeof (p) == sizeof (unsigned int))
392 id = u.ui;
393 else if (sizeof (p) == sizeof (unsigned long))
394 id = u.ul;
395 else
396 id = u.um;
397
d823b11b 398 scm_puts ("#<thread ", port);
23d72566 399 scm_uintprint (id, 10, port);
1b92fb6b 400 scm_puts (" (", port);
0345e278 401 scm_uintprint ((scm_t_bits)t, 16, port);
1b92fb6b 402 scm_puts (")>", port);
d823b11b
MV
403 return 1;
404}
405
706846f6 406\f
9de87eea 407/*** Blocking on queues. */
f7eca35d 408
9de87eea
MV
409/* See also scm_i_queue_async_cell for how such a block is
410 interrputed.
411*/
d823b11b 412
9de87eea
MV
413/* Put the current thread on QUEUE and go to sleep, waiting for it to
414 be woken up by a call to 'unblock_from_queue', or to be
415 interrupted. Upon return of this function, the current thread is
416 no longer on QUEUE, even when the sleep has been interrupted.
417
d2a51087 418 The caller of block_self must hold MUTEX. It will be atomically
9de87eea
MV
419 unlocked while sleeping, just as with scm_i_pthread_cond_wait.
420
421 SLEEP_OBJECT is an arbitrary SCM value that is kept alive as long
422 as MUTEX is needed.
423
424 When WAITTIME is not NULL, the sleep will be aborted at that time.
425
426 The return value of block_self is an errno value. It will be zero
427 when the sleep has been successfully completed by a call to
428 unblock_from_queue, EINTR when it has been interrupted by the
429 delivery of a system async, and ETIMEDOUT when the timeout has
430 expired.
431
432 The system asyncs themselves are not executed by block_self.
433*/
434static int
435block_self (SCM queue, SCM sleep_object, scm_i_pthread_mutex_t *mutex,
436 const scm_t_timespec *waittime)
76da80e7 437{
9de87eea
MV
438 scm_i_thread *t = SCM_I_CURRENT_THREAD;
439 SCM q_handle;
440 int err;
441
442 if (scm_i_setup_sleep (t, sleep_object, mutex, -1))
443 err = EINTR;
444 else
445 {
446 t->block_asyncs++;
447 q_handle = enqueue (queue, t->handle);
448 if (waittime == NULL)
449 err = scm_i_scm_pthread_cond_wait (&t->sleep_cond, mutex);
450 else
451 err = scm_i_scm_pthread_cond_timedwait (&t->sleep_cond, mutex, waittime);
452
453 /* When we are still on QUEUE, we have been interrupted. We
454 report this only when no other error (such as a timeout) has
455 happened above.
456 */
457 if (remqueue (queue, q_handle) && err == 0)
458 err = EINTR;
459 t->block_asyncs--;
460 scm_i_reset_sleep (t);
461 }
462
463 return err;
76da80e7 464}
9de87eea 465
d2a51087
NJ
466/* Wake up the first thread on QUEUE, if any. The awoken thread is
467 returned, or #f if the queue was empty.
9de87eea
MV
468 */
469static SCM
470unblock_from_queue (SCM queue)
471{
472 SCM thread = dequeue (queue);
473 if (scm_is_true (thread))
474 scm_i_pthread_cond_signal (&SCM_I_THREAD_DATA(thread)->sleep_cond);
475 return thread;
476}
477
45f15cac 478\f
9de87eea
MV
479/* Getting into and out of guile mode.
480 */
481
f60a7648
AW
482/* Key used to attach a cleanup handler to a given thread. Also, if
483 thread-local storage is unavailable, this key is used to retrieve the
484 current thread with `pthread_getspecific ()'. */
485scm_i_pthread_key_t scm_i_thread_key;
486
487
705edb95
LC
488#ifdef SCM_HAVE_THREAD_STORAGE_CLASS
489
490/* When thread-local storage (TLS) is available, a pointer to the
491 current-thread object is kept in TLS. Note that storing the thread-object
492 itself in TLS (rather than a pointer to some malloc'd memory) is not
493 possible since thread objects may live longer than the actual thread they
494 represent. */
495SCM_THREAD_LOCAL scm_i_thread *scm_i_current_thread = NULL;
496
f60a7648 497#endif /* SCM_HAVE_THREAD_STORAGE_CLASS */
705edb95 498
d823b11b 499
9de87eea
MV
500static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
501static scm_i_thread *all_threads = NULL;
502static int thread_count;
503
504static SCM scm_i_default_dynamic_state;
505
0b77014f
AW
506/* Run when a fluid is collected. */
507void
aafb4ed7 508scm_i_reset_fluid (size_t n)
0b77014f
AW
509{
510 scm_i_thread *t;
511
512 scm_i_pthread_mutex_lock (&thread_admin_mutex);
513 for (t = all_threads; t; t = t->next_thread)
514 if (SCM_I_DYNAMIC_STATE_P (t->dynamic_state))
515 {
516 SCM v = SCM_I_DYNAMIC_STATE_FLUIDS (t->dynamic_state);
517
518 if (n < SCM_SIMPLE_VECTOR_LENGTH (v))
aafb4ed7 519 SCM_SIMPLE_VECTOR_SET (v, n, SCM_UNDEFINED);
0b77014f
AW
520 }
521 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
522}
523
9de87eea 524/* Perform first stage of thread initialisation, in non-guile mode.
d823b11b 525 */
9de87eea 526static void
12c1d861 527guilify_self_1 (struct GC_stack_base *base)
d823b11b 528{
7f22442b
AW
529 scm_i_thread t;
530
531 /* We must arrange for SCM_I_CURRENT_THREAD to point to a valid value
532 before allocating anything in this thread, because allocation could
533 cause GC to run, and GC could cause finalizers, which could invoke
534 Scheme functions, which need the current thread to be set. */
535
536 t.pthread = scm_i_pthread_self ();
537 t.handle = SCM_BOOL_F;
538 t.result = SCM_BOOL_F;
539 t.cleanup_handler = SCM_BOOL_F;
540 t.mutexes = SCM_EOL;
541 t.held_mutex = NULL;
542 t.join_queue = SCM_EOL;
543 t.dynamic_state = SCM_BOOL_F;
544 t.dynwinds = SCM_EOL;
545 t.active_asyncs = SCM_EOL;
546 t.block_asyncs = 1;
547 t.pending_asyncs = 1;
548 t.critical_section_level = 0;
549 t.base = base->mem_base;
346e4402 550#ifdef __ia64__
7f22442b 551 t.register_backing_store_base = base->reg-base;
346e4402 552#endif
7f22442b
AW
553 t.continuation_root = SCM_EOL;
554 t.continuation_base = t.base;
555 scm_i_pthread_cond_init (&t.sleep_cond, NULL);
556 t.sleep_mutex = NULL;
557 t.sleep_object = SCM_BOOL_F;
558 t.sleep_fd = -1;
559
32f94bf2 560 if (pipe2 (t.sleep_pipe, O_CLOEXEC) != 0)
634aa8de
LC
561 /* FIXME: Error conditions during the initialization phase are handled
562 gracelessly since public functions such as `scm_init_guile ()'
563 currently have type `void'. */
564 abort ();
565
7f22442b
AW
566 scm_i_pthread_mutex_init (&t.admin_mutex, NULL);
567 t.current_mark_stack_ptr = NULL;
568 t.current_mark_stack_limit = NULL;
569 t.canceled = 0;
570 t.exited = 0;
571 t.guile_mode = 0;
9de87eea 572
7f22442b
AW
573 /* The switcheroo. */
574 {
575 scm_i_thread *t_ptr = &t;
576
577 GC_disable ();
578 t_ptr = GC_malloc (sizeof (scm_i_thread));
579 memcpy (t_ptr, &t, sizeof t);
580
581 scm_i_pthread_setspecific (scm_i_thread_key, t_ptr);
f60a7648
AW
582
583#ifdef SCM_HAVE_THREAD_STORAGE_CLASS
7f22442b
AW
584 /* Cache the current thread in TLS for faster lookup. */
585 scm_i_current_thread = t_ptr;
f60a7648 586#endif
9de87eea 587
7f22442b
AW
588 scm_i_pthread_mutex_lock (&thread_admin_mutex);
589 t_ptr->next_thread = all_threads;
590 all_threads = t_ptr;
591 thread_count++;
592 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
593
594 GC_enable ();
595 }
d823b11b
MV
596}
597
9de87eea 598/* Perform second stage of thread initialisation, in guile mode.
d823b11b 599 */
9de87eea
MV
600static void
601guilify_self_2 (SCM parent)
d823b11b 602{
9de87eea
MV
603 scm_i_thread *t = SCM_I_CURRENT_THREAD;
604
72e6b608
LC
605 t->guile_mode = 1;
606
9de87eea 607 SCM_NEWSMOB (t->handle, scm_tc16_thread, t);
c812243b 608
9de87eea
MV
609 t->continuation_root = scm_cons (t->handle, SCM_EOL);
610 t->continuation_base = t->base;
2bbe1533 611 t->vm = SCM_BOOL_F;
9de87eea
MV
612
613 if (scm_is_true (parent))
614 t->dynamic_state = scm_make_dynamic_state (parent);
615 else
616 t->dynamic_state = scm_i_make_initial_dynamic_state ();
617
618 t->join_queue = make_queue ();
619 t->block_asyncs = 0;
d823b11b
MV
620}
621
6180e336
NJ
622\f
623/*** Fat mutexes */
624
625/* We implement our own mutex type since we want them to be 'fair', we
626 want to do fancy things while waiting for them (like running
627 asyncs) and we might want to add things that are nice for
628 debugging.
629*/
630
631typedef struct {
632 scm_i_pthread_mutex_t lock;
633 SCM owner;
adc085f1 634 int level; /* how much the owner owns us. <= 1 for non-recursive mutexes */
6180e336 635
adc085f1 636 int recursive; /* allow recursive locking? */
6180e336
NJ
637 int unchecked_unlock; /* is it an error to unlock an unlocked mutex? */
638 int allow_external_unlock; /* is it an error to unlock a mutex that is not
639 owned by the current thread? */
640
641 SCM waiting; /* the threads waiting for this mutex. */
642} fat_mutex;
643
644#define SCM_MUTEXP(x) SCM_SMOB_PREDICATE (scm_tc16_mutex, x)
645#define SCM_MUTEX_DATA(x) ((fat_mutex *) SCM_SMOB_DATA (x))
646
2002f1f8
AW
647static SCM
648call_cleanup (void *data)
649{
650 SCM *proc_p = data;
651 return scm_call_0 (*proc_p);
652}
653
9de87eea 654/* Perform thread tear-down, in guile mode.
d823b11b 655 */
9de87eea
MV
656static void *
657do_thread_exit (void *v)
658{
2e77f720
LC
659 scm_i_thread *t = (scm_i_thread *) v;
660
91230883
LC
661 /* Ensure the signal handling thread has been launched, because we might be
662 shutting it down. This needs to be done in Guile mode. */
663 scm_i_ensure_signal_delivery_thread ();
664
2e77f720
LC
665 if (!scm_is_false (t->cleanup_handler))
666 {
667 SCM ptr = t->cleanup_handler;
668
669 t->cleanup_handler = SCM_BOOL_F;
670 t->result = scm_internal_catch (SCM_BOOL_T,
2002f1f8 671 call_cleanup, &ptr,
2e77f720
LC
672 scm_handle_by_message_noexit, NULL);
673 }
9de87eea 674
86a597f8 675 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
9de87eea
MV
676
677 t->exited = 1;
0c97d7dd
MV
678 close (t->sleep_pipe[0]);
679 close (t->sleep_pipe[1]);
9de87eea
MV
680 while (scm_is_true (unblock_from_queue (t->join_queue)))
681 ;
9de87eea 682
74926120 683 while (!scm_is_null (t->mutexes))
6180e336 684 {
a0faf7dd 685 SCM mutex = SCM_WEAK_PAIR_CAR (t->mutexes);
74926120 686
a0faf7dd
LC
687 if (!SCM_UNBNDP (mutex))
688 {
689 fat_mutex *m = SCM_MUTEX_DATA (mutex);
690
691 scm_i_pthread_mutex_lock (&m->lock);
f57fdf07
LC
692
693 /* Since MUTEX is in `t->mutexes', T must be its owner. */
694 assert (scm_is_eq (m->owner, t->handle));
695
a0faf7dd 696 unblock_from_queue (m->waiting);
f57fdf07 697
a0faf7dd
LC
698 scm_i_pthread_mutex_unlock (&m->lock);
699 }
6180e336 700
a0faf7dd 701 t->mutexes = SCM_WEAK_PAIR_CDR (t->mutexes);
6180e336
NJ
702 }
703
86a597f8 704 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720 705
9de87eea
MV
706 return NULL;
707}
708
f60a7648
AW
709static void *
710do_thread_exit_trampoline (struct GC_stack_base *sb, void *v)
711{
7f22442b 712 /* Won't hurt if we are already registered. */
8e76ce94 713#if SCM_USE_PTHREAD_THREADS
7f22442b 714 GC_register_my_thread (sb);
8e76ce94 715#endif
f60a7648 716
7f22442b 717 return scm_with_guile (do_thread_exit, v);
f60a7648
AW
718}
719
d823b11b 720static void
9de87eea 721on_thread_exit (void *v)
d823b11b 722{
29776e85 723 /* This handler is executed in non-guile mode. */
2e77f720 724 scm_i_thread *t = (scm_i_thread *) v, **tp;
0c97d7dd 725
b8441577
LC
726 /* If we were canceled, we were unable to clear `t->guile_mode', so do
727 it here. */
728 t->guile_mode = 0;
729
d2a51087
NJ
730 /* If this thread was cancelled while doing a cond wait, it will
731 still have a mutex locked, so we unlock it here. */
732 if (t->held_mutex)
733 {
734 scm_i_pthread_mutex_unlock (t->held_mutex);
735 t->held_mutex = NULL;
736 }
737
f60a7648
AW
738 /* Reinstate the current thread for purposes of scm_with_guile
739 guile-mode cleanup handlers. Only really needed in the non-TLS
740 case but it doesn't hurt to be consistent. */
741 scm_i_pthread_setspecific (scm_i_thread_key, t);
0c97d7dd 742
7f22442b
AW
743 /* Scheme-level thread finalizers and other cleanup needs to happen in
744 guile mode. */
745 GC_call_with_stack_base (do_thread_exit_trampoline, t);
0c97d7dd
MV
746
747 /* Removing ourself from the list of all threads needs to happen in
748 non-guile mode since all SCM values on our stack become
29776e85 749 unprotected once we are no longer in the list. */
0c97d7dd
MV
750 scm_i_pthread_mutex_lock (&thread_admin_mutex);
751 for (tp = &all_threads; *tp; tp = &(*tp)->next_thread)
752 if (*tp == t)
753 {
754 *tp = t->next_thread;
c058db8a
LC
755
756 /* GC-robust */
757 t->next_thread = NULL;
758
0c97d7dd
MV
759 break;
760 }
761 thread_count--;
2e77f720
LC
762
763 /* If there's only one other thread, it could be the signal delivery
764 thread, so we need to notify it to shut down by closing its read pipe.
765 If it's not the signal delivery thread, then closing the read pipe isn't
766 going to hurt. */
767 if (thread_count <= 1)
768 scm_i_close_signal_pipe ();
769
0c97d7dd
MV
770 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
771
f60a7648 772 scm_i_pthread_setspecific (scm_i_thread_key, NULL);
7f22442b 773
8e76ce94 774#if SCM_USE_PTHREAD_THREADS
7f22442b 775 GC_unregister_my_thread ();
653ccd78 776#endif
d823b11b
MV
777}
778
9de87eea 779static scm_i_pthread_once_t init_thread_key_once = SCM_I_PTHREAD_ONCE_INIT;
d823b11b 780
9de87eea
MV
781static void
782init_thread_key (void)
783{
f60a7648 784 scm_i_pthread_key_create (&scm_i_thread_key, on_thread_exit);
9de87eea 785}
d823b11b 786
cde24ce1
AW
787/* Perform any initializations necessary to make the current thread
788 known to Guile (via SCM_I_CURRENT_THREAD), initializing Guile itself,
789 if necessary.
a54a94b3 790
9de87eea
MV
791 BASE is the stack base to use with GC.
792
793 PARENT is the dynamic state to use as the parent, ot SCM_BOOL_F in
794 which case the default dynamic state is used.
795
cde24ce1 796 Returns zero when the thread was known to guile already; otherwise
9de87eea 797 return 1.
cde24ce1
AW
798
799 Note that it could be the case that the thread was known
800 to Guile, but not in guile mode (because we are within a
801 scm_without_guile call). Check SCM_I_CURRENT_THREAD->guile_mode to
802 be sure. New threads are put into guile mode implicitly. */
9de87eea
MV
803
804static int
12c1d861 805scm_i_init_thread_for_guile (struct GC_stack_base *base, SCM parent)
d823b11b 806{
9de87eea
MV
807 scm_i_pthread_once (&init_thread_key_once, init_thread_key);
808
cde24ce1
AW
809 if (SCM_I_CURRENT_THREAD)
810 {
811 /* Thread is already known to Guile.
812 */
813 return 0;
814 }
815 else
9de87eea
MV
816 {
817 /* This thread has not been guilified yet.
818 */
819
820 scm_i_pthread_mutex_lock (&scm_i_init_mutex);
821 if (scm_initialized_p == 0)
822 {
823 /* First thread ever to enter Guile. Run the full
824 initialization.
825 */
826 scm_i_init_guile (base);
12c1d861 827
8e76ce94 828#if defined (HAVE_GC_ALLOW_REGISTER_THREADS) && SCM_USE_PTHREAD_THREADS
12c1d861
AW
829 /* Allow other threads to come in later. */
830 GC_allow_register_threads ();
4000d064 831#endif
12c1d861 832
9de87eea
MV
833 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
834 }
835 else
836 {
837 /* Guile is already initialized, but this thread enters it for
838 the first time. Only initialize this thread.
839 */
840 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
12c1d861
AW
841
842 /* Register this thread with libgc. */
8e76ce94 843#if SCM_USE_PTHREAD_THREADS
12c1d861 844 GC_register_my_thread (base);
8e76ce94 845#endif
12c1d861 846
9de87eea
MV
847 guilify_self_1 (base);
848 guilify_self_2 (parent);
849 }
850 return 1;
851 }
d823b11b
MV
852}
853
12c1d861
AW
854void
855scm_init_guile ()
d823b11b 856{
12c1d861
AW
857 struct GC_stack_base stack_base;
858
859 if (GC_get_stack_base (&stack_base) == GC_SUCCESS)
860 scm_i_init_thread_for_guile (&stack_base,
861 scm_i_default_dynamic_state);
9de87eea
MV
862 else
863 {
12c1d861
AW
864 fprintf (stderr, "Failed to get stack base for current thread.\n");
865 exit (1);
9de87eea 866 }
a54a94b3
MV
867}
868
12c1d861 869struct with_guile_args
cde24ce1
AW
870{
871 GC_fn_type func;
872 void *data;
12c1d861 873 SCM parent;
cde24ce1
AW
874};
875
876static void *
877with_guile_trampoline (void *data)
878{
12c1d861 879 struct with_guile_args *args = data;
cde24ce1
AW
880
881 return scm_c_with_continuation_barrier (args->func, args->data);
882}
883
12c1d861
AW
884static void *
885with_guile_and_parent (struct GC_stack_base *base, void *data)
9de87eea
MV
886{
887 void *res;
cde24ce1
AW
888 int new_thread;
889 scm_i_thread *t;
12c1d861 890 struct with_guile_args *args = data;
2e77f720 891
12c1d861 892 new_thread = scm_i_init_thread_for_guile (base, args->parent);
cde24ce1
AW
893 t = SCM_I_CURRENT_THREAD;
894 if (new_thread)
2e77f720 895 {
cde24ce1
AW
896 /* We are in Guile mode. */
897 assert (t->guile_mode);
898
12c1d861 899 res = scm_c_with_continuation_barrier (args->func, args->data);
cde24ce1
AW
900
901 /* Leave Guile mode. */
902 t->guile_mode = 0;
903 }
904 else if (t->guile_mode)
905 {
906 /* Already in Guile mode. */
12c1d861 907 res = scm_c_with_continuation_barrier (args->func, args->data);
2e77f720 908 }
74926120 909 else
cde24ce1 910 {
cde24ce1
AW
911 /* We are not in Guile mode, either because we are not within a
912 scm_with_guile, or because we are within a scm_without_guile.
72e6b608 913
cde24ce1
AW
914 This call to scm_with_guile() could happen from anywhere on the
915 stack, and in particular lower on the stack than when it was
916 when this thread was first guilified. Thus, `base' must be
917 updated. */
918#if SCM_STACK_GROWS_UP
12c1d861
AW
919 if (SCM_STACK_PTR (base->mem_base) < t->base)
920 t->base = SCM_STACK_PTR (base->mem_base);
cde24ce1 921#else
12c1d861
AW
922 if (SCM_STACK_PTR (base->mem_base) > t->base)
923 t->base = SCM_STACK_PTR (base->mem_base);
cde24ce1 924#endif
72e6b608 925
cde24ce1 926 t->guile_mode = 1;
12c1d861 927 res = with_gc_active (with_guile_trampoline, args);
cde24ce1
AW
928 t->guile_mode = 0;
929 }
930 return res;
72e6b608 931}
3d1af79f 932
12c1d861
AW
933static void *
934scm_i_with_guile_and_parent (void *(*func)(void *), void *data, SCM parent)
935{
936 struct with_guile_args args;
937
938 args.func = func;
939 args.data = data;
940 args.parent = parent;
941
942 return GC_call_with_stack_base (with_guile_and_parent, &args);
943}
944
945void *
946scm_with_guile (void *(*func)(void *), void *data)
947{
948 return scm_i_with_guile_and_parent (func, data,
949 scm_i_default_dynamic_state);
950}
951
9de87eea
MV
952void *
953scm_without_guile (void *(*func)(void *), void *data)
d823b11b 954{
72e6b608 955 void *result;
cde24ce1 956 scm_i_thread *t = SCM_I_CURRENT_THREAD;
72e6b608 957
cde24ce1 958 if (t->guile_mode)
72e6b608 959 {
cde24ce1
AW
960 SCM_I_CURRENT_THREAD->guile_mode = 0;
961 result = with_gc_inactive (func, data);
962 SCM_I_CURRENT_THREAD->guile_mode = 1;
72e6b608
LC
963 }
964 else
cde24ce1 965 /* Otherwise we're not in guile mode, so nothing to do. */
72e6b608
LC
966 result = func (data);
967
968 return result;
9de87eea
MV
969}
970
72e6b608 971\f
9de87eea
MV
972/*** Thread creation */
973
974typedef struct {
975 SCM parent;
976 SCM thunk;
977 SCM handler;
76da80e7 978 SCM thread;
9de87eea
MV
979 scm_i_pthread_mutex_t mutex;
980 scm_i_pthread_cond_t cond;
981} launch_data;
d823b11b 982
9de87eea
MV
983static void *
984really_launch (void *d)
985{
986 launch_data *data = (launch_data *)d;
987 SCM thunk = data->thunk, handler = data->handler;
988 scm_i_thread *t;
d823b11b 989
9de87eea 990 t = SCM_I_CURRENT_THREAD;
a54a94b3 991
9de87eea
MV
992 scm_i_scm_pthread_mutex_lock (&data->mutex);
993 data->thread = scm_current_thread ();
994 scm_i_pthread_cond_signal (&data->cond);
995 scm_i_pthread_mutex_unlock (&data->mutex);
996
997 if (SCM_UNBNDP (handler))
998 t->result = scm_call_0 (thunk);
999 else
1000 t->result = scm_catch (SCM_BOOL_T, thunk, handler);
1001
1002 return 0;
d823b11b
MV
1003}
1004
9de87eea
MV
1005static void *
1006launch_thread (void *d)
1007{
1008 launch_data *data = (launch_data *)d;
1009 scm_i_pthread_detach (scm_i_pthread_self ());
1010 scm_i_with_guile_and_parent (really_launch, d, data->parent);
1011 return NULL;
1012}
1013
1014SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 1, 1, 0,
d823b11b 1015 (SCM thunk, SCM handler),
9de87eea
MV
1016 "Call @code{thunk} in a new thread and with a new dynamic state,\n"
1017 "returning a new thread object representing the thread. The procedure\n"
1018 "@var{thunk} is called via @code{with-continuation-barrier}.\n"
1019 "\n"
1020 "When @var{handler} is specified, then @var{thunk} is called from\n"
1021 "within a @code{catch} with tag @code{#t} that has @var{handler} as its\n"
1022 "handler. This catch is established inside the continuation barrier.\n"
1023 "\n"
1024 "Once @var{thunk} or @var{handler} returns, the return value is made\n"
1025 "the @emph{exit value} of the thread and the thread is terminated.")
d823b11b
MV
1026#define FUNC_NAME s_scm_call_with_new_thread
1027{
9de87eea
MV
1028 launch_data data;
1029 scm_i_pthread_t id;
1030 int err;
d823b11b 1031
9de87eea
MV
1032 SCM_ASSERT (scm_is_true (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
1033 SCM_ASSERT (SCM_UNBNDP (handler) || scm_is_true (scm_procedure_p (handler)),
1034 handler, SCM_ARG2, FUNC_NAME);
1035
9f7537dc 1036 GC_collect_a_little ();
9de87eea
MV
1037 data.parent = scm_current_dynamic_state ();
1038 data.thunk = thunk;
1039 data.handler = handler;
1040 data.thread = SCM_BOOL_F;
1041 scm_i_pthread_mutex_init (&data.mutex, NULL);
1042 scm_i_pthread_cond_init (&data.cond, NULL);
1043
1044 scm_i_scm_pthread_mutex_lock (&data.mutex);
1045 err = scm_i_pthread_create (&id, NULL, launch_thread, &data);
1046 if (err)
1047 {
1048 scm_i_pthread_mutex_unlock (&data.mutex);
1049 errno = err;
1050 scm_syserror (NULL);
1051 }
1052 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
1053 scm_i_pthread_mutex_unlock (&data.mutex);
74926120 1054
9de87eea 1055 return data.thread;
d823b11b
MV
1056}
1057#undef FUNC_NAME
1058
9de87eea
MV
1059typedef struct {
1060 SCM parent;
1061 scm_t_catch_body body;
1062 void *body_data;
1063 scm_t_catch_handler handler;
1064 void *handler_data;
1065 SCM thread;
1066 scm_i_pthread_mutex_t mutex;
1067 scm_i_pthread_cond_t cond;
1068} spawn_data;
1069
1070static void *
1071really_spawn (void *d)
1072{
1073 spawn_data *data = (spawn_data *)d;
1074 scm_t_catch_body body = data->body;
1075 void *body_data = data->body_data;
1076 scm_t_catch_handler handler = data->handler;
1077 void *handler_data = data->handler_data;
1078 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1079
1080 scm_i_scm_pthread_mutex_lock (&data->mutex);
1081 data->thread = scm_current_thread ();
1082 scm_i_pthread_cond_signal (&data->cond);
1083 scm_i_pthread_mutex_unlock (&data->mutex);
1084
1085 if (handler == NULL)
1086 t->result = body (body_data);
1087 else
1088 t->result = scm_internal_catch (SCM_BOOL_T,
1089 body, body_data,
1090 handler, handler_data);
1091
1092 return 0;
1093}
1094
1095static void *
1096spawn_thread (void *d)
1097{
1098 spawn_data *data = (spawn_data *)d;
1099 scm_i_pthread_detach (scm_i_pthread_self ());
1100 scm_i_with_guile_and_parent (really_spawn, d, data->parent);
1101 return NULL;
1102}
1103
1104SCM
1105scm_spawn_thread (scm_t_catch_body body, void *body_data,
1106 scm_t_catch_handler handler, void *handler_data)
1107{
1108 spawn_data data;
1109 scm_i_pthread_t id;
1110 int err;
1111
1112 data.parent = scm_current_dynamic_state ();
1113 data.body = body;
1114 data.body_data = body_data;
1115 data.handler = handler;
1116 data.handler_data = handler_data;
1117 data.thread = SCM_BOOL_F;
1118 scm_i_pthread_mutex_init (&data.mutex, NULL);
1119 scm_i_pthread_cond_init (&data.cond, NULL);
1120
1121 scm_i_scm_pthread_mutex_lock (&data.mutex);
1122 err = scm_i_pthread_create (&id, NULL, spawn_thread, &data);
1123 if (err)
1124 {
1125 scm_i_pthread_mutex_unlock (&data.mutex);
1126 errno = err;
1127 scm_syserror (NULL);
1128 }
1129 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
1130 scm_i_pthread_mutex_unlock (&data.mutex);
74926120 1131
9de87eea
MV
1132 return data.thread;
1133}
1134
29717c89
MD
1135SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
1136 (),
1137"Move the calling thread to the end of the scheduling queue.")
1138#define FUNC_NAME s_scm_yield
1139{
9de87eea 1140 return scm_from_bool (scm_i_sched_yield ());
29717c89
MD
1141}
1142#undef FUNC_NAME
1143
2e77f720
LC
1144SCM_DEFINE (scm_cancel_thread, "cancel-thread", 1, 0, 0,
1145 (SCM thread),
1146"Asynchronously force the target @var{thread} to terminate. @var{thread} "
1147"cannot be the current thread, and if @var{thread} has already terminated or "
1148"been signaled to terminate, this function is a no-op.")
1149#define FUNC_NAME s_scm_cancel_thread
1150{
1151 scm_i_thread *t = NULL;
1152
1153 SCM_VALIDATE_THREAD (1, thread);
1154 t = SCM_I_THREAD_DATA (thread);
86a597f8 1155 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
2e77f720
LC
1156 if (!t->canceled)
1157 {
1158 t->canceled = 1;
86a597f8 1159 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1160 scm_i_pthread_cancel (t->pthread);
1161 }
1162 else
86a597f8 1163 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1164
1165 return SCM_UNSPECIFIED;
1166}
1167#undef FUNC_NAME
1168
1169SCM_DEFINE (scm_set_thread_cleanup_x, "set-thread-cleanup!", 2, 0, 0,
1170 (SCM thread, SCM proc),
1171"Set the thunk @var{proc} as the cleanup handler for the thread @var{thread}. "
1172"This handler will be called when the thread exits.")
1173#define FUNC_NAME s_scm_set_thread_cleanup_x
1174{
1175 scm_i_thread *t;
1176
1177 SCM_VALIDATE_THREAD (1, thread);
1178 if (!scm_is_false (proc))
1179 SCM_VALIDATE_THUNK (2, proc);
1180
2e77f720 1181 t = SCM_I_THREAD_DATA (thread);
86a597f8
NJ
1182 scm_i_pthread_mutex_lock (&t->admin_mutex);
1183
2e77f720
LC
1184 if (!(t->exited || t->canceled))
1185 t->cleanup_handler = proc;
1186
86a597f8 1187 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1188
1189 return SCM_UNSPECIFIED;
1190}
1191#undef FUNC_NAME
1192
1193SCM_DEFINE (scm_thread_cleanup, "thread-cleanup", 1, 0, 0,
1194 (SCM thread),
1195"Return the cleanup handler installed for the thread @var{thread}.")
1196#define FUNC_NAME s_scm_thread_cleanup
1197{
1198 scm_i_thread *t;
1199 SCM ret;
1200
1201 SCM_VALIDATE_THREAD (1, thread);
1202
2e77f720 1203 t = SCM_I_THREAD_DATA (thread);
86a597f8 1204 scm_i_pthread_mutex_lock (&t->admin_mutex);
2e77f720 1205 ret = (t->exited || t->canceled) ? SCM_BOOL_F : t->cleanup_handler;
86a597f8 1206 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1207
1208 return ret;
1209}
1210#undef FUNC_NAME
1211
6180e336
NJ
1212SCM scm_join_thread (SCM thread)
1213{
1214 return scm_join_thread_timed (thread, SCM_UNDEFINED, SCM_UNDEFINED);
1215}
1216
1217SCM_DEFINE (scm_join_thread_timed, "join-thread", 1, 2, 0,
1218 (SCM thread, SCM timeout, SCM timeoutval),
d823b11b
MV
1219"Suspend execution of the calling thread until the target @var{thread} "
1220"terminates, unless the target @var{thread} has already terminated. ")
6180e336 1221#define FUNC_NAME s_scm_join_thread_timed
5f05c406 1222{
9de87eea 1223 scm_i_thread *t;
6180e336
NJ
1224 scm_t_timespec ctimeout, *timeout_ptr = NULL;
1225 SCM res = SCM_BOOL_F;
1226
1227 if (! (SCM_UNBNDP (timeoutval)))
1228 res = timeoutval;
d823b11b
MV
1229
1230 SCM_VALIDATE_THREAD (1, thread);
9de87eea 1231 if (scm_is_eq (scm_current_thread (), thread))
2e77f720 1232 SCM_MISC_ERROR ("cannot join the current thread", SCM_EOL);
d823b11b 1233
9de87eea 1234 t = SCM_I_THREAD_DATA (thread);
86a597f8
NJ
1235 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
1236
6180e336
NJ
1237 if (! SCM_UNBNDP (timeout))
1238 {
1239 to_timespec (timeout, &ctimeout);
1240 timeout_ptr = &ctimeout;
1241 }
1242
1243 if (t->exited)
1244 res = t->result;
1245 else
d823b11b 1246 {
9de87eea
MV
1247 while (1)
1248 {
74926120 1249 int err = block_self (t->join_queue, thread, &t->admin_mutex,
6180e336
NJ
1250 timeout_ptr);
1251 if (err == 0)
1252 {
1253 if (t->exited)
1254 {
1255 res = t->result;
1256 break;
1257 }
1258 }
1259 else if (err == ETIMEDOUT)
9de87eea 1260 break;
6180e336 1261
86a597f8 1262 scm_i_pthread_mutex_unlock (&t->admin_mutex);
9de87eea 1263 SCM_TICK;
86a597f8 1264 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
21346c4f
NJ
1265
1266 /* Check for exit again, since we just released and
1267 reacquired the admin mutex, before the next block_self
1268 call (which would block forever if t has already
1269 exited). */
1270 if (t->exited)
1271 {
1272 res = t->result;
1273 break;
1274 }
9de87eea 1275 }
d823b11b 1276 }
9de87eea 1277
86a597f8 1278 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720 1279
d823b11b 1280 return res;
5f05c406
MV
1281}
1282#undef FUNC_NAME
1283
6180e336
NJ
1284SCM_DEFINE (scm_thread_p, "thread?", 1, 0, 0,
1285 (SCM obj),
1286 "Return @code{#t} if @var{obj} is a thread.")
1287#define FUNC_NAME s_scm_thread_p
1288{
1289 return SCM_I_IS_THREAD(obj) ? SCM_BOOL_T : SCM_BOOL_F;
1290}
1291#undef FUNC_NAME
5f05c406 1292
4079f87e 1293
9de87eea
MV
1294static size_t
1295fat_mutex_free (SCM mx)
76da80e7 1296{
9de87eea
MV
1297 fat_mutex *m = SCM_MUTEX_DATA (mx);
1298 scm_i_pthread_mutex_destroy (&m->lock);
76da80e7
MV
1299 return 0;
1300}
1301
1302static int
9de87eea 1303fat_mutex_print (SCM mx, SCM port, scm_print_state *pstate SCM_UNUSED)
76da80e7 1304{
9de87eea
MV
1305 fat_mutex *m = SCM_MUTEX_DATA (mx);
1306 scm_puts ("#<mutex ", port);
1307 scm_uintprint ((scm_t_bits)m, 16, port);
1308 scm_puts (">", port);
1309 return 1;
76da80e7
MV
1310}
1311
76da80e7 1312static SCM
6180e336 1313make_fat_mutex (int recursive, int unchecked_unlock, int external_unlock)
76da80e7 1314{
9de87eea
MV
1315 fat_mutex *m;
1316 SCM mx;
1317
1318 m = scm_gc_malloc (sizeof (fat_mutex), "mutex");
1319 scm_i_pthread_mutex_init (&m->lock, NULL);
1320 m->owner = SCM_BOOL_F;
adc085f1 1321 m->level = 0;
6180e336 1322
adc085f1 1323 m->recursive = recursive;
6180e336
NJ
1324 m->unchecked_unlock = unchecked_unlock;
1325 m->allow_external_unlock = external_unlock;
1326
9de87eea
MV
1327 m->waiting = SCM_EOL;
1328 SCM_NEWSMOB (mx, scm_tc16_mutex, (scm_t_bits) m);
1329 m->waiting = make_queue ();
1330 return mx;
76da80e7
MV
1331}
1332
6180e336
NJ
1333SCM scm_make_mutex (void)
1334{
1335 return scm_make_mutex_with_flags (SCM_EOL);
1336}
1337
2a1d0688
NJ
1338SCM_SYMBOL (unchecked_unlock_sym, "unchecked-unlock");
1339SCM_SYMBOL (allow_external_unlock_sym, "allow-external-unlock");
1340SCM_SYMBOL (recursive_sym, "recursive");
6180e336
NJ
1341
1342SCM_DEFINE (scm_make_mutex_with_flags, "make-mutex", 0, 0, 1,
1343 (SCM flags),
9de87eea 1344 "Create a new mutex. ")
6180e336 1345#define FUNC_NAME s_scm_make_mutex_with_flags
76da80e7 1346{
6180e336
NJ
1347 int unchecked_unlock = 0, external_unlock = 0, recursive = 0;
1348
1349 SCM ptr = flags;
1350 while (! scm_is_null (ptr))
1351 {
1352 SCM flag = SCM_CAR (ptr);
1353 if (scm_is_eq (flag, unchecked_unlock_sym))
1354 unchecked_unlock = 1;
1355 else if (scm_is_eq (flag, allow_external_unlock_sym))
1356 external_unlock = 1;
1357 else if (scm_is_eq (flag, recursive_sym))
1358 recursive = 1;
74926120 1359 else
2a1d0688 1360 SCM_MISC_ERROR ("unsupported mutex option: ~a", scm_list_1 (flag));
6180e336
NJ
1361 ptr = SCM_CDR (ptr);
1362 }
1363 return make_fat_mutex (recursive, unchecked_unlock, external_unlock);
76da80e7
MV
1364}
1365#undef FUNC_NAME
1366
9de87eea 1367SCM_DEFINE (scm_make_recursive_mutex, "make-recursive-mutex", 0, 0, 0,
9bc4701c 1368 (void),
9de87eea
MV
1369 "Create a new recursive mutex. ")
1370#define FUNC_NAME s_scm_make_recursive_mutex
9bc4701c 1371{
6180e336 1372 return make_fat_mutex (1, 0, 0);
9bc4701c
MD
1373}
1374#undef FUNC_NAME
1375
6180e336
NJ
1376SCM_SYMBOL (scm_abandoned_mutex_error_key, "abandoned-mutex-error");
1377
1378static SCM
adc085f1 1379fat_mutex_lock (SCM mutex, scm_t_timespec *timeout, SCM owner, int *ret)
9de87eea
MV
1380{
1381 fat_mutex *m = SCM_MUTEX_DATA (mutex);
6180e336 1382
adc085f1 1383 SCM new_owner = SCM_UNBNDP (owner) ? scm_current_thread() : owner;
6180e336
NJ
1384 SCM err = SCM_BOOL_F;
1385
1386 struct timeval current_time;
9de87eea
MV
1387
1388 scm_i_scm_pthread_mutex_lock (&m->lock);
adc085f1
JG
1389
1390 while (1)
9de87eea 1391 {
adc085f1 1392 if (m->level == 0)
6180e336 1393 {
adc085f1 1394 m->owner = new_owner;
6180e336 1395 m->level++;
74926120 1396
adc085f1 1397 if (SCM_I_IS_THREAD (new_owner))
6180e336 1398 {
adc085f1 1399 scm_i_thread *t = SCM_I_THREAD_DATA (new_owner);
ccb80964 1400
4f39f31e
LC
1401 /* FIXME: The order in which `t->admin_mutex' and
1402 `m->lock' are taken differs from that in
1403 `on_thread_exit', potentially leading to deadlocks. */
6180e336 1404 scm_i_pthread_mutex_lock (&t->admin_mutex);
a0faf7dd
LC
1405
1406 /* Only keep a weak reference to MUTEX so that it's not
f57fdf07
LC
1407 retained when not referenced elsewhere (bug #27450).
1408 The weak pair itself is eventually removed when MUTEX
1409 is unlocked. Note that `t->mutexes' lists mutexes
1410 currently held by T, so it should be small. */
a0faf7dd
LC
1411 t->mutexes = scm_weak_car_pair (mutex, t->mutexes);
1412
6180e336 1413 scm_i_pthread_mutex_unlock (&t->admin_mutex);
6180e336 1414 }
adc085f1
JG
1415 *ret = 1;
1416 break;
1417 }
1418 else if (SCM_I_IS_THREAD (m->owner) && scm_c_thread_exited_p (m->owner))
1419 {
1420 m->owner = new_owner;
1421 err = scm_cons (scm_abandoned_mutex_error_key,
1422 scm_from_locale_string ("lock obtained on abandoned "
1423 "mutex"));
1424 *ret = 1;
1425 break;
1426 }
1427 else if (scm_is_eq (m->owner, new_owner))
1428 {
1429 if (m->recursive)
1430 {
1431 m->level++;
74926120 1432 *ret = 1;
adc085f1
JG
1433 }
1434 else
6180e336 1435 {
adc085f1
JG
1436 err = scm_cons (scm_misc_error_key,
1437 scm_from_locale_string ("mutex already locked "
1438 "by thread"));
1439 *ret = 0;
1440 }
74926120 1441 break;
adc085f1 1442 }
9de87eea 1443 else
9de87eea 1444 {
74926120 1445 if (timeout != NULL)
adc085f1
JG
1446 {
1447 gettimeofday (&current_time, NULL);
1448 if (current_time.tv_sec > timeout->tv_sec ||
1449 (current_time.tv_sec == timeout->tv_sec &&
1450 current_time.tv_usec * 1000 > timeout->tv_nsec))
6180e336 1451 {
adc085f1
JG
1452 *ret = 0;
1453 break;
6180e336 1454 }
6180e336 1455 }
37a52039 1456 block_self (m->waiting, mutex, &m->lock, timeout);
9de87eea
MV
1457 scm_i_pthread_mutex_unlock (&m->lock);
1458 SCM_TICK;
1459 scm_i_scm_pthread_mutex_lock (&m->lock);
1460 }
1461 }
1462 scm_i_pthread_mutex_unlock (&m->lock);
6180e336 1463 return err;
9de87eea
MV
1464}
1465
6180e336
NJ
1466SCM scm_lock_mutex (SCM mx)
1467{
adc085f1 1468 return scm_lock_mutex_timed (mx, SCM_UNDEFINED, SCM_UNDEFINED);
6180e336
NJ
1469}
1470
adc085f1
JG
1471SCM_DEFINE (scm_lock_mutex_timed, "lock-mutex", 1, 2, 0,
1472 (SCM m, SCM timeout, SCM owner),
9bc4701c
MD
1473"Lock @var{mutex}. If the mutex is already locked, the calling thread "
1474"blocks until the mutex becomes available. The function returns when "
1475"the calling thread owns the lock on @var{mutex}. Locking a mutex that "
1476"a thread already owns will succeed right away and will not block the "
1477"thread. That is, Guile's mutexes are @emph{recursive}. ")
6180e336 1478#define FUNC_NAME s_scm_lock_mutex_timed
9bc4701c 1479{
6180e336
NJ
1480 SCM exception;
1481 int ret = 0;
1482 scm_t_timespec cwaittime, *waittime = NULL;
76da80e7 1483
6180e336
NJ
1484 SCM_VALIDATE_MUTEX (1, m);
1485
1486 if (! SCM_UNBNDP (timeout) && ! scm_is_false (timeout))
1487 {
1488 to_timespec (timeout, &cwaittime);
1489 waittime = &cwaittime;
1490 }
1491
97ec95b7
LC
1492 if (!SCM_UNBNDP (owner) && !scm_is_false (owner))
1493 SCM_VALIDATE_THREAD (3, owner);
1494
adc085f1 1495 exception = fat_mutex_lock (m, waittime, owner, &ret);
6180e336
NJ
1496 if (!scm_is_false (exception))
1497 scm_ithrow (SCM_CAR (exception), scm_list_1 (SCM_CDR (exception)), 1);
1498 return ret ? SCM_BOOL_T : SCM_BOOL_F;
9bc4701c 1499}
76da80e7 1500#undef FUNC_NAME
9bc4701c 1501
2a3db25e
MW
1502static void
1503lock_mutex_return_void (SCM mx)
1504{
1505 (void) scm_lock_mutex (mx);
1506}
1507
1508static void
1509unlock_mutex_return_void (SCM mx)
1510{
1511 (void) scm_unlock_mutex (mx);
1512}
1513
a4d106c7 1514void
661ae7ab 1515scm_dynwind_lock_mutex (SCM mutex)
a4d106c7 1516{
2a3db25e 1517 scm_dynwind_unwind_handler_with_scm (unlock_mutex_return_void, mutex,
661ae7ab 1518 SCM_F_WIND_EXPLICITLY);
2a3db25e 1519 scm_dynwind_rewind_handler_with_scm (lock_mutex_return_void, mutex,
661ae7ab 1520 SCM_F_WIND_EXPLICITLY);
a4d106c7
MV
1521}
1522
9bc4701c 1523SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
ba1b7223 1524 (SCM mutex),
9bc4701c
MD
1525"Try to lock @var{mutex}. If the mutex is already locked by someone "
1526"else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
1527#define FUNC_NAME s_scm_try_mutex
1528{
6180e336
NJ
1529 SCM exception;
1530 int ret = 0;
1531 scm_t_timespec cwaittime, *waittime = NULL;
9de87eea 1532
ba1b7223 1533 SCM_VALIDATE_MUTEX (1, mutex);
6180e336
NJ
1534
1535 to_timespec (scm_from_int(0), &cwaittime);
1536 waittime = &cwaittime;
74926120 1537
adc085f1 1538 exception = fat_mutex_lock (mutex, waittime, SCM_UNDEFINED, &ret);
6180e336
NJ
1539 if (!scm_is_false (exception))
1540 scm_ithrow (SCM_CAR (exception), scm_list_1 (SCM_CDR (exception)), 1);
1541 return ret ? SCM_BOOL_T : SCM_BOOL_F;
9de87eea
MV
1542}
1543#undef FUNC_NAME
76da80e7 1544
6180e336
NJ
1545/*** Fat condition variables */
1546
1547typedef struct {
1548 scm_i_pthread_mutex_t lock;
1549 SCM waiting; /* the threads waiting for this condition. */
1550} fat_cond;
1551
1552#define SCM_CONDVARP(x) SCM_SMOB_PREDICATE (scm_tc16_condvar, x)
1553#define SCM_CONDVAR_DATA(x) ((fat_cond *) SCM_SMOB_DATA (x))
1554
1555static int
1556fat_mutex_unlock (SCM mutex, SCM cond,
1557 const scm_t_timespec *waittime, int relock)
9de87eea 1558{
7f991c7d 1559 SCM owner;
6180e336
NJ
1560 fat_mutex *m = SCM_MUTEX_DATA (mutex);
1561 fat_cond *c = NULL;
1562 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1563 int err = 0, ret = 0;
9de87eea
MV
1564
1565 scm_i_scm_pthread_mutex_lock (&m->lock);
adc085f1 1566
7f991c7d 1567 owner = m->owner;
adc085f1 1568
d31ae2c3 1569 if (!scm_is_eq (owner, t->handle))
9bc4701c 1570 {
adc085f1 1571 if (m->level == 0)
6180e336
NJ
1572 {
1573 if (!m->unchecked_unlock)
2a1d0688
NJ
1574 {
1575 scm_i_pthread_mutex_unlock (&m->lock);
1576 scm_misc_error (NULL, "mutex not locked", SCM_EOL);
1577 }
d31ae2c3 1578 owner = t->handle;
6180e336
NJ
1579 }
1580 else if (!m->allow_external_unlock)
2a1d0688
NJ
1581 {
1582 scm_i_pthread_mutex_unlock (&m->lock);
1583 scm_misc_error (NULL, "mutex not locked by current thread", SCM_EOL);
1584 }
6180e336
NJ
1585 }
1586
1587 if (! (SCM_UNBNDP (cond)))
1588 {
6180e336
NJ
1589 c = SCM_CONDVAR_DATA (cond);
1590 while (1)
1591 {
1592 int brk = 0;
1593
6180e336
NJ
1594 if (m->level > 0)
1595 m->level--;
adc085f1 1596 if (m->level == 0)
f57fdf07
LC
1597 {
1598 /* Change the owner of MUTEX. */
1599 t->mutexes = scm_delq_x (mutex, t->mutexes);
1600 m->owner = unblock_from_queue (m->waiting);
1601 }
adc085f1 1602
6180e336 1603 t->block_asyncs++;
74926120 1604
d2a51087
NJ
1605 err = block_self (c->waiting, cond, &m->lock, waittime);
1606 scm_i_pthread_mutex_unlock (&m->lock);
6180e336
NJ
1607
1608 if (err == 0)
1609 {
1610 ret = 1;
1611 brk = 1;
1612 }
1613 else if (err == ETIMEDOUT)
1614 {
1615 ret = 0;
1616 brk = 1;
1617 }
1618 else if (err != EINTR)
74926120 1619 {
6180e336 1620 errno = err;
6180e336 1621 scm_syserror (NULL);
74926120 1622 }
6180e336
NJ
1623
1624 if (brk)
1625 {
1626 if (relock)
adc085f1 1627 scm_lock_mutex_timed (mutex, SCM_UNDEFINED, owner);
4201062d 1628 t->block_asyncs--;
6180e336
NJ
1629 break;
1630 }
74926120 1631
6180e336
NJ
1632 t->block_asyncs--;
1633 scm_async_click ();
74926120 1634
6180e336
NJ
1635 scm_remember_upto_here_2 (cond, mutex);
1636
1637 scm_i_scm_pthread_mutex_lock (&m->lock);
1638 }
9bc4701c 1639 }
9de87eea 1640 else
6180e336
NJ
1641 {
1642 if (m->level > 0)
1643 m->level--;
74926120 1644 if (m->level == 0)
f57fdf07
LC
1645 {
1646 /* Change the owner of MUTEX. */
1647 t->mutexes = scm_delq_x (mutex, t->mutexes);
1648 m->owner = unblock_from_queue (m->waiting);
1649 }
74926120 1650
6180e336
NJ
1651 scm_i_pthread_mutex_unlock (&m->lock);
1652 ret = 1;
1653 }
9de87eea 1654
6180e336 1655 return ret;
9bc4701c 1656}
9bc4701c 1657
6180e336
NJ
1658SCM scm_unlock_mutex (SCM mx)
1659{
1660 return scm_unlock_mutex_timed (mx, SCM_UNDEFINED, SCM_UNDEFINED);
9bc4701c 1661}
9bc4701c 1662
6180e336
NJ
1663SCM_DEFINE (scm_unlock_mutex_timed, "unlock-mutex", 1, 2, 0,
1664 (SCM mx, SCM cond, SCM timeout),
9bc4701c
MD
1665"Unlocks @var{mutex} if the calling thread owns the lock on "
1666"@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
1667"thread results in undefined behaviour. Once a mutex has been unlocked, "
1668"one thread blocked on @var{mutex} is awakened and grabs the mutex "
1669"lock. Every call to @code{lock-mutex} by this thread must be matched "
1670"with a call to @code{unlock-mutex}. Only the last call to "
1671"@code{unlock-mutex} will actually unlock the mutex. ")
6180e336 1672#define FUNC_NAME s_scm_unlock_mutex_timed
9bc4701c 1673{
6180e336
NJ
1674 scm_t_timespec cwaittime, *waittime = NULL;
1675
9bc4701c 1676 SCM_VALIDATE_MUTEX (1, mx);
6180e336
NJ
1677 if (! (SCM_UNBNDP (cond)))
1678 {
1679 SCM_VALIDATE_CONDVAR (2, cond);
1680
1681 if (! (SCM_UNBNDP (timeout)))
1682 {
1683 to_timespec (timeout, &cwaittime);
1684 waittime = &cwaittime;
1685 }
1686 }
1687
1688 return fat_mutex_unlock (mx, cond, waittime, 0) ? SCM_BOOL_T : SCM_BOOL_F;
9bc4701c
MD
1689}
1690#undef FUNC_NAME
1691
6180e336
NJ
1692SCM_DEFINE (scm_mutex_p, "mutex?", 1, 0, 0,
1693 (SCM obj),
1694 "Return @code{#t} if @var{obj} is a mutex.")
1695#define FUNC_NAME s_scm_mutex_p
1696{
1697 return SCM_MUTEXP (obj) ? SCM_BOOL_T : SCM_BOOL_F;
1698}
74926120 1699#undef FUNC_NAME
9de87eea
MV
1700
1701SCM_DEFINE (scm_mutex_owner, "mutex-owner", 1, 0, 0,
1702 (SCM mx),
1703 "Return the thread owning @var{mx}, or @code{#f}.")
1704#define FUNC_NAME s_scm_mutex_owner
1705{
adc085f1
JG
1706 SCM owner;
1707 fat_mutex *m = NULL;
1708
9de87eea 1709 SCM_VALIDATE_MUTEX (1, mx);
adc085f1
JG
1710 m = SCM_MUTEX_DATA (mx);
1711 scm_i_pthread_mutex_lock (&m->lock);
1712 owner = m->owner;
1713 scm_i_pthread_mutex_unlock (&m->lock);
1714
1715 return owner;
9de87eea
MV
1716}
1717#undef FUNC_NAME
1718
1719SCM_DEFINE (scm_mutex_level, "mutex-level", 1, 0, 0,
1720 (SCM mx),
adc085f1 1721 "Return the lock level of mutex @var{mx}.")
9de87eea
MV
1722#define FUNC_NAME s_scm_mutex_level
1723{
1724 SCM_VALIDATE_MUTEX (1, mx);
1725 return scm_from_int (SCM_MUTEX_DATA(mx)->level);
1726}
1727#undef FUNC_NAME
1728
adc085f1
JG
1729SCM_DEFINE (scm_mutex_locked_p, "mutex-locked?", 1, 0, 0,
1730 (SCM mx),
1731 "Returns @code{#t} if the mutex @var{mx} is locked.")
1732#define FUNC_NAME s_scm_mutex_locked_p
1733{
1734 SCM_VALIDATE_MUTEX (1, mx);
1735 return SCM_MUTEX_DATA (mx)->level > 0 ? SCM_BOOL_T : SCM_BOOL_F;
1736}
1737#undef FUNC_NAME
9de87eea 1738
9de87eea
MV
1739static int
1740fat_cond_print (SCM cv, SCM port, scm_print_state *pstate SCM_UNUSED)
1741{
1742 fat_cond *c = SCM_CONDVAR_DATA (cv);
1743 scm_puts ("#<condition-variable ", port);
1744 scm_uintprint ((scm_t_bits)c, 16, port);
1745 scm_puts (">", port);
1746 return 1;
1747}
9bc4701c 1748
d823b11b
MV
1749SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
1750 (void),
1751 "Make a new condition variable.")
1752#define FUNC_NAME s_scm_make_condition_variable
5f05c406 1753{
9de87eea
MV
1754 fat_cond *c;
1755 SCM cv;
1756
1757 c = scm_gc_malloc (sizeof (fat_cond), "condition variable");
9de87eea
MV
1758 c->waiting = SCM_EOL;
1759 SCM_NEWSMOB (cv, scm_tc16_condvar, (scm_t_bits) c);
1760 c->waiting = make_queue ();
d823b11b 1761 return cv;
5f05c406 1762}
d823b11b 1763#undef FUNC_NAME
5f05c406 1764
d823b11b
MV
1765SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
1766 (SCM cv, SCM mx, SCM t),
1767"Wait until @var{cond-var} has been signalled. While waiting, "
1768"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
1769"is locked again when this function returns. When @var{time} is given, "
1770"it specifies a point in time where the waiting should be aborted. It "
1771"can be either a integer as returned by @code{current-time} or a pair "
1772"as returned by @code{gettimeofday}. When the waiting is aborted the "
1773"mutex is locked and @code{#f} is returned. When the condition "
1774"variable is in fact signalled, the mutex is also locked and @code{#t} "
1775"is returned. ")
1776#define FUNC_NAME s_scm_timed_wait_condition_variable
5f05c406 1777{
9de87eea 1778 scm_t_timespec waittime, *waitptr = NULL;
d823b11b
MV
1779
1780 SCM_VALIDATE_CONDVAR (1, cv);
1781 SCM_VALIDATE_MUTEX (2, mx);
74926120 1782
d823b11b
MV
1783 if (!SCM_UNBNDP (t))
1784 {
6180e336 1785 to_timespec (t, &waittime);
9de87eea 1786 waitptr = &waittime;
d823b11b
MV
1787 }
1788
2a1d0688 1789 return fat_mutex_unlock (mx, cv, waitptr, 1) ? SCM_BOOL_T : SCM_BOOL_F;
5f05c406 1790}
d823b11b 1791#undef FUNC_NAME
5f05c406 1792
9de87eea
MV
1793static void
1794fat_cond_signal (fat_cond *c)
1795{
9de87eea 1796 unblock_from_queue (c->waiting);
9de87eea
MV
1797}
1798
d823b11b
MV
1799SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
1800 (SCM cv),
1801 "Wake up one thread that is waiting for @var{cv}")
1802#define FUNC_NAME s_scm_signal_condition_variable
5f05c406 1803{
d823b11b 1804 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1805 fat_cond_signal (SCM_CONDVAR_DATA (cv));
d823b11b 1806 return SCM_BOOL_T;
5f05c406 1807}
d823b11b 1808#undef FUNC_NAME
5f05c406 1809
9de87eea
MV
1810static void
1811fat_cond_broadcast (fat_cond *c)
1812{
9de87eea
MV
1813 while (scm_is_true (unblock_from_queue (c->waiting)))
1814 ;
9de87eea
MV
1815}
1816
d823b11b
MV
1817SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
1818 (SCM cv),
1819 "Wake up all threads that are waiting for @var{cv}. ")
1820#define FUNC_NAME s_scm_broadcast_condition_variable
5f05c406 1821{
d823b11b 1822 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1823 fat_cond_broadcast (SCM_CONDVAR_DATA (cv));
d823b11b 1824 return SCM_BOOL_T;
5f05c406 1825}
d823b11b 1826#undef FUNC_NAME
5f05c406 1827
6180e336
NJ
1828SCM_DEFINE (scm_condition_variable_p, "condition-variable?", 1, 0, 0,
1829 (SCM obj),
1830 "Return @code{#t} if @var{obj} is a condition variable.")
1831#define FUNC_NAME s_scm_condition_variable_p
1832{
1833 return SCM_CONDVARP(obj) ? SCM_BOOL_T : SCM_BOOL_F;
1834}
1835#undef FUNC_NAME
1836
6087fad9 1837
8c2b3143 1838\f
d823b11b
MV
1839/*** Select */
1840
8c2b3143
LC
1841struct select_args
1842{
1843 int nfds;
1844 SELECT_TYPE *read_fds;
1845 SELECT_TYPE *write_fds;
1846 SELECT_TYPE *except_fds;
1847 struct timeval *timeout;
1848
1849 int result;
1850 int errno_value;
1851};
1852
1853static void *
1854do_std_select (void *args)
1855{
1856 struct select_args *select_args;
1857
1858 select_args = (struct select_args *) args;
1859
1860 select_args->result =
1861 select (select_args->nfds,
1862 select_args->read_fds, select_args->write_fds,
1863 select_args->except_fds, select_args->timeout);
1864 select_args->errno_value = errno;
1865
1866 return NULL;
1867}
1868
911782b7 1869int
9de87eea
MV
1870scm_std_select (int nfds,
1871 SELECT_TYPE *readfds,
1872 SELECT_TYPE *writefds,
1873 SELECT_TYPE *exceptfds,
1874 struct timeval *timeout)
1875{
1876 fd_set my_readfds;
1877 int res, eno, wakeup_fd;
1878 scm_i_thread *t = SCM_I_CURRENT_THREAD;
8c2b3143 1879 struct select_args args;
9de87eea
MV
1880
1881 if (readfds == NULL)
1882 {
1883 FD_ZERO (&my_readfds);
1884 readfds = &my_readfds;
1885 }
1886
1887 while (scm_i_setup_sleep (t, SCM_BOOL_F, NULL, t->sleep_pipe[1]))
1888 SCM_TICK;
1889
1890 wakeup_fd = t->sleep_pipe[0];
9de87eea
MV
1891 FD_SET (wakeup_fd, readfds);
1892 if (wakeup_fd >= nfds)
1893 nfds = wakeup_fd+1;
9de87eea 1894
8c2b3143
LC
1895 args.nfds = nfds;
1896 args.read_fds = readfds;
1897 args.write_fds = writefds;
1898 args.except_fds = exceptfds;
1899 args.timeout = timeout;
1900
1901 /* Explicitly cooperate with the GC. */
1902 scm_without_guile (do_std_select, &args);
1903
1904 res = args.result;
1905 eno = args.errno_value;
1906
1907 t->sleep_fd = -1;
9de87eea
MV
1908 scm_i_reset_sleep (t);
1909
1910 if (res > 0 && FD_ISSET (wakeup_fd, readfds))
1911 {
1912 char dummy;
634aa8de
LC
1913 full_read (wakeup_fd, &dummy, 1);
1914
9de87eea
MV
1915 FD_CLR (wakeup_fd, readfds);
1916 res -= 1;
1917 if (res == 0)
1918 {
1919 eno = EINTR;
1920 res = -1;
1921 }
1922 }
d823b11b
MV
1923 errno = eno;
1924 return res;
5f05c406
MV
1925}
1926
9de87eea 1927/* Convenience API for blocking while in guile mode. */
76da80e7 1928
9de87eea 1929#if SCM_USE_PTHREAD_THREADS
92e64b87 1930
2956b071
LC
1931/* It seems reasonable to not run procedures related to mutex and condition
1932 variables within `GC_do_blocking ()' since, (i) the GC can operate even
1933 without it, and (ii) the only potential gain would be GC latency. See
1934 http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2245/focus=2251
1935 for a discussion of the pros and cons. */
1936
9bc4701c 1937int
9de87eea 1938scm_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
9bc4701c 1939{
9de87eea 1940 int res = scm_i_pthread_mutex_lock (mutex);
9bc4701c
MD
1941 return res;
1942}
1943
9de87eea 1944static void
2b829bbb 1945do_unlock (void *data)
28d52ebb 1946{
9de87eea 1947 scm_i_pthread_mutex_unlock ((scm_i_pthread_mutex_t *)data);
28d52ebb
MD
1948}
1949
1950void
661ae7ab 1951scm_dynwind_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
28d52ebb 1952{
9de87eea 1953 scm_i_scm_pthread_mutex_lock (mutex);
2b829bbb 1954 scm_dynwind_unwind_handler (do_unlock, mutex, SCM_F_WIND_EXPLICITLY);
28d52ebb
MD
1955}
1956
9bc4701c 1957int
9de87eea 1958scm_pthread_cond_wait (scm_i_pthread_cond_t *cond, scm_i_pthread_mutex_t *mutex)
9bc4701c 1959{
4cf72f0b
LC
1960 int res;
1961 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1962
1963 t->held_mutex = mutex;
1964 res = scm_i_pthread_cond_wait (cond, mutex);
1965 t->held_mutex = NULL;
1966
9bc4701c
MD
1967 return res;
1968}
9bc4701c 1969
76da80e7 1970int
9de87eea
MV
1971scm_pthread_cond_timedwait (scm_i_pthread_cond_t *cond,
1972 scm_i_pthread_mutex_t *mutex,
1973 const scm_t_timespec *wt)
76da80e7 1974{
4cf72f0b
LC
1975 int res;
1976 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1977
1978 t->held_mutex = mutex;
1979 res = scm_i_pthread_cond_timedwait (cond, mutex, wt);
1980 t->held_mutex = NULL;
1981
9de87eea 1982 return res;
76da80e7
MV
1983}
1984
9de87eea 1985#endif
76da80e7 1986
d823b11b 1987unsigned long
9de87eea 1988scm_std_usleep (unsigned long usecs)
5f05c406 1989{
d823b11b
MV
1990 struct timeval tv;
1991 tv.tv_usec = usecs % 1000000;
1992 tv.tv_sec = usecs / 1000000;
9de87eea
MV
1993 scm_std_select (0, NULL, NULL, NULL, &tv);
1994 return tv.tv_sec * 1000000 + tv.tv_usec;
5f05c406
MV
1995}
1996
9de87eea
MV
1997unsigned int
1998scm_std_sleep (unsigned int secs)
6c214b62 1999{
d823b11b
MV
2000 struct timeval tv;
2001 tv.tv_usec = 0;
2002 tv.tv_sec = secs;
9de87eea 2003 scm_std_select (0, NULL, NULL, NULL, &tv);
d823b11b 2004 return tv.tv_sec;
6c214b62
MD
2005}
2006
d823b11b
MV
2007/*** Misc */
2008
2009SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
2010 (void),
2011 "Return the thread that called this function.")
2012#define FUNC_NAME s_scm_current_thread
2013{
9de87eea 2014 return SCM_I_CURRENT_THREAD->handle;
d823b11b
MV
2015}
2016#undef FUNC_NAME
2017
9de87eea
MV
2018static SCM
2019scm_c_make_list (size_t n, SCM fill)
2020{
2021 SCM res = SCM_EOL;
2022 while (n-- > 0)
2023 res = scm_cons (fill, res);
2024 return res;
2025}
2026
d823b11b
MV
2027SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
2028 (void),
2029 "Return a list of all threads.")
9bc4701c 2030#define FUNC_NAME s_scm_all_threads
d823b11b 2031{
9de87eea
MV
2032 /* We can not allocate while holding the thread_admin_mutex because
2033 of the way GC is done.
2034 */
2035 int n = thread_count;
2036 scm_i_thread *t;
2037 SCM list = scm_c_make_list (n, SCM_UNSPECIFIED), *l;
d823b11b 2038
9de87eea
MV
2039 scm_i_pthread_mutex_lock (&thread_admin_mutex);
2040 l = &list;
2041 for (t = all_threads; t && n > 0; t = t->next_thread)
2042 {
2e77f720
LC
2043 if (t != scm_i_signal_delivery_thread)
2044 {
2045 SCM_SETCAR (*l, t->handle);
2046 l = SCM_CDRLOC (*l);
2047 }
9de87eea
MV
2048 n--;
2049 }
2050 *l = SCM_EOL;
2051 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
2052 return list;
d823b11b 2053}
9de87eea 2054#undef FUNC_NAME
d823b11b
MV
2055
2056SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
2057 (SCM thread),
2058 "Return @code{#t} iff @var{thread} has exited.\n")
2059#define FUNC_NAME s_scm_thread_exited_p
2060{
7888309b 2061 return scm_from_bool (scm_c_thread_exited_p (thread));
d823b11b
MV
2062}
2063#undef FUNC_NAME
2064
911782b7 2065int
d823b11b
MV
2066scm_c_thread_exited_p (SCM thread)
2067#define FUNC_NAME s_scm_thread_exited_p
5f05c406 2068{
9de87eea 2069 scm_i_thread *t;
d823b11b 2070 SCM_VALIDATE_THREAD (1, thread);
9de87eea 2071 t = SCM_I_THREAD_DATA (thread);
d823b11b 2072 return t->exited;
5f05c406 2073}
d823b11b 2074#undef FUNC_NAME
5f05c406 2075
d20912e6
LC
2076SCM_DEFINE (scm_total_processor_count, "total-processor-count", 0, 0, 0,
2077 (void),
2078 "Return the total number of processors of the machine, which\n"
2079 "is guaranteed to be at least 1. A ``processor'' here is a\n"
2080 "thread execution unit, which can be either:\n\n"
2081 "@itemize\n"
2082 "@item an execution core in a (possibly multi-core) chip, in a\n"
2083 " (possibly multi- chip) module, in a single computer, or\n"
2084 "@item a thread execution unit inside a core in the case of\n"
2085 " @dfn{hyper-threaded} CPUs.\n"
2086 "@end itemize\n\n"
2087 "Which of the two definitions is used, is unspecified.\n")
2088#define FUNC_NAME s_scm_total_processor_count
2089{
2090 return scm_from_ulong (num_processors (NPROC_ALL));
2091}
2092#undef FUNC_NAME
2093
2094SCM_DEFINE (scm_current_processor_count, "current-processor-count", 0, 0, 0,
2095 (void),
2096 "Like @code{total-processor-count}, but return the number of\n"
2097 "processors available to the current process. See\n"
2098 "@code{setaffinity} and @code{getaffinity} for more\n"
2099 "information.\n")
2100#define FUNC_NAME s_scm_current_processor_count
2101{
2102 return scm_from_ulong (num_processors (NPROC_CURRENT));
2103}
2104#undef FUNC_NAME
2105
2106
2107\f
2108
9de87eea 2109static scm_i_pthread_cond_t wake_up_cond;
9bc4701c
MD
2110static int threads_initialized_p = 0;
2111
9bc4701c 2112
a4d106c7
MV
2113/* This mutex is used by SCM_CRITICAL_SECTION_START/END.
2114 */
d1138028 2115scm_i_pthread_mutex_t scm_i_critical_section_mutex;
a4d106c7 2116
661ae7ab 2117static SCM dynwind_critical_section_mutex;
a54a94b3 2118
9bc4701c 2119void
661ae7ab 2120scm_dynwind_critical_section (SCM mutex)
76da80e7 2121{
a4d106c7 2122 if (scm_is_false (mutex))
661ae7ab
MV
2123 mutex = dynwind_critical_section_mutex;
2124 scm_dynwind_lock_mutex (mutex);
2125 scm_dynwind_block_asyncs ();
9de87eea
MV
2126}
2127
2128/*** Initialization */
2129
9de87eea
MV
2130scm_i_pthread_mutex_t scm_i_misc_mutex;
2131
d1138028
MV
2132#if SCM_USE_PTHREAD_THREADS
2133pthread_mutexattr_t scm_i_pthread_mutexattr_recursive[1];
2134#endif
2135
9de87eea 2136void
12c1d861 2137scm_threads_prehistory (void *base)
9de87eea 2138{
d1138028
MV
2139#if SCM_USE_PTHREAD_THREADS
2140 pthread_mutexattr_init (scm_i_pthread_mutexattr_recursive);
2141 pthread_mutexattr_settype (scm_i_pthread_mutexattr_recursive,
2142 PTHREAD_MUTEX_RECURSIVE);
2143#endif
2144
2145 scm_i_pthread_mutex_init (&scm_i_critical_section_mutex,
2146 scm_i_pthread_mutexattr_recursive);
9de87eea
MV
2147 scm_i_pthread_mutex_init (&scm_i_misc_mutex, NULL);
2148 scm_i_pthread_cond_init (&wake_up_cond, NULL);
74926120 2149
12c1d861 2150 guilify_self_1 ((struct GC_stack_base *) base);
9bc4701c
MD
2151}
2152
d823b11b
MV
2153scm_t_bits scm_tc16_thread;
2154scm_t_bits scm_tc16_mutex;
2155scm_t_bits scm_tc16_condvar;
7bfd3b9e 2156
7bfd3b9e 2157void
9de87eea 2158scm_init_threads ()
7bfd3b9e 2159{
9de87eea 2160 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_i_thread));
d823b11b 2161 scm_set_smob_print (scm_tc16_thread, thread_print);
d823b11b 2162
9de87eea 2163 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (fat_mutex));
9de87eea
MV
2164 scm_set_smob_print (scm_tc16_mutex, fat_mutex_print);
2165 scm_set_smob_free (scm_tc16_mutex, fat_mutex_free);
9bc4701c 2166
9de87eea
MV
2167 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
2168 sizeof (fat_cond));
9de87eea 2169 scm_set_smob_print (scm_tc16_condvar, fat_cond_print);
d823b11b 2170
9de87eea
MV
2171 scm_i_default_dynamic_state = SCM_BOOL_F;
2172 guilify_self_2 (SCM_BOOL_F);
9bc4701c 2173 threads_initialized_p = 1;
a4d106c7 2174
f39448c5 2175 dynwind_critical_section_mutex = scm_make_recursive_mutex ();
7bfd3b9e 2176}
89e00824 2177
5f05c406 2178void
9de87eea 2179scm_init_threads_default_dynamic_state ()
5f05c406 2180{
9de87eea 2181 SCM state = scm_make_dynamic_state (scm_current_dynamic_state ());
f39448c5 2182 scm_i_default_dynamic_state = state;
5f05c406
MV
2183}
2184
d823b11b 2185void
9de87eea 2186scm_init_thread_procs ()
d823b11b 2187{
9de87eea 2188#include "libguile/threads.x"
d823b11b
MV
2189}
2190
3c13664e
LC
2191\f
2192/* IA64-specific things. */
2193
2194#ifdef __ia64__
2195# ifdef __hpux
2196# include <sys/param.h>
2197# include <sys/pstat.h>
2198void *
2199scm_ia64_register_backing_store_base (void)
2200{
2201 struct pst_vm_status vm_status;
2202 int i = 0;
2203 while (pstat_getprocvm (&vm_status, sizeof (vm_status), 0, i++) == 1)
2204 if (vm_status.pst_type == PS_RSESTACK)
2205 return (void *) vm_status.pst_vaddr;
2206 abort ();
2207}
2208void *
2209scm_ia64_ar_bsp (const void *ctx)
2210{
2211 uint64_t bsp;
2212 __uc_get_ar_bsp (ctx, &bsp);
2213 return (void *) bsp;
2214}
2215# endif /* hpux */
2216# ifdef linux
2217# include <ucontext.h>
2218void *
2219scm_ia64_register_backing_store_base (void)
2220{
2221 extern void *__libc_ia64_register_backing_store_base;
2222 return __libc_ia64_register_backing_store_base;
2223}
2224void *
2225scm_ia64_ar_bsp (const void *opaque)
2226{
2227 const ucontext_t *ctx = opaque;
2228 return (void *) ctx->uc_mcontext.sc_ar_bsp;
2229}
2230# endif /* linux */
ba20d262
AW
2231# ifdef __FreeBSD__
2232# include <ucontext.h>
2233void *
2234scm_ia64_register_backing_store_base (void)
2235{
2236 return (void *)0x8000000000000000;
2237}
2238void *
2239scm_ia64_ar_bsp (const void *opaque)
2240{
2241 const ucontext_t *ctx = opaque;
2242 return (void *)(ctx->uc_mcontext.mc_special.bspstore
2243 + ctx->uc_mcontext.mc_special.ndirty);
2244}
2245# endif /* __FreeBSD__ */
3c13664e
LC
2246#endif /* __ia64__ */
2247
2248
89e00824
ML
2249/*
2250 Local Variables:
2251 c-file-style: "gnu"
2252 End:
2253*/