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