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