remove a bunch of needless scm_permanent_object calls
[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 341 t->base = base;
346e4402
NJ
342#ifdef __ia64__
343 /* Calculate and store off the base of this thread's register
344 backing store (RBS). Unfortunately our implementation(s) of
345 scm_ia64_register_backing_store_base are only reliable for the
346 main thread. For other threads, therefore, find out the current
347 top of the RBS, and use that as a maximum. */
348 t->register_backing_store_base = scm_ia64_register_backing_store_base ();
349 {
350 ucontext_t ctx;
351 void *bsp;
352 getcontext (&ctx);
353 bsp = scm_ia64_ar_bsp (&ctx);
354 if (t->register_backing_store_base > bsp)
355 t->register_backing_store_base = bsp;
356 }
357#endif
0c97d7dd 358 t->continuation_root = SCM_EOL;
9de87eea
MV
359 t->continuation_base = base;
360 scm_i_pthread_cond_init (&t->sleep_cond, NULL);
361 t->sleep_mutex = NULL;
362 t->sleep_object = SCM_BOOL_F;
363 t->sleep_fd = -1;
634aa8de
LC
364
365 if (pipe (t->sleep_pipe) != 0)
366 /* FIXME: Error conditions during the initialization phase are handled
367 gracelessly since public functions such as `scm_init_guile ()'
368 currently have type `void'. */
369 abort ();
370
86a597f8 371 scm_i_pthread_mutex_init (&t->admin_mutex, NULL);
378f2625
LC
372 t->current_mark_stack_ptr = NULL;
373 t->current_mark_stack_limit = NULL;
2e77f720 374 t->canceled = 0;
9de87eea 375 t->exited = 0;
72e6b608 376 t->guile_mode = 0;
9de87eea 377
705edb95 378 SET_CURRENT_THREAD (t);
9de87eea 379
9de87eea
MV
380 scm_i_pthread_mutex_lock (&thread_admin_mutex);
381 t->next_thread = all_threads;
382 all_threads = t;
383 thread_count++;
384 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
d823b11b
MV
385}
386
9de87eea 387/* Perform second stage of thread initialisation, in guile mode.
d823b11b 388 */
9de87eea
MV
389static void
390guilify_self_2 (SCM parent)
d823b11b 391{
9de87eea
MV
392 scm_i_thread *t = SCM_I_CURRENT_THREAD;
393
72e6b608
LC
394 t->guile_mode = 1;
395
9de87eea 396 SCM_NEWSMOB (t->handle, scm_tc16_thread, t);
c812243b 397
9de87eea
MV
398 t->continuation_root = scm_cons (t->handle, SCM_EOL);
399 t->continuation_base = t->base;
2bbe1533 400 t->vm = SCM_BOOL_F;
9de87eea
MV
401
402 if (scm_is_true (parent))
403 t->dynamic_state = scm_make_dynamic_state (parent);
404 else
405 t->dynamic_state = scm_i_make_initial_dynamic_state ();
406
407 t->join_queue = make_queue ();
408 t->block_asyncs = 0;
d823b11b
MV
409}
410
6180e336
NJ
411\f
412/*** Fat mutexes */
413
414/* We implement our own mutex type since we want them to be 'fair', we
415 want to do fancy things while waiting for them (like running
416 asyncs) and we might want to add things that are nice for
417 debugging.
418*/
419
420typedef struct {
421 scm_i_pthread_mutex_t lock;
422 SCM owner;
adc085f1 423 int level; /* how much the owner owns us. <= 1 for non-recursive mutexes */
6180e336 424
adc085f1 425 int recursive; /* allow recursive locking? */
6180e336
NJ
426 int unchecked_unlock; /* is it an error to unlock an unlocked mutex? */
427 int allow_external_unlock; /* is it an error to unlock a mutex that is not
428 owned by the current thread? */
429
430 SCM waiting; /* the threads waiting for this mutex. */
431} fat_mutex;
432
433#define SCM_MUTEXP(x) SCM_SMOB_PREDICATE (scm_tc16_mutex, x)
434#define SCM_MUTEX_DATA(x) ((fat_mutex *) SCM_SMOB_DATA (x))
435
9de87eea 436/* Perform thread tear-down, in guile mode.
d823b11b 437 */
9de87eea
MV
438static void *
439do_thread_exit (void *v)
440{
2e77f720
LC
441 scm_i_thread *t = (scm_i_thread *) v;
442
443 if (!scm_is_false (t->cleanup_handler))
444 {
445 SCM ptr = t->cleanup_handler;
446
447 t->cleanup_handler = SCM_BOOL_F;
448 t->result = scm_internal_catch (SCM_BOOL_T,
449 (scm_t_catch_body) scm_call_0, ptr,
450 scm_handle_by_message_noexit, NULL);
451 }
9de87eea 452
86a597f8 453 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
9de87eea
MV
454
455 t->exited = 1;
0c97d7dd
MV
456 close (t->sleep_pipe[0]);
457 close (t->sleep_pipe[1]);
9de87eea
MV
458 while (scm_is_true (unblock_from_queue (t->join_queue)))
459 ;
9de87eea 460
74926120 461 while (!scm_is_null (t->mutexes))
6180e336 462 {
a0faf7dd 463 SCM mutex = SCM_WEAK_PAIR_CAR (t->mutexes);
74926120 464
a0faf7dd
LC
465 if (!SCM_UNBNDP (mutex))
466 {
467 fat_mutex *m = SCM_MUTEX_DATA (mutex);
468
469 scm_i_pthread_mutex_lock (&m->lock);
470 unblock_from_queue (m->waiting);
471 scm_i_pthread_mutex_unlock (&m->lock);
472 }
6180e336 473
a0faf7dd 474 t->mutexes = SCM_WEAK_PAIR_CDR (t->mutexes);
6180e336
NJ
475 }
476
86a597f8 477 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720 478
9de87eea
MV
479 return NULL;
480}
481
d823b11b 482static void
9de87eea 483on_thread_exit (void *v)
d823b11b 484{
29776e85 485 /* This handler is executed in non-guile mode. */
2e77f720 486 scm_i_thread *t = (scm_i_thread *) v, **tp;
0c97d7dd 487
d2a51087
NJ
488 /* If this thread was cancelled while doing a cond wait, it will
489 still have a mutex locked, so we unlock it here. */
490 if (t->held_mutex)
491 {
492 scm_i_pthread_mutex_unlock (t->held_mutex);
493 t->held_mutex = NULL;
494 }
495
705edb95 496 SET_CURRENT_THREAD (v);
0c97d7dd 497
2e77f720
LC
498 /* Ensure the signal handling thread has been launched, because we might be
499 shutting it down. */
500 scm_i_ensure_signal_delivery_thread ();
501
0c97d7dd 502 /* Unblocking the joining threads needs to happen in guile mode
29776e85 503 since the queue is a SCM data structure. */
35747a3e 504
47b6e9bd
LC
505 /* Note: Since `do_thread_exit ()' uses allocates memory via `libgc', we
506 assume the GC is usable at this point, and notably that thread-local
507 storage (TLS) hasn't been deallocated yet. */
508 do_thread_exit (v);
0c97d7dd
MV
509
510 /* Removing ourself from the list of all threads needs to happen in
511 non-guile mode since all SCM values on our stack become
29776e85 512 unprotected once we are no longer in the list. */
0c97d7dd
MV
513 scm_i_pthread_mutex_lock (&thread_admin_mutex);
514 for (tp = &all_threads; *tp; tp = &(*tp)->next_thread)
515 if (*tp == t)
516 {
517 *tp = t->next_thread;
c058db8a
LC
518
519 /* GC-robust */
520 t->next_thread = NULL;
521
0c97d7dd
MV
522 break;
523 }
524 thread_count--;
2e77f720
LC
525
526 /* If there's only one other thread, it could be the signal delivery
527 thread, so we need to notify it to shut down by closing its read pipe.
528 If it's not the signal delivery thread, then closing the read pipe isn't
529 going to hurt. */
530 if (thread_count <= 1)
531 scm_i_close_signal_pipe ();
532
0c97d7dd
MV
533 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
534
705edb95 535 SET_CURRENT_THREAD (NULL);
d823b11b
MV
536}
537
705edb95
LC
538#ifndef SCM_HAVE_THREAD_STORAGE_CLASS
539
9de87eea 540static scm_i_pthread_once_t init_thread_key_once = SCM_I_PTHREAD_ONCE_INIT;
d823b11b 541
9de87eea
MV
542static void
543init_thread_key (void)
544{
47b6e9bd 545 scm_i_pthread_key_create (&scm_i_thread_key, NULL);
9de87eea 546}
d823b11b 547
705edb95
LC
548#endif
549
9de87eea
MV
550/* Perform any initializations necessary to bring the current thread
551 into guile mode, initializing Guile itself, if necessary.
a54a94b3 552
9de87eea
MV
553 BASE is the stack base to use with GC.
554
555 PARENT is the dynamic state to use as the parent, ot SCM_BOOL_F in
556 which case the default dynamic state is used.
557
558 Return zero when the thread was in guile mode already; otherwise
559 return 1.
560*/
561
562static int
563scm_i_init_thread_for_guile (SCM_STACKITEM *base, SCM parent)
d823b11b 564{
9de87eea
MV
565 scm_i_thread *t;
566
705edb95 567#ifndef SCM_HAVE_THREAD_STORAGE_CLASS
9de87eea 568 scm_i_pthread_once (&init_thread_key_once, init_thread_key);
705edb95 569#endif
9de87eea 570
705edb95
LC
571 t = SCM_I_CURRENT_THREAD;
572 if (t == NULL)
9de87eea
MV
573 {
574 /* This thread has not been guilified yet.
575 */
576
577 scm_i_pthread_mutex_lock (&scm_i_init_mutex);
578 if (scm_initialized_p == 0)
579 {
580 /* First thread ever to enter Guile. Run the full
581 initialization.
582 */
583 scm_i_init_guile (base);
584 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
585 }
586 else
587 {
588 /* Guile is already initialized, but this thread enters it for
589 the first time. Only initialize this thread.
590 */
591 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
592 guilify_self_1 (base);
593 guilify_self_2 (parent);
594 }
595 return 1;
596 }
597 else if (t->top)
598 {
599 /* This thread is already guilified but not in guile mode, just
600 resume it.
74926120 601
ccf1ca4a
LC
602 A user call to scm_with_guile() will lead us to here. This could
603 happen from anywhere on the stack, and in particular lower on the
604 stack than when it was when this thread was first guilified. Thus,
605 `base' must be updated. */
606#if SCM_STACK_GROWS_UP
607 if (base < t->base)
608 t->base = base;
609#else
610 if (base > t->base)
611 t->base = base;
612#endif
613
45f15cac 614 t->top = NULL;
9de87eea
MV
615 return 1;
616 }
617 else
618 {
619 /* Thread is already in guile mode. Nothing to do.
620 */
621 return 0;
622 }
d823b11b
MV
623}
624
9de87eea 625#if SCM_USE_PTHREAD_THREADS
9de87eea 626
23d72566
KR
627#if HAVE_PTHREAD_ATTR_GETSTACK && HAVE_PTHREAD_GETATTR_NP
628/* This method for GNU/Linux and perhaps some other systems.
629 It's not for MacOS X or Solaris 10, since pthread_getattr_np is not
630 available on them. */
9de87eea
MV
631#define HAVE_GET_THREAD_STACK_BASE
632
633static SCM_STACKITEM *
634get_thread_stack_base ()
d823b11b 635{
9de87eea
MV
636 pthread_attr_t attr;
637 void *start, *end;
638 size_t size;
639
9de87eea
MV
640 pthread_getattr_np (pthread_self (), &attr);
641 pthread_attr_getstack (&attr, &start, &size);
642 end = (char *)start + size;
643
2b829bbb
KR
644 /* XXX - pthread_getattr_np from LinuxThreads does not seem to work
645 for the main thread, but we can use scm_get_stack_base in that
646 case.
647 */
648
649#ifndef PTHREAD_ATTR_GETSTACK_WORKS
9de87eea 650 if ((void *)&attr < start || (void *)&attr >= end)
071e0d93 651 return (SCM_STACKITEM *) GC_stackbottom;
9de87eea 652 else
2b829bbb 653#endif
9de87eea
MV
654 {
655#if SCM_STACK_GROWS_UP
656 return start;
657#else
658 return end;
659#endif
660 }
a54a94b3
MV
661}
662
56a3dcd4 663#elif defined HAVE_PTHREAD_GET_STACKADDR_NP
23d72566
KR
664/* This method for MacOS X.
665 It'd be nice if there was some documentation on pthread_get_stackaddr_np,
666 but as of 2006 there's nothing obvious at apple.com. */
667#define HAVE_GET_THREAD_STACK_BASE
668static SCM_STACKITEM *
669get_thread_stack_base ()
670{
671 return pthread_get_stackaddr_np (pthread_self ());
672}
673
674#elif defined (__MINGW32__)
675/* This method for mingw. In mingw the basic scm_get_stack_base can be used
676 in any thread. We don't like hard-coding the name of a system, but there
677 doesn't seem to be a cleaner way of knowing scm_get_stack_base can
678 work. */
679#define HAVE_GET_THREAD_STACK_BASE
680static SCM_STACKITEM *
681get_thread_stack_base ()
682{
071e0d93 683 return (SCM_STACKITEM *) GC_stackbottom;
23d72566
KR
684}
685
686#endif /* pthread methods of get_thread_stack_base */
9de87eea
MV
687
688#else /* !SCM_USE_PTHREAD_THREADS */
689
690#define HAVE_GET_THREAD_STACK_BASE
691
692static SCM_STACKITEM *
693get_thread_stack_base ()
a54a94b3 694{
071e0d93 695 return (SCM_STACKITEM *) GC_stackbottom;
d823b11b
MV
696}
697
9de87eea 698#endif /* !SCM_USE_PTHREAD_THREADS */
9de87eea
MV
699
700#ifdef HAVE_GET_THREAD_STACK_BASE
701
702void
703scm_init_guile ()
d823b11b 704{
9de87eea
MV
705 scm_i_init_thread_for_guile (get_thread_stack_base (),
706 scm_i_default_dynamic_state);
d823b11b
MV
707}
708
9de87eea
MV
709#endif
710
711void *
712scm_with_guile (void *(*func)(void *), void *data)
713{
714 return scm_i_with_guile_and_parent (func, data,
715 scm_i_default_dynamic_state);
716}
717
70eca635 718SCM_UNUSED static void
2e77f720
LC
719scm_leave_guile_cleanup (void *x)
720{
47b6e9bd 721 on_thread_exit (SCM_I_CURRENT_THREAD);
2e77f720
LC
722}
723
9de87eea 724void *
2e77f720 725scm_i_with_guile_and_parent (void *(*func)(void *), void *data, SCM parent)
9de87eea
MV
726{
727 void *res;
728 int really_entered;
729 SCM_STACKITEM base_item;
2e77f720 730
9de87eea 731 really_entered = scm_i_init_thread_for_guile (&base_item, parent);
9de87eea 732 if (really_entered)
2e77f720
LC
733 {
734 scm_i_pthread_cleanup_push (scm_leave_guile_cleanup, NULL);
735 res = scm_c_with_continuation_barrier (func, data);
736 scm_i_pthread_cleanup_pop (0);
2e77f720 737 }
74926120 738 else
2e77f720
LC
739 res = scm_c_with_continuation_barrier (func, data);
740
9de87eea
MV
741 return res;
742}
743
72e6b608
LC
744\f
745/*** Non-guile mode. */
746
3d1af79f 747#ifdef HAVE_GC_DO_BLOCKING
72e6b608 748
3d1af79f
LC
749# ifndef HAVE_GC_FN_TYPE
750/* This typedef is missing from the public headers of GC 7.1 and earlier. */
751typedef void * (* GC_fn_type) (void *);
752# endif /* HAVE_GC_FN_TYPE */
72e6b608 753
3d1af79f
LC
754# ifndef HAVE_DECL_GC_DO_BLOCKING
755/* This declaration is missing from the public headers of GC 7.1. */
756extern void GC_do_blocking (GC_fn_type, void *);
757# endif /* HAVE_DECL_GC_DO_BLOCKING */
72e6b608 758
72e6b608
LC
759struct without_guile_arg
760{
761 void * (*function) (void *);
762 void *data;
763 void *result;
764};
765
766static void
767without_guile_trampoline (void *closure)
768{
769 struct without_guile_arg *arg;
770
771 SCM_I_CURRENT_THREAD->guile_mode = 0;
772
773 arg = (struct without_guile_arg *) closure;
774 arg->result = arg->function (arg->data);
775
776 SCM_I_CURRENT_THREAD->guile_mode = 1;
777}
3d1af79f
LC
778
779#endif /* HAVE_GC_DO_BLOCKING */
780
72e6b608 781
9de87eea
MV
782void *
783scm_without_guile (void *(*func)(void *), void *data)
d823b11b 784{
72e6b608
LC
785 void *result;
786
787#ifdef HAVE_GC_DO_BLOCKING
788 if (SCM_I_CURRENT_THREAD->guile_mode)
789 {
790 struct without_guile_arg arg;
791
792 arg.function = func;
793 arg.data = data;
3d1af79f 794 GC_do_blocking ((GC_fn_type) without_guile_trampoline, &arg);
72e6b608
LC
795 result = arg.result;
796 }
797 else
798#endif
799 result = func (data);
800
801 return result;
9de87eea
MV
802}
803
72e6b608 804\f
9de87eea
MV
805/*** Thread creation */
806
807typedef struct {
808 SCM parent;
809 SCM thunk;
810 SCM handler;
76da80e7 811 SCM thread;
9de87eea
MV
812 scm_i_pthread_mutex_t mutex;
813 scm_i_pthread_cond_t cond;
814} launch_data;
d823b11b 815
9de87eea
MV
816static void *
817really_launch (void *d)
818{
819 launch_data *data = (launch_data *)d;
820 SCM thunk = data->thunk, handler = data->handler;
821 scm_i_thread *t;
d823b11b 822
9de87eea 823 t = SCM_I_CURRENT_THREAD;
a54a94b3 824
9de87eea
MV
825 scm_i_scm_pthread_mutex_lock (&data->mutex);
826 data->thread = scm_current_thread ();
827 scm_i_pthread_cond_signal (&data->cond);
828 scm_i_pthread_mutex_unlock (&data->mutex);
829
830 if (SCM_UNBNDP (handler))
831 t->result = scm_call_0 (thunk);
832 else
833 t->result = scm_catch (SCM_BOOL_T, thunk, handler);
834
47b6e9bd
LC
835 /* Trigger a call to `on_thread_exit ()'. */
836 pthread_exit (NULL);
837
9de87eea 838 return 0;
d823b11b
MV
839}
840
9de87eea
MV
841static void *
842launch_thread (void *d)
843{
844 launch_data *data = (launch_data *)d;
845 scm_i_pthread_detach (scm_i_pthread_self ());
846 scm_i_with_guile_and_parent (really_launch, d, data->parent);
847 return NULL;
848}
849
850SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 1, 1, 0,
d823b11b 851 (SCM thunk, SCM handler),
9de87eea
MV
852 "Call @code{thunk} in a new thread and with a new dynamic state,\n"
853 "returning a new thread object representing the thread. The procedure\n"
854 "@var{thunk} is called via @code{with-continuation-barrier}.\n"
855 "\n"
856 "When @var{handler} is specified, then @var{thunk} is called from\n"
857 "within a @code{catch} with tag @code{#t} that has @var{handler} as its\n"
858 "handler. This catch is established inside the continuation barrier.\n"
859 "\n"
860 "Once @var{thunk} or @var{handler} returns, the return value is made\n"
861 "the @emph{exit value} of the thread and the thread is terminated.")
d823b11b
MV
862#define FUNC_NAME s_scm_call_with_new_thread
863{
9de87eea
MV
864 launch_data data;
865 scm_i_pthread_t id;
866 int err;
d823b11b 867
9de87eea
MV
868 SCM_ASSERT (scm_is_true (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
869 SCM_ASSERT (SCM_UNBNDP (handler) || scm_is_true (scm_procedure_p (handler)),
870 handler, SCM_ARG2, FUNC_NAME);
871
872 data.parent = scm_current_dynamic_state ();
873 data.thunk = thunk;
874 data.handler = handler;
875 data.thread = SCM_BOOL_F;
876 scm_i_pthread_mutex_init (&data.mutex, NULL);
877 scm_i_pthread_cond_init (&data.cond, NULL);
878
879 scm_i_scm_pthread_mutex_lock (&data.mutex);
880 err = scm_i_pthread_create (&id, NULL, launch_thread, &data);
881 if (err)
882 {
883 scm_i_pthread_mutex_unlock (&data.mutex);
884 errno = err;
885 scm_syserror (NULL);
886 }
887 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
888 scm_i_pthread_mutex_unlock (&data.mutex);
74926120 889
9de87eea 890 return data.thread;
d823b11b
MV
891}
892#undef FUNC_NAME
893
9de87eea
MV
894typedef struct {
895 SCM parent;
896 scm_t_catch_body body;
897 void *body_data;
898 scm_t_catch_handler handler;
899 void *handler_data;
900 SCM thread;
901 scm_i_pthread_mutex_t mutex;
902 scm_i_pthread_cond_t cond;
903} spawn_data;
904
905static void *
906really_spawn (void *d)
907{
908 spawn_data *data = (spawn_data *)d;
909 scm_t_catch_body body = data->body;
910 void *body_data = data->body_data;
911 scm_t_catch_handler handler = data->handler;
912 void *handler_data = data->handler_data;
913 scm_i_thread *t = SCM_I_CURRENT_THREAD;
914
915 scm_i_scm_pthread_mutex_lock (&data->mutex);
916 data->thread = scm_current_thread ();
917 scm_i_pthread_cond_signal (&data->cond);
918 scm_i_pthread_mutex_unlock (&data->mutex);
919
920 if (handler == NULL)
921 t->result = body (body_data);
922 else
923 t->result = scm_internal_catch (SCM_BOOL_T,
924 body, body_data,
925 handler, handler_data);
926
927 return 0;
928}
929
930static void *
931spawn_thread (void *d)
932{
933 spawn_data *data = (spawn_data *)d;
934 scm_i_pthread_detach (scm_i_pthread_self ());
935 scm_i_with_guile_and_parent (really_spawn, d, data->parent);
936 return NULL;
937}
938
939SCM
940scm_spawn_thread (scm_t_catch_body body, void *body_data,
941 scm_t_catch_handler handler, void *handler_data)
942{
943 spawn_data data;
944 scm_i_pthread_t id;
945 int err;
946
947 data.parent = scm_current_dynamic_state ();
948 data.body = body;
949 data.body_data = body_data;
950 data.handler = handler;
951 data.handler_data = handler_data;
952 data.thread = SCM_BOOL_F;
953 scm_i_pthread_mutex_init (&data.mutex, NULL);
954 scm_i_pthread_cond_init (&data.cond, NULL);
955
956 scm_i_scm_pthread_mutex_lock (&data.mutex);
957 err = scm_i_pthread_create (&id, NULL, spawn_thread, &data);
958 if (err)
959 {
960 scm_i_pthread_mutex_unlock (&data.mutex);
961 errno = err;
962 scm_syserror (NULL);
963 }
964 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
965 scm_i_pthread_mutex_unlock (&data.mutex);
74926120 966
9de87eea
MV
967 return data.thread;
968}
969
29717c89
MD
970SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
971 (),
972"Move the calling thread to the end of the scheduling queue.")
973#define FUNC_NAME s_scm_yield
974{
9de87eea 975 return scm_from_bool (scm_i_sched_yield ());
29717c89
MD
976}
977#undef FUNC_NAME
978
2e77f720
LC
979SCM_DEFINE (scm_cancel_thread, "cancel-thread", 1, 0, 0,
980 (SCM thread),
981"Asynchronously force the target @var{thread} to terminate. @var{thread} "
982"cannot be the current thread, and if @var{thread} has already terminated or "
983"been signaled to terminate, this function is a no-op.")
984#define FUNC_NAME s_scm_cancel_thread
985{
986 scm_i_thread *t = NULL;
987
988 SCM_VALIDATE_THREAD (1, thread);
989 t = SCM_I_THREAD_DATA (thread);
86a597f8 990 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
2e77f720
LC
991 if (!t->canceled)
992 {
993 t->canceled = 1;
86a597f8 994 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
995 scm_i_pthread_cancel (t->pthread);
996 }
997 else
86a597f8 998 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
999
1000 return SCM_UNSPECIFIED;
1001}
1002#undef FUNC_NAME
1003
1004SCM_DEFINE (scm_set_thread_cleanup_x, "set-thread-cleanup!", 2, 0, 0,
1005 (SCM thread, SCM proc),
1006"Set the thunk @var{proc} as the cleanup handler for the thread @var{thread}. "
1007"This handler will be called when the thread exits.")
1008#define FUNC_NAME s_scm_set_thread_cleanup_x
1009{
1010 scm_i_thread *t;
1011
1012 SCM_VALIDATE_THREAD (1, thread);
1013 if (!scm_is_false (proc))
1014 SCM_VALIDATE_THUNK (2, proc);
1015
2e77f720 1016 t = SCM_I_THREAD_DATA (thread);
86a597f8
NJ
1017 scm_i_pthread_mutex_lock (&t->admin_mutex);
1018
2e77f720
LC
1019 if (!(t->exited || t->canceled))
1020 t->cleanup_handler = proc;
1021
86a597f8 1022 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1023
1024 return SCM_UNSPECIFIED;
1025}
1026#undef FUNC_NAME
1027
1028SCM_DEFINE (scm_thread_cleanup, "thread-cleanup", 1, 0, 0,
1029 (SCM thread),
1030"Return the cleanup handler installed for the thread @var{thread}.")
1031#define FUNC_NAME s_scm_thread_cleanup
1032{
1033 scm_i_thread *t;
1034 SCM ret;
1035
1036 SCM_VALIDATE_THREAD (1, thread);
1037
2e77f720 1038 t = SCM_I_THREAD_DATA (thread);
86a597f8 1039 scm_i_pthread_mutex_lock (&t->admin_mutex);
2e77f720 1040 ret = (t->exited || t->canceled) ? SCM_BOOL_F : t->cleanup_handler;
86a597f8 1041 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720
LC
1042
1043 return ret;
1044}
1045#undef FUNC_NAME
1046
6180e336
NJ
1047SCM scm_join_thread (SCM thread)
1048{
1049 return scm_join_thread_timed (thread, SCM_UNDEFINED, SCM_UNDEFINED);
1050}
1051
1052SCM_DEFINE (scm_join_thread_timed, "join-thread", 1, 2, 0,
1053 (SCM thread, SCM timeout, SCM timeoutval),
d823b11b
MV
1054"Suspend execution of the calling thread until the target @var{thread} "
1055"terminates, unless the target @var{thread} has already terminated. ")
6180e336 1056#define FUNC_NAME s_scm_join_thread_timed
5f05c406 1057{
9de87eea 1058 scm_i_thread *t;
6180e336
NJ
1059 scm_t_timespec ctimeout, *timeout_ptr = NULL;
1060 SCM res = SCM_BOOL_F;
1061
1062 if (! (SCM_UNBNDP (timeoutval)))
1063 res = timeoutval;
d823b11b
MV
1064
1065 SCM_VALIDATE_THREAD (1, thread);
9de87eea 1066 if (scm_is_eq (scm_current_thread (), thread))
2e77f720 1067 SCM_MISC_ERROR ("cannot join the current thread", SCM_EOL);
d823b11b 1068
9de87eea 1069 t = SCM_I_THREAD_DATA (thread);
86a597f8
NJ
1070 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
1071
6180e336
NJ
1072 if (! SCM_UNBNDP (timeout))
1073 {
1074 to_timespec (timeout, &ctimeout);
1075 timeout_ptr = &ctimeout;
1076 }
1077
1078 if (t->exited)
1079 res = t->result;
1080 else
d823b11b 1081 {
9de87eea
MV
1082 while (1)
1083 {
74926120 1084 int err = block_self (t->join_queue, thread, &t->admin_mutex,
6180e336
NJ
1085 timeout_ptr);
1086 if (err == 0)
1087 {
1088 if (t->exited)
1089 {
1090 res = t->result;
1091 break;
1092 }
1093 }
1094 else if (err == ETIMEDOUT)
9de87eea 1095 break;
6180e336 1096
86a597f8 1097 scm_i_pthread_mutex_unlock (&t->admin_mutex);
9de87eea 1098 SCM_TICK;
86a597f8 1099 scm_i_scm_pthread_mutex_lock (&t->admin_mutex);
21346c4f
NJ
1100
1101 /* Check for exit again, since we just released and
1102 reacquired the admin mutex, before the next block_self
1103 call (which would block forever if t has already
1104 exited). */
1105 if (t->exited)
1106 {
1107 res = t->result;
1108 break;
1109 }
9de87eea 1110 }
d823b11b 1111 }
9de87eea 1112
86a597f8 1113 scm_i_pthread_mutex_unlock (&t->admin_mutex);
2e77f720 1114
d823b11b 1115 return res;
5f05c406
MV
1116}
1117#undef FUNC_NAME
1118
6180e336
NJ
1119SCM_DEFINE (scm_thread_p, "thread?", 1, 0, 0,
1120 (SCM obj),
1121 "Return @code{#t} if @var{obj} is a thread.")
1122#define FUNC_NAME s_scm_thread_p
1123{
1124 return SCM_I_IS_THREAD(obj) ? SCM_BOOL_T : SCM_BOOL_F;
1125}
1126#undef FUNC_NAME
5f05c406 1127
4079f87e 1128
9de87eea
MV
1129static size_t
1130fat_mutex_free (SCM mx)
76da80e7 1131{
9de87eea
MV
1132 fat_mutex *m = SCM_MUTEX_DATA (mx);
1133 scm_i_pthread_mutex_destroy (&m->lock);
76da80e7
MV
1134 return 0;
1135}
1136
1137static int
9de87eea 1138fat_mutex_print (SCM mx, SCM port, scm_print_state *pstate SCM_UNUSED)
76da80e7 1139{
9de87eea
MV
1140 fat_mutex *m = SCM_MUTEX_DATA (mx);
1141 scm_puts ("#<mutex ", port);
1142 scm_uintprint ((scm_t_bits)m, 16, port);
1143 scm_puts (">", port);
1144 return 1;
76da80e7
MV
1145}
1146
76da80e7 1147static SCM
6180e336 1148make_fat_mutex (int recursive, int unchecked_unlock, int external_unlock)
76da80e7 1149{
9de87eea
MV
1150 fat_mutex *m;
1151 SCM mx;
1152
1153 m = scm_gc_malloc (sizeof (fat_mutex), "mutex");
1154 scm_i_pthread_mutex_init (&m->lock, NULL);
1155 m->owner = SCM_BOOL_F;
adc085f1 1156 m->level = 0;
6180e336 1157
adc085f1 1158 m->recursive = recursive;
6180e336
NJ
1159 m->unchecked_unlock = unchecked_unlock;
1160 m->allow_external_unlock = external_unlock;
1161
9de87eea
MV
1162 m->waiting = SCM_EOL;
1163 SCM_NEWSMOB (mx, scm_tc16_mutex, (scm_t_bits) m);
1164 m->waiting = make_queue ();
1165 return mx;
76da80e7
MV
1166}
1167
6180e336
NJ
1168SCM scm_make_mutex (void)
1169{
1170 return scm_make_mutex_with_flags (SCM_EOL);
1171}
1172
2a1d0688
NJ
1173SCM_SYMBOL (unchecked_unlock_sym, "unchecked-unlock");
1174SCM_SYMBOL (allow_external_unlock_sym, "allow-external-unlock");
1175SCM_SYMBOL (recursive_sym, "recursive");
6180e336
NJ
1176
1177SCM_DEFINE (scm_make_mutex_with_flags, "make-mutex", 0, 0, 1,
1178 (SCM flags),
9de87eea 1179 "Create a new mutex. ")
6180e336 1180#define FUNC_NAME s_scm_make_mutex_with_flags
76da80e7 1181{
6180e336
NJ
1182 int unchecked_unlock = 0, external_unlock = 0, recursive = 0;
1183
1184 SCM ptr = flags;
1185 while (! scm_is_null (ptr))
1186 {
1187 SCM flag = SCM_CAR (ptr);
1188 if (scm_is_eq (flag, unchecked_unlock_sym))
1189 unchecked_unlock = 1;
1190 else if (scm_is_eq (flag, allow_external_unlock_sym))
1191 external_unlock = 1;
1192 else if (scm_is_eq (flag, recursive_sym))
1193 recursive = 1;
74926120 1194 else
2a1d0688 1195 SCM_MISC_ERROR ("unsupported mutex option: ~a", scm_list_1 (flag));
6180e336
NJ
1196 ptr = SCM_CDR (ptr);
1197 }
1198 return make_fat_mutex (recursive, unchecked_unlock, external_unlock);
76da80e7
MV
1199}
1200#undef FUNC_NAME
1201
9de87eea 1202SCM_DEFINE (scm_make_recursive_mutex, "make-recursive-mutex", 0, 0, 0,
9bc4701c 1203 (void),
9de87eea
MV
1204 "Create a new recursive mutex. ")
1205#define FUNC_NAME s_scm_make_recursive_mutex
9bc4701c 1206{
6180e336 1207 return make_fat_mutex (1, 0, 0);
9bc4701c
MD
1208}
1209#undef FUNC_NAME
1210
6180e336
NJ
1211SCM_SYMBOL (scm_abandoned_mutex_error_key, "abandoned-mutex-error");
1212
1213static SCM
adc085f1 1214fat_mutex_lock (SCM mutex, scm_t_timespec *timeout, SCM owner, int *ret)
9de87eea
MV
1215{
1216 fat_mutex *m = SCM_MUTEX_DATA (mutex);
6180e336 1217
adc085f1 1218 SCM new_owner = SCM_UNBNDP (owner) ? scm_current_thread() : owner;
6180e336
NJ
1219 SCM err = SCM_BOOL_F;
1220
1221 struct timeval current_time;
9de87eea
MV
1222
1223 scm_i_scm_pthread_mutex_lock (&m->lock);
adc085f1
JG
1224
1225 while (1)
9de87eea 1226 {
adc085f1 1227 if (m->level == 0)
6180e336 1228 {
adc085f1 1229 m->owner = new_owner;
6180e336 1230 m->level++;
74926120 1231
adc085f1 1232 if (SCM_I_IS_THREAD (new_owner))
6180e336 1233 {
adc085f1 1234 scm_i_thread *t = SCM_I_THREAD_DATA (new_owner);
6180e336 1235 scm_i_pthread_mutex_lock (&t->admin_mutex);
a0faf7dd
LC
1236
1237 /* Only keep a weak reference to MUTEX so that it's not
1238 retained when not referenced elsewhere (bug #27450). Note
1239 that the weak pair itself it still retained, but it's better
1240 than retaining MUTEX and the threads referred to by its
1241 associated queue. */
1242 t->mutexes = scm_weak_car_pair (mutex, t->mutexes);
1243
6180e336 1244 scm_i_pthread_mutex_unlock (&t->admin_mutex);
6180e336 1245 }
adc085f1
JG
1246 *ret = 1;
1247 break;
1248 }
1249 else if (SCM_I_IS_THREAD (m->owner) && scm_c_thread_exited_p (m->owner))
1250 {
1251 m->owner = new_owner;
1252 err = scm_cons (scm_abandoned_mutex_error_key,
1253 scm_from_locale_string ("lock obtained on abandoned "
1254 "mutex"));
1255 *ret = 1;
1256 break;
1257 }
1258 else if (scm_is_eq (m->owner, new_owner))
1259 {
1260 if (m->recursive)
1261 {
1262 m->level++;
74926120 1263 *ret = 1;
adc085f1
JG
1264 }
1265 else
6180e336 1266 {
adc085f1
JG
1267 err = scm_cons (scm_misc_error_key,
1268 scm_from_locale_string ("mutex already locked "
1269 "by thread"));
1270 *ret = 0;
1271 }
74926120 1272 break;
adc085f1 1273 }
9de87eea 1274 else
9de87eea 1275 {
74926120 1276 if (timeout != NULL)
adc085f1
JG
1277 {
1278 gettimeofday (&current_time, NULL);
1279 if (current_time.tv_sec > timeout->tv_sec ||
1280 (current_time.tv_sec == timeout->tv_sec &&
1281 current_time.tv_usec * 1000 > timeout->tv_nsec))
6180e336 1282 {
adc085f1
JG
1283 *ret = 0;
1284 break;
6180e336 1285 }
6180e336 1286 }
37a52039 1287 block_self (m->waiting, mutex, &m->lock, timeout);
9de87eea
MV
1288 scm_i_pthread_mutex_unlock (&m->lock);
1289 SCM_TICK;
1290 scm_i_scm_pthread_mutex_lock (&m->lock);
1291 }
1292 }
1293 scm_i_pthread_mutex_unlock (&m->lock);
6180e336 1294 return err;
9de87eea
MV
1295}
1296
6180e336
NJ
1297SCM scm_lock_mutex (SCM mx)
1298{
adc085f1 1299 return scm_lock_mutex_timed (mx, SCM_UNDEFINED, SCM_UNDEFINED);
6180e336
NJ
1300}
1301
adc085f1
JG
1302SCM_DEFINE (scm_lock_mutex_timed, "lock-mutex", 1, 2, 0,
1303 (SCM m, SCM timeout, SCM owner),
9bc4701c
MD
1304"Lock @var{mutex}. If the mutex is already locked, the calling thread "
1305"blocks until the mutex becomes available. The function returns when "
1306"the calling thread owns the lock on @var{mutex}. Locking a mutex that "
1307"a thread already owns will succeed right away and will not block the "
1308"thread. That is, Guile's mutexes are @emph{recursive}. ")
6180e336 1309#define FUNC_NAME s_scm_lock_mutex_timed
9bc4701c 1310{
6180e336
NJ
1311 SCM exception;
1312 int ret = 0;
1313 scm_t_timespec cwaittime, *waittime = NULL;
76da80e7 1314
6180e336
NJ
1315 SCM_VALIDATE_MUTEX (1, m);
1316
1317 if (! SCM_UNBNDP (timeout) && ! scm_is_false (timeout))
1318 {
1319 to_timespec (timeout, &cwaittime);
1320 waittime = &cwaittime;
1321 }
1322
adc085f1 1323 exception = fat_mutex_lock (m, waittime, owner, &ret);
6180e336
NJ
1324 if (!scm_is_false (exception))
1325 scm_ithrow (SCM_CAR (exception), scm_list_1 (SCM_CDR (exception)), 1);
1326 return ret ? SCM_BOOL_T : SCM_BOOL_F;
9bc4701c 1327}
76da80e7 1328#undef FUNC_NAME
9bc4701c 1329
a4d106c7 1330void
661ae7ab 1331scm_dynwind_lock_mutex (SCM mutex)
a4d106c7 1332{
661ae7ab
MV
1333 scm_dynwind_unwind_handler_with_scm ((void(*)(SCM))scm_unlock_mutex, mutex,
1334 SCM_F_WIND_EXPLICITLY);
1335 scm_dynwind_rewind_handler_with_scm ((void(*)(SCM))scm_lock_mutex, mutex,
1336 SCM_F_WIND_EXPLICITLY);
a4d106c7
MV
1337}
1338
9bc4701c 1339SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
ba1b7223 1340 (SCM mutex),
9bc4701c
MD
1341"Try to lock @var{mutex}. If the mutex is already locked by someone "
1342"else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
1343#define FUNC_NAME s_scm_try_mutex
1344{
6180e336
NJ
1345 SCM exception;
1346 int ret = 0;
1347 scm_t_timespec cwaittime, *waittime = NULL;
9de87eea 1348
ba1b7223 1349 SCM_VALIDATE_MUTEX (1, mutex);
6180e336
NJ
1350
1351 to_timespec (scm_from_int(0), &cwaittime);
1352 waittime = &cwaittime;
74926120 1353
adc085f1 1354 exception = fat_mutex_lock (mutex, waittime, SCM_UNDEFINED, &ret);
6180e336
NJ
1355 if (!scm_is_false (exception))
1356 scm_ithrow (SCM_CAR (exception), scm_list_1 (SCM_CDR (exception)), 1);
1357 return ret ? SCM_BOOL_T : SCM_BOOL_F;
9de87eea
MV
1358}
1359#undef FUNC_NAME
76da80e7 1360
6180e336
NJ
1361/*** Fat condition variables */
1362
1363typedef struct {
1364 scm_i_pthread_mutex_t lock;
1365 SCM waiting; /* the threads waiting for this condition. */
1366} fat_cond;
1367
1368#define SCM_CONDVARP(x) SCM_SMOB_PREDICATE (scm_tc16_condvar, x)
1369#define SCM_CONDVAR_DATA(x) ((fat_cond *) SCM_SMOB_DATA (x))
1370
1371static int
1372fat_mutex_unlock (SCM mutex, SCM cond,
1373 const scm_t_timespec *waittime, int relock)
9de87eea 1374{
7f991c7d 1375 SCM owner;
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 1382
7f991c7d 1383 owner = m->owner;
adc085f1
JG
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
f39448c5 1950 dynwind_critical_section_mutex = scm_make_recursive_mutex ();
7bfd3b9e 1951}
89e00824 1952
5f05c406 1953void
9de87eea 1954scm_init_threads_default_dynamic_state ()
5f05c406 1955{
9de87eea 1956 SCM state = scm_make_dynamic_state (scm_current_dynamic_state ());
f39448c5 1957 scm_i_default_dynamic_state = state;
5f05c406
MV
1958}
1959
d823b11b 1960void
9de87eea 1961scm_init_thread_procs ()
d823b11b 1962{
9de87eea 1963#include "libguile/threads.x"
d823b11b
MV
1964}
1965
3c13664e
LC
1966\f
1967/* IA64-specific things. */
1968
1969#ifdef __ia64__
1970# ifdef __hpux
1971# include <sys/param.h>
1972# include <sys/pstat.h>
1973void *
1974scm_ia64_register_backing_store_base (void)
1975{
1976 struct pst_vm_status vm_status;
1977 int i = 0;
1978 while (pstat_getprocvm (&vm_status, sizeof (vm_status), 0, i++) == 1)
1979 if (vm_status.pst_type == PS_RSESTACK)
1980 return (void *) vm_status.pst_vaddr;
1981 abort ();
1982}
1983void *
1984scm_ia64_ar_bsp (const void *ctx)
1985{
1986 uint64_t bsp;
1987 __uc_get_ar_bsp (ctx, &bsp);
1988 return (void *) bsp;
1989}
1990# endif /* hpux */
1991# ifdef linux
1992# include <ucontext.h>
1993void *
1994scm_ia64_register_backing_store_base (void)
1995{
1996 extern void *__libc_ia64_register_backing_store_base;
1997 return __libc_ia64_register_backing_store_base;
1998}
1999void *
2000scm_ia64_ar_bsp (const void *opaque)
2001{
2002 const ucontext_t *ctx = opaque;
2003 return (void *) ctx->uc_mcontext.sc_ar_bsp;
2004}
2005# endif /* linux */
2006#endif /* __ia64__ */
2007
2008
89e00824
ML
2009/*
2010 Local Variables:
2011 c-file-style: "gnu"
2012 End:
2013*/