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