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