Remove deprecated guardian code.
[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
23d72566
KR
664#elif HAVE_PTHREAD_GET_STACKADDR_NP
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{
6180e336
NJ
1376 fat_mutex *m = SCM_MUTEX_DATA (mutex);
1377 fat_cond *c = NULL;
1378 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1379 int err = 0, ret = 0;
9de87eea
MV
1380
1381 scm_i_scm_pthread_mutex_lock (&m->lock);
adc085f1
JG
1382
1383 SCM owner = m->owner;
1384
1385 if (!scm_is_eq (owner, scm_current_thread ()))
9bc4701c 1386 {
adc085f1 1387 if (m->level == 0)
6180e336
NJ
1388 {
1389 if (!m->unchecked_unlock)
2a1d0688
NJ
1390 {
1391 scm_i_pthread_mutex_unlock (&m->lock);
1392 scm_misc_error (NULL, "mutex not locked", SCM_EOL);
1393 }
adc085f1 1394 owner = scm_current_thread ();
6180e336
NJ
1395 }
1396 else if (!m->allow_external_unlock)
2a1d0688
NJ
1397 {
1398 scm_i_pthread_mutex_unlock (&m->lock);
1399 scm_misc_error (NULL, "mutex not locked by current thread", SCM_EOL);
1400 }
6180e336
NJ
1401 }
1402
1403 if (! (SCM_UNBNDP (cond)))
1404 {
6180e336
NJ
1405 c = SCM_CONDVAR_DATA (cond);
1406 while (1)
1407 {
1408 int brk = 0;
1409
6180e336
NJ
1410 if (m->level > 0)
1411 m->level--;
adc085f1 1412 if (m->level == 0)
6180e336 1413 m->owner = unblock_from_queue (m->waiting);
adc085f1 1414
6180e336 1415 t->block_asyncs++;
74926120 1416
d2a51087
NJ
1417 err = block_self (c->waiting, cond, &m->lock, waittime);
1418 scm_i_pthread_mutex_unlock (&m->lock);
6180e336
NJ
1419
1420 if (err == 0)
1421 {
1422 ret = 1;
1423 brk = 1;
1424 }
1425 else if (err == ETIMEDOUT)
1426 {
1427 ret = 0;
1428 brk = 1;
1429 }
1430 else if (err != EINTR)
74926120 1431 {
6180e336 1432 errno = err;
6180e336 1433 scm_syserror (NULL);
74926120 1434 }
6180e336
NJ
1435
1436 if (brk)
1437 {
1438 if (relock)
adc085f1 1439 scm_lock_mutex_timed (mutex, SCM_UNDEFINED, owner);
4201062d 1440 t->block_asyncs--;
6180e336
NJ
1441 break;
1442 }
74926120 1443
6180e336
NJ
1444 t->block_asyncs--;
1445 scm_async_click ();
74926120 1446
6180e336
NJ
1447 scm_remember_upto_here_2 (cond, mutex);
1448
1449 scm_i_scm_pthread_mutex_lock (&m->lock);
1450 }
9bc4701c 1451 }
9de87eea 1452 else
6180e336
NJ
1453 {
1454 if (m->level > 0)
1455 m->level--;
74926120 1456 if (m->level == 0)
6180e336 1457 m->owner = unblock_from_queue (m->waiting);
74926120 1458
6180e336
NJ
1459 scm_i_pthread_mutex_unlock (&m->lock);
1460 ret = 1;
1461 }
9de87eea 1462
6180e336 1463 return ret;
9bc4701c 1464}
9bc4701c 1465
6180e336
NJ
1466SCM scm_unlock_mutex (SCM mx)
1467{
1468 return scm_unlock_mutex_timed (mx, SCM_UNDEFINED, SCM_UNDEFINED);
9bc4701c 1469}
9bc4701c 1470
6180e336
NJ
1471SCM_DEFINE (scm_unlock_mutex_timed, "unlock-mutex", 1, 2, 0,
1472 (SCM mx, SCM cond, SCM timeout),
9bc4701c
MD
1473"Unlocks @var{mutex} if the calling thread owns the lock on "
1474"@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
1475"thread results in undefined behaviour. Once a mutex has been unlocked, "
1476"one thread blocked on @var{mutex} is awakened and grabs the mutex "
1477"lock. Every call to @code{lock-mutex} by this thread must be matched "
1478"with a call to @code{unlock-mutex}. Only the last call to "
1479"@code{unlock-mutex} will actually unlock the mutex. ")
6180e336 1480#define FUNC_NAME s_scm_unlock_mutex_timed
9bc4701c 1481{
6180e336
NJ
1482 scm_t_timespec cwaittime, *waittime = NULL;
1483
9bc4701c 1484 SCM_VALIDATE_MUTEX (1, mx);
6180e336
NJ
1485 if (! (SCM_UNBNDP (cond)))
1486 {
1487 SCM_VALIDATE_CONDVAR (2, cond);
1488
1489 if (! (SCM_UNBNDP (timeout)))
1490 {
1491 to_timespec (timeout, &cwaittime);
1492 waittime = &cwaittime;
1493 }
1494 }
1495
1496 return fat_mutex_unlock (mx, cond, waittime, 0) ? SCM_BOOL_T : SCM_BOOL_F;
9bc4701c
MD
1497}
1498#undef FUNC_NAME
1499
6180e336
NJ
1500SCM_DEFINE (scm_mutex_p, "mutex?", 1, 0, 0,
1501 (SCM obj),
1502 "Return @code{#t} if @var{obj} is a mutex.")
1503#define FUNC_NAME s_scm_mutex_p
1504{
1505 return SCM_MUTEXP (obj) ? SCM_BOOL_T : SCM_BOOL_F;
1506}
74926120 1507#undef FUNC_NAME
9de87eea
MV
1508
1509SCM_DEFINE (scm_mutex_owner, "mutex-owner", 1, 0, 0,
1510 (SCM mx),
1511 "Return the thread owning @var{mx}, or @code{#f}.")
1512#define FUNC_NAME s_scm_mutex_owner
1513{
adc085f1
JG
1514 SCM owner;
1515 fat_mutex *m = NULL;
1516
9de87eea 1517 SCM_VALIDATE_MUTEX (1, mx);
adc085f1
JG
1518 m = SCM_MUTEX_DATA (mx);
1519 scm_i_pthread_mutex_lock (&m->lock);
1520 owner = m->owner;
1521 scm_i_pthread_mutex_unlock (&m->lock);
1522
1523 return owner;
9de87eea
MV
1524}
1525#undef FUNC_NAME
1526
1527SCM_DEFINE (scm_mutex_level, "mutex-level", 1, 0, 0,
1528 (SCM mx),
adc085f1 1529 "Return the lock level of mutex @var{mx}.")
9de87eea
MV
1530#define FUNC_NAME s_scm_mutex_level
1531{
1532 SCM_VALIDATE_MUTEX (1, mx);
1533 return scm_from_int (SCM_MUTEX_DATA(mx)->level);
1534}
1535#undef FUNC_NAME
1536
adc085f1
JG
1537SCM_DEFINE (scm_mutex_locked_p, "mutex-locked?", 1, 0, 0,
1538 (SCM mx),
1539 "Returns @code{#t} if the mutex @var{mx} is locked.")
1540#define FUNC_NAME s_scm_mutex_locked_p
1541{
1542 SCM_VALIDATE_MUTEX (1, mx);
1543 return SCM_MUTEX_DATA (mx)->level > 0 ? SCM_BOOL_T : SCM_BOOL_F;
1544}
1545#undef FUNC_NAME
9de87eea 1546
9de87eea
MV
1547static int
1548fat_cond_print (SCM cv, SCM port, scm_print_state *pstate SCM_UNUSED)
1549{
1550 fat_cond *c = SCM_CONDVAR_DATA (cv);
1551 scm_puts ("#<condition-variable ", port);
1552 scm_uintprint ((scm_t_bits)c, 16, port);
1553 scm_puts (">", port);
1554 return 1;
1555}
9bc4701c 1556
d823b11b
MV
1557SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
1558 (void),
1559 "Make a new condition variable.")
1560#define FUNC_NAME s_scm_make_condition_variable
5f05c406 1561{
9de87eea
MV
1562 fat_cond *c;
1563 SCM cv;
1564
1565 c = scm_gc_malloc (sizeof (fat_cond), "condition variable");
9de87eea
MV
1566 c->waiting = SCM_EOL;
1567 SCM_NEWSMOB (cv, scm_tc16_condvar, (scm_t_bits) c);
1568 c->waiting = make_queue ();
d823b11b 1569 return cv;
5f05c406 1570}
d823b11b 1571#undef FUNC_NAME
5f05c406 1572
d823b11b
MV
1573SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
1574 (SCM cv, SCM mx, SCM t),
1575"Wait until @var{cond-var} has been signalled. While waiting, "
1576"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
1577"is locked again when this function returns. When @var{time} is given, "
1578"it specifies a point in time where the waiting should be aborted. It "
1579"can be either a integer as returned by @code{current-time} or a pair "
1580"as returned by @code{gettimeofday}. When the waiting is aborted the "
1581"mutex is locked and @code{#f} is returned. When the condition "
1582"variable is in fact signalled, the mutex is also locked and @code{#t} "
1583"is returned. ")
1584#define FUNC_NAME s_scm_timed_wait_condition_variable
5f05c406 1585{
9de87eea 1586 scm_t_timespec waittime, *waitptr = NULL;
d823b11b
MV
1587
1588 SCM_VALIDATE_CONDVAR (1, cv);
1589 SCM_VALIDATE_MUTEX (2, mx);
74926120 1590
d823b11b
MV
1591 if (!SCM_UNBNDP (t))
1592 {
6180e336 1593 to_timespec (t, &waittime);
9de87eea 1594 waitptr = &waittime;
d823b11b
MV
1595 }
1596
2a1d0688 1597 return fat_mutex_unlock (mx, cv, waitptr, 1) ? SCM_BOOL_T : SCM_BOOL_F;
5f05c406 1598}
d823b11b 1599#undef FUNC_NAME
5f05c406 1600
9de87eea
MV
1601static void
1602fat_cond_signal (fat_cond *c)
1603{
9de87eea 1604 unblock_from_queue (c->waiting);
9de87eea
MV
1605}
1606
d823b11b
MV
1607SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
1608 (SCM cv),
1609 "Wake up one thread that is waiting for @var{cv}")
1610#define FUNC_NAME s_scm_signal_condition_variable
5f05c406 1611{
d823b11b 1612 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1613 fat_cond_signal (SCM_CONDVAR_DATA (cv));
d823b11b 1614 return SCM_BOOL_T;
5f05c406 1615}
d823b11b 1616#undef FUNC_NAME
5f05c406 1617
9de87eea
MV
1618static void
1619fat_cond_broadcast (fat_cond *c)
1620{
9de87eea
MV
1621 while (scm_is_true (unblock_from_queue (c->waiting)))
1622 ;
9de87eea
MV
1623}
1624
d823b11b
MV
1625SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
1626 (SCM cv),
1627 "Wake up all threads that are waiting for @var{cv}. ")
1628#define FUNC_NAME s_scm_broadcast_condition_variable
5f05c406 1629{
d823b11b 1630 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1631 fat_cond_broadcast (SCM_CONDVAR_DATA (cv));
d823b11b 1632 return SCM_BOOL_T;
5f05c406 1633}
d823b11b 1634#undef FUNC_NAME
5f05c406 1635
6180e336
NJ
1636SCM_DEFINE (scm_condition_variable_p, "condition-variable?", 1, 0, 0,
1637 (SCM obj),
1638 "Return @code{#t} if @var{obj} is a condition variable.")
1639#define FUNC_NAME s_scm_condition_variable_p
1640{
1641 return SCM_CONDVARP(obj) ? SCM_BOOL_T : SCM_BOOL_F;
1642}
1643#undef FUNC_NAME
1644
6087fad9 1645
8c2b3143 1646\f
d823b11b
MV
1647/*** Select */
1648
8c2b3143
LC
1649struct select_args
1650{
1651 int nfds;
1652 SELECT_TYPE *read_fds;
1653 SELECT_TYPE *write_fds;
1654 SELECT_TYPE *except_fds;
1655 struct timeval *timeout;
1656
1657 int result;
1658 int errno_value;
1659};
1660
1661static void *
1662do_std_select (void *args)
1663{
1664 struct select_args *select_args;
1665
1666 select_args = (struct select_args *) args;
1667
1668 select_args->result =
1669 select (select_args->nfds,
1670 select_args->read_fds, select_args->write_fds,
1671 select_args->except_fds, select_args->timeout);
1672 select_args->errno_value = errno;
1673
1674 return NULL;
1675}
1676
911782b7 1677int
9de87eea
MV
1678scm_std_select (int nfds,
1679 SELECT_TYPE *readfds,
1680 SELECT_TYPE *writefds,
1681 SELECT_TYPE *exceptfds,
1682 struct timeval *timeout)
1683{
1684 fd_set my_readfds;
1685 int res, eno, wakeup_fd;
1686 scm_i_thread *t = SCM_I_CURRENT_THREAD;
8c2b3143 1687 struct select_args args;
9de87eea
MV
1688
1689 if (readfds == NULL)
1690 {
1691 FD_ZERO (&my_readfds);
1692 readfds = &my_readfds;
1693 }
1694
1695 while (scm_i_setup_sleep (t, SCM_BOOL_F, NULL, t->sleep_pipe[1]))
1696 SCM_TICK;
1697
1698 wakeup_fd = t->sleep_pipe[0];
9de87eea
MV
1699 FD_SET (wakeup_fd, readfds);
1700 if (wakeup_fd >= nfds)
1701 nfds = wakeup_fd+1;
9de87eea 1702
8c2b3143
LC
1703 args.nfds = nfds;
1704 args.read_fds = readfds;
1705 args.write_fds = writefds;
1706 args.except_fds = exceptfds;
1707 args.timeout = timeout;
1708
1709 /* Explicitly cooperate with the GC. */
1710 scm_without_guile (do_std_select, &args);
1711
1712 res = args.result;
1713 eno = args.errno_value;
1714
1715 t->sleep_fd = -1;
9de87eea
MV
1716 scm_i_reset_sleep (t);
1717
1718 if (res > 0 && FD_ISSET (wakeup_fd, readfds))
1719 {
1720 char dummy;
634aa8de
LC
1721 full_read (wakeup_fd, &dummy, 1);
1722
9de87eea
MV
1723 FD_CLR (wakeup_fd, readfds);
1724 res -= 1;
1725 if (res == 0)
1726 {
1727 eno = EINTR;
1728 res = -1;
1729 }
1730 }
d823b11b
MV
1731 errno = eno;
1732 return res;
5f05c406
MV
1733}
1734
9de87eea 1735/* Convenience API for blocking while in guile mode. */
76da80e7 1736
9de87eea 1737#if SCM_USE_PTHREAD_THREADS
92e64b87 1738
2956b071
LC
1739/* It seems reasonable to not run procedures related to mutex and condition
1740 variables within `GC_do_blocking ()' since, (i) the GC can operate even
1741 without it, and (ii) the only potential gain would be GC latency. See
1742 http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2245/focus=2251
1743 for a discussion of the pros and cons. */
1744
9bc4701c 1745int
9de87eea 1746scm_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
9bc4701c 1747{
9de87eea 1748 int res = scm_i_pthread_mutex_lock (mutex);
9bc4701c
MD
1749 return res;
1750}
1751
9de87eea 1752static void
2b829bbb 1753do_unlock (void *data)
28d52ebb 1754{
9de87eea 1755 scm_i_pthread_mutex_unlock ((scm_i_pthread_mutex_t *)data);
28d52ebb
MD
1756}
1757
1758void
661ae7ab 1759scm_dynwind_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
28d52ebb 1760{
9de87eea 1761 scm_i_scm_pthread_mutex_lock (mutex);
2b829bbb 1762 scm_dynwind_unwind_handler (do_unlock, mutex, SCM_F_WIND_EXPLICITLY);
28d52ebb
MD
1763}
1764
9bc4701c 1765int
9de87eea 1766scm_pthread_cond_wait (scm_i_pthread_cond_t *cond, scm_i_pthread_mutex_t *mutex)
9bc4701c 1767{
4cf72f0b
LC
1768 int res;
1769 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1770
1771 t->held_mutex = mutex;
1772 res = scm_i_pthread_cond_wait (cond, mutex);
1773 t->held_mutex = NULL;
1774
9bc4701c
MD
1775 return res;
1776}
9bc4701c 1777
76da80e7 1778int
9de87eea
MV
1779scm_pthread_cond_timedwait (scm_i_pthread_cond_t *cond,
1780 scm_i_pthread_mutex_t *mutex,
1781 const scm_t_timespec *wt)
76da80e7 1782{
4cf72f0b
LC
1783 int res;
1784 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1785
1786 t->held_mutex = mutex;
1787 res = scm_i_pthread_cond_timedwait (cond, mutex, wt);
1788 t->held_mutex = NULL;
1789
9de87eea 1790 return res;
76da80e7
MV
1791}
1792
9de87eea 1793#endif
76da80e7 1794
d823b11b 1795unsigned long
9de87eea 1796scm_std_usleep (unsigned long usecs)
5f05c406 1797{
d823b11b
MV
1798 struct timeval tv;
1799 tv.tv_usec = usecs % 1000000;
1800 tv.tv_sec = usecs / 1000000;
9de87eea
MV
1801 scm_std_select (0, NULL, NULL, NULL, &tv);
1802 return tv.tv_sec * 1000000 + tv.tv_usec;
5f05c406
MV
1803}
1804
9de87eea
MV
1805unsigned int
1806scm_std_sleep (unsigned int secs)
6c214b62 1807{
d823b11b
MV
1808 struct timeval tv;
1809 tv.tv_usec = 0;
1810 tv.tv_sec = secs;
9de87eea 1811 scm_std_select (0, NULL, NULL, NULL, &tv);
d823b11b 1812 return tv.tv_sec;
6c214b62
MD
1813}
1814
d823b11b
MV
1815/*** Misc */
1816
1817SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1818 (void),
1819 "Return the thread that called this function.")
1820#define FUNC_NAME s_scm_current_thread
1821{
9de87eea 1822 return SCM_I_CURRENT_THREAD->handle;
d823b11b
MV
1823}
1824#undef FUNC_NAME
1825
9de87eea
MV
1826static SCM
1827scm_c_make_list (size_t n, SCM fill)
1828{
1829 SCM res = SCM_EOL;
1830 while (n-- > 0)
1831 res = scm_cons (fill, res);
1832 return res;
1833}
1834
d823b11b
MV
1835SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1836 (void),
1837 "Return a list of all threads.")
9bc4701c 1838#define FUNC_NAME s_scm_all_threads
d823b11b 1839{
9de87eea
MV
1840 /* We can not allocate while holding the thread_admin_mutex because
1841 of the way GC is done.
1842 */
1843 int n = thread_count;
1844 scm_i_thread *t;
1845 SCM list = scm_c_make_list (n, SCM_UNSPECIFIED), *l;
d823b11b 1846
9de87eea
MV
1847 scm_i_pthread_mutex_lock (&thread_admin_mutex);
1848 l = &list;
1849 for (t = all_threads; t && n > 0; t = t->next_thread)
1850 {
2e77f720
LC
1851 if (t != scm_i_signal_delivery_thread)
1852 {
1853 SCM_SETCAR (*l, t->handle);
1854 l = SCM_CDRLOC (*l);
1855 }
9de87eea
MV
1856 n--;
1857 }
1858 *l = SCM_EOL;
1859 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
1860 return list;
d823b11b 1861}
9de87eea 1862#undef FUNC_NAME
d823b11b
MV
1863
1864SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1865 (SCM thread),
1866 "Return @code{#t} iff @var{thread} has exited.\n")
1867#define FUNC_NAME s_scm_thread_exited_p
1868{
7888309b 1869 return scm_from_bool (scm_c_thread_exited_p (thread));
d823b11b
MV
1870}
1871#undef FUNC_NAME
1872
911782b7 1873int
d823b11b
MV
1874scm_c_thread_exited_p (SCM thread)
1875#define FUNC_NAME s_scm_thread_exited_p
5f05c406 1876{
9de87eea 1877 scm_i_thread *t;
d823b11b 1878 SCM_VALIDATE_THREAD (1, thread);
9de87eea 1879 t = SCM_I_THREAD_DATA (thread);
d823b11b 1880 return t->exited;
5f05c406 1881}
d823b11b 1882#undef FUNC_NAME
5f05c406 1883
9de87eea 1884static scm_i_pthread_cond_t wake_up_cond;
9bc4701c
MD
1885static int threads_initialized_p = 0;
1886
9bc4701c 1887
a4d106c7
MV
1888/* This mutex is used by SCM_CRITICAL_SECTION_START/END.
1889 */
d1138028 1890scm_i_pthread_mutex_t scm_i_critical_section_mutex;
a4d106c7 1891
661ae7ab 1892static SCM dynwind_critical_section_mutex;
a54a94b3 1893
9bc4701c 1894void
661ae7ab 1895scm_dynwind_critical_section (SCM mutex)
76da80e7 1896{
a4d106c7 1897 if (scm_is_false (mutex))
661ae7ab
MV
1898 mutex = dynwind_critical_section_mutex;
1899 scm_dynwind_lock_mutex (mutex);
1900 scm_dynwind_block_asyncs ();
9de87eea
MV
1901}
1902
1903/*** Initialization */
1904
9de87eea
MV
1905scm_i_pthread_mutex_t scm_i_misc_mutex;
1906
d1138028
MV
1907#if SCM_USE_PTHREAD_THREADS
1908pthread_mutexattr_t scm_i_pthread_mutexattr_recursive[1];
1909#endif
1910
9de87eea
MV
1911void
1912scm_threads_prehistory (SCM_STACKITEM *base)
1913{
d1138028
MV
1914#if SCM_USE_PTHREAD_THREADS
1915 pthread_mutexattr_init (scm_i_pthread_mutexattr_recursive);
1916 pthread_mutexattr_settype (scm_i_pthread_mutexattr_recursive,
1917 PTHREAD_MUTEX_RECURSIVE);
1918#endif
1919
1920 scm_i_pthread_mutex_init (&scm_i_critical_section_mutex,
1921 scm_i_pthread_mutexattr_recursive);
9de87eea
MV
1922 scm_i_pthread_mutex_init (&scm_i_misc_mutex, NULL);
1923 scm_i_pthread_cond_init (&wake_up_cond, NULL);
74926120 1924
9de87eea 1925 guilify_self_1 (base);
9bc4701c
MD
1926}
1927
d823b11b
MV
1928scm_t_bits scm_tc16_thread;
1929scm_t_bits scm_tc16_mutex;
1930scm_t_bits scm_tc16_condvar;
7bfd3b9e 1931
7bfd3b9e 1932void
9de87eea 1933scm_init_threads ()
7bfd3b9e 1934{
9de87eea 1935 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_i_thread));
d823b11b 1936 scm_set_smob_print (scm_tc16_thread, thread_print);
d823b11b 1937
9de87eea 1938 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (fat_mutex));
9de87eea
MV
1939 scm_set_smob_print (scm_tc16_mutex, fat_mutex_print);
1940 scm_set_smob_free (scm_tc16_mutex, fat_mutex_free);
9bc4701c 1941
9de87eea
MV
1942 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
1943 sizeof (fat_cond));
9de87eea 1944 scm_set_smob_print (scm_tc16_condvar, fat_cond_print);
d823b11b 1945
9de87eea
MV
1946 scm_i_default_dynamic_state = SCM_BOOL_F;
1947 guilify_self_2 (SCM_BOOL_F);
9bc4701c 1948 threads_initialized_p = 1;
a4d106c7 1949
661ae7ab 1950 dynwind_critical_section_mutex =
a4d106c7 1951 scm_permanent_object (scm_make_recursive_mutex ());
7bfd3b9e 1952}
89e00824 1953
5f05c406 1954void
9de87eea 1955scm_init_threads_default_dynamic_state ()
5f05c406 1956{
9de87eea
MV
1957 SCM state = scm_make_dynamic_state (scm_current_dynamic_state ());
1958 scm_i_default_dynamic_state = scm_permanent_object (state);
5f05c406
MV
1959}
1960
d823b11b 1961void
9de87eea 1962scm_init_thread_procs ()
d823b11b 1963{
9de87eea 1964#include "libguile/threads.x"
d823b11b
MV
1965}
1966
3c13664e
LC
1967\f
1968/* IA64-specific things. */
1969
1970#ifdef __ia64__
1971# ifdef __hpux
1972# include <sys/param.h>
1973# include <sys/pstat.h>
1974void *
1975scm_ia64_register_backing_store_base (void)
1976{
1977 struct pst_vm_status vm_status;
1978 int i = 0;
1979 while (pstat_getprocvm (&vm_status, sizeof (vm_status), 0, i++) == 1)
1980 if (vm_status.pst_type == PS_RSESTACK)
1981 return (void *) vm_status.pst_vaddr;
1982 abort ();
1983}
1984void *
1985scm_ia64_ar_bsp (const void *ctx)
1986{
1987 uint64_t bsp;
1988 __uc_get_ar_bsp (ctx, &bsp);
1989 return (void *) bsp;
1990}
1991# endif /* hpux */
1992# ifdef linux
1993# include <ucontext.h>
1994void *
1995scm_ia64_register_backing_store_base (void)
1996{
1997 extern void *__libc_ia64_register_backing_store_base;
1998 return __libc_ia64_register_backing_store_base;
1999}
2000void *
2001scm_ia64_ar_bsp (const void *opaque)
2002{
2003 const ucontext_t *ctx = opaque;
2004 return (void *) ctx->uc_mcontext.sc_ar_bsp;
2005}
2006# endif /* linux */
2007#endif /* __ia64__ */
2008
2009
89e00824
ML
2010/*
2011 Local Variables:
2012 c-file-style: "gnu"
2013 End:
2014*/