Changes from arch/CVS synchronization
[bpt/guile.git] / libguile / threads.c
CommitLineData
2b829bbb 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
7bfd3b9e 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7bfd3b9e 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
1bbd0b84 17
1bbd0b84 18
7bfd3b9e
JB
19\f
20
9de87eea 21#define _GNU_SOURCE
76da80e7 22
1810dc4e
RB
23#include "libguile/_scm.h"
24
fcc5d734 25#if HAVE_UNISTD_H
d823b11b 26#include <unistd.h>
fcc5d734 27#endif
d823b11b
MV
28#include <stdio.h>
29#include <assert.h>
8ab3d8a0
KR
30
31#ifdef HAVE_STRING_H
32#include <string.h> /* for memset used by FD_ZERO on Solaris 10 */
33#endif
34
fcc5d734 35#if HAVE_SYS_TIME_H
d823b11b 36#include <sys/time.h>
fcc5d734 37#endif
5f05c406 38
d823b11b
MV
39#include "libguile/validate.h"
40#include "libguile/root.h"
41#include "libguile/eval.h"
42#include "libguile/async.h"
43#include "libguile/ports.h"
44#include "libguile/threads.h"
a0599745 45#include "libguile/dynwind.h"
d823b11b 46#include "libguile/iselect.h"
9de87eea
MV
47#include "libguile/fluids.h"
48#include "libguile/continuations.h"
2b829bbb 49#include "libguile/gc.h"
9de87eea 50#include "libguile/init.h"
7bfd3b9e 51
ecc9f40f
MV
52#ifdef __MINGW32__
53#ifndef ETIMEDOUT
54# define ETIMEDOUT WSAETIMEDOUT
55#endif
56# include <fcntl.h>
57# include <process.h>
58# define pipe(fd) _pipe (fd, 256, O_BINARY)
59#endif /* __MINGW32__ */
60
d823b11b 61/*** Queues */
7bfd3b9e 62
9de87eea
MV
63/* Make an empty queue data structure.
64 */
d823b11b
MV
65static SCM
66make_queue ()
67{
68 return scm_cons (SCM_EOL, SCM_EOL);
69}
7bfd3b9e 70
9de87eea
MV
71/* Put T at the back of Q and return a handle that can be used with
72 remqueue to remove T from Q again.
73 */
d823b11b
MV
74static SCM
75enqueue (SCM q, SCM t)
76{
77 SCM c = scm_cons (t, SCM_EOL);
d2e53ed6 78 if (scm_is_null (SCM_CDR (q)))
d823b11b
MV
79 SCM_SETCDR (q, c);
80 else
81 SCM_SETCDR (SCM_CAR (q), c);
82 SCM_SETCAR (q, c);
83 return c;
84}
7bfd3b9e 85
9de87eea
MV
86/* Remove the element that the handle C refers to from the queue Q. C
87 must have been returned from a call to enqueue. The return value
88 is zero when the element referred to by C has already been removed.
89 Otherwise, 1 is returned.
90*/
91static int
d823b11b
MV
92remqueue (SCM q, SCM c)
93{
94 SCM p, prev = q;
d2e53ed6 95 for (p = SCM_CDR (q); !scm_is_null (p); p = SCM_CDR (p))
d823b11b 96 {
bc36d050 97 if (scm_is_eq (p, c))
d823b11b 98 {
bc36d050 99 if (scm_is_eq (c, SCM_CAR (q)))
d823b11b
MV
100 SCM_SETCAR (q, SCM_CDR (c));
101 SCM_SETCDR (prev, SCM_CDR (c));
9de87eea 102 return 1;
d823b11b
MV
103 }
104 prev = p;
105 }
9de87eea 106 return 0;
d823b11b
MV
107}
108
9de87eea
MV
109/* Remove the front-most element from the queue Q and return it.
110 Return SCM_BOOL_F when Q is empty.
111*/
d823b11b
MV
112static SCM
113dequeue (SCM q)
114{
115 SCM c = SCM_CDR (q);
d2e53ed6 116 if (scm_is_null (c))
d823b11b
MV
117 return SCM_BOOL_F;
118 else
119 {
120 SCM_SETCDR (q, SCM_CDR (c));
d2e53ed6 121 if (scm_is_null (SCM_CDR (q)))
d823b11b
MV
122 SCM_SETCAR (q, SCM_EOL);
123 return SCM_CAR (c);
124 }
125}
7bfd3b9e 126
9de87eea 127/*** Thread smob routines */
76da80e7 128
d823b11b
MV
129static SCM
130thread_mark (SCM obj)
131{
9de87eea 132 scm_i_thread *t = SCM_I_THREAD_DATA (obj);
d823b11b 133 scm_gc_mark (t->result);
9de87eea
MV
134 scm_gc_mark (t->join_queue);
135 scm_gc_mark (t->dynwinds);
136 scm_gc_mark (t->active_asyncs);
9de87eea
MV
137 scm_gc_mark (t->continuation_root);
138 return t->dynamic_state;
d823b11b
MV
139}
140
141static int
142thread_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
143{
23d72566
KR
144 /* On a Gnu system pthread_t is an unsigned long, but on mingw it's a
145 struct. A cast like "(unsigned long) t->pthread" is a syntax error in
146 the struct case, hence we go via a union, and extract according to the
147 size of pthread_t. */
148 union {
149 scm_i_pthread_t p;
150 unsigned short us;
151 unsigned int ui;
152 unsigned long ul;
153 scm_t_uintmax um;
154 } u;
9de87eea 155 scm_i_thread *t = SCM_I_THREAD_DATA (exp);
23d72566
KR
156 scm_i_pthread_t p = t->pthread;
157 scm_t_uintmax id;
158 u.p = p;
159 if (sizeof (p) == sizeof (unsigned short))
160 id = u.us;
161 else if (sizeof (p) == sizeof (unsigned int))
162 id = u.ui;
163 else if (sizeof (p) == sizeof (unsigned long))
164 id = u.ul;
165 else
166 id = u.um;
167
d823b11b 168 scm_puts ("#<thread ", port);
23d72566 169 scm_uintprint (id, 10, port);
1b92fb6b 170 scm_puts (" (", port);
0345e278 171 scm_uintprint ((scm_t_bits)t, 16, port);
1b92fb6b 172 scm_puts (")>", port);
d823b11b
MV
173 return 1;
174}
175
176static size_t
177thread_free (SCM obj)
178{
9de87eea
MV
179 scm_i_thread *t = SCM_I_THREAD_DATA (obj);
180 assert (t->exited);
d823b11b
MV
181 scm_gc_free (t, sizeof (*t), "thread");
182 return 0;
183}
184
9de87eea 185/*** Blocking on queues. */
f7eca35d 186
9de87eea
MV
187/* See also scm_i_queue_async_cell for how such a block is
188 interrputed.
189*/
d823b11b 190
9de87eea
MV
191/* Put the current thread on QUEUE and go to sleep, waiting for it to
192 be woken up by a call to 'unblock_from_queue', or to be
193 interrupted. Upon return of this function, the current thread is
194 no longer on QUEUE, even when the sleep has been interrupted.
195
196 The QUEUE data structure is assumed to be protected by MUTEX and
197 the caller of block_self must hold MUTEX. It will be atomically
198 unlocked while sleeping, just as with scm_i_pthread_cond_wait.
199
200 SLEEP_OBJECT is an arbitrary SCM value that is kept alive as long
201 as MUTEX is needed.
202
203 When WAITTIME is not NULL, the sleep will be aborted at that time.
204
205 The return value of block_self is an errno value. It will be zero
206 when the sleep has been successfully completed by a call to
207 unblock_from_queue, EINTR when it has been interrupted by the
208 delivery of a system async, and ETIMEDOUT when the timeout has
209 expired.
210
211 The system asyncs themselves are not executed by block_self.
212*/
213static int
214block_self (SCM queue, SCM sleep_object, scm_i_pthread_mutex_t *mutex,
215 const scm_t_timespec *waittime)
76da80e7 216{
9de87eea
MV
217 scm_i_thread *t = SCM_I_CURRENT_THREAD;
218 SCM q_handle;
219 int err;
220
221 if (scm_i_setup_sleep (t, sleep_object, mutex, -1))
222 err = EINTR;
223 else
224 {
225 t->block_asyncs++;
226 q_handle = enqueue (queue, t->handle);
227 if (waittime == NULL)
228 err = scm_i_scm_pthread_cond_wait (&t->sleep_cond, mutex);
229 else
230 err = scm_i_scm_pthread_cond_timedwait (&t->sleep_cond, mutex, waittime);
231
232 /* When we are still on QUEUE, we have been interrupted. We
233 report this only when no other error (such as a timeout) has
234 happened above.
235 */
236 if (remqueue (queue, q_handle) && err == 0)
237 err = EINTR;
238 t->block_asyncs--;
239 scm_i_reset_sleep (t);
240 }
241
242 return err;
76da80e7 243}
9de87eea
MV
244
245/* Wake up the first thread on QUEUE, if any. The caller must hold
246 the mutex that protects QUEUE. The awoken thread is returned, or
247 #f when the queue was empty.
248 */
249static SCM
250unblock_from_queue (SCM queue)
251{
252 SCM thread = dequeue (queue);
253 if (scm_is_true (thread))
254 scm_i_pthread_cond_signal (&SCM_I_THREAD_DATA(thread)->sleep_cond);
255 return thread;
256}
257
258/* Getting into and out of guile mode.
259 */
260
98648121
MV
261/* Ken Raeburn observes that the implementation of suspend and resume
262 (and the things that build on top of them) are very likely not
263 correct (see below). We will need fix this eventually, and that's
264 why scm_leave_guile/scm_enter_guile are not exported in the API.
265
266 Ken writes:
267
268 Consider this sequence:
269
270 Function foo, called in Guile mode, calls suspend (maybe indirectly
271 through scm_leave_guile), which does this:
272
273 // record top of stack for the GC
274 t->top = SCM_STACK_PTR (&t); // just takes address of automatic
275 var 't'
276 // save registers.
277 SCM_FLUSH_REGISTER_WINDOWS; // sparc only
278 setjmp (t->regs); // here's most of the magic
279
280 ... and returns.
281
282 Function foo has a SCM value X, a handle on a non-immediate object, in
283 a caller-saved register R, and it's the only reference to the object
284 currently.
285
286 The compiler wants to use R in suspend, so it pushes the current
287 value, X, into a stack slot which will be reloaded on exit from
288 suspend; then it loads stuff into R and goes about its business. The
289 setjmp call saves (some of) the current registers, including R, which
290 no longer contains X. (This isn't a problem for a normal
291 setjmp/longjmp situation, where longjmp would be called before
292 setjmp's caller returns; the old value for X would be loaded back from
293 the stack after the longjmp, before the function returned.)
294
295 So, suspend returns, loading X back into R (and invalidating the jump
296 buffer) in the process. The caller foo then goes off and calls a
297 bunch of other functions out of Guile mode, occasionally storing X on
298 the stack again, but, say, much deeper on the stack than suspend's
299 stack frame went, and the stack slot where suspend had written X has
300 long since been overwritten with other values.
301
302 Okay, nothing actively broken so far. Now, let garbage collection
303 run, triggered by another thread.
304
305 The thread calling foo is out of Guile mode at the time, so the
306 garbage collector just scans a range of stack addresses. Too bad that
307 X isn't stored there. So the pointed-to storage goes onto the free
308 list, and I think you can see where things go from there.
309
310 Is there anything I'm missing that'll prevent this scenario from
311 happening? I mean, aside from, "well, suspend and scm_leave_guile
312 don't have many local variables, so they probably won't need to save
313 any registers on most systems, so we hope everything will wind up in
314 the jump buffer and we'll just get away with it"?
315
316 (And, going the other direction, if scm_leave_guile and suspend push
317 the stack pointer over onto a new page, and foo doesn't make further
318 function calls and thus the stack pointer no longer includes that
319 page, are we guaranteed that the kernel cannot release the now-unused
320 stack page that contains the top-of-stack pointer we just saved? I
321 don't know if any OS actually does that. If it does, we could get
322 faults in garbage collection.)
323
324 I don't think scm_without_guile has to have this problem, as it gets
325 more control over the stack handling -- but it should call setjmp
326 itself. I'd probably try something like:
327
328 // record top of stack for the GC
329 t->top = SCM_STACK_PTR (&t);
330 // save registers.
331 SCM_FLUSH_REGISTER_WINDOWS;
332 setjmp (t->regs);
333 res = func(data);
334 scm_enter_guile (t);
335
336 ... though even that's making some assumptions about the stack
337 ordering of local variables versus caller-saved registers.
338
339 For something like scm_leave_guile to work, I don't think it can just
340 rely on invalidated jump buffers. A valid jump buffer, and a handle
341 on the stack state at the point when the jump buffer was initialized,
342 together, would work fine, but I think then we're talking about macros
343 invoking setjmp in the caller's stack frame, and requiring that the
344 caller of scm_leave_guile also call scm_enter_guile before returning,
345 kind of like pthread_cleanup_push/pop calls that have to be paired up
346 in a function. (In fact, the pthread ones have to be paired up
347 syntactically, as if they might expand to a compound statement
348 incorporating the user's code, and invoking a compiler's
349 exception-handling primitives. Which might be something to think
350 about for cases where Guile is used with C++ exceptions or
351 pthread_cancel.)
352*/
353
9de87eea
MV
354scm_i_pthread_key_t scm_i_thread_key;
355
d823b11b 356static void
9de87eea 357resume (scm_i_thread *t)
d823b11b 358{
d823b11b 359 t->top = NULL;
9bc4701c
MD
360 if (t->clear_freelists_p)
361 {
362 *SCM_FREELIST_LOC (scm_i_freelist) = SCM_EOL;
363 *SCM_FREELIST_LOC (scm_i_freelist2) = SCM_EOL;
364 t->clear_freelists_p = 0;
365 }
d823b11b
MV
366}
367
98648121
MV
368typedef void* scm_t_guile_ticket;
369
370static void
9de87eea 371scm_enter_guile (scm_t_guile_ticket ticket)
d823b11b 372{
9de87eea
MV
373 scm_i_thread *t = (scm_i_thread *)ticket;
374 if (t)
375 {
376 scm_i_pthread_mutex_lock (&t->heap_mutex);
377 resume (t);
378 }
d823b11b
MV
379}
380
9de87eea
MV
381static scm_i_thread *
382suspend (void)
d823b11b 383{
9de87eea 384 scm_i_thread *t = SCM_I_CURRENT_THREAD;
d823b11b
MV
385
386 /* record top of stack for the GC */
9de87eea 387 t->top = SCM_STACK_PTR (&t);
d823b11b
MV
388 /* save registers. */
389 SCM_FLUSH_REGISTER_WINDOWS;
9de87eea
MV
390 setjmp (t->regs);
391 return t;
d823b11b
MV
392}
393
98648121 394static scm_t_guile_ticket
9de87eea 395scm_leave_guile ()
d823b11b 396{
9de87eea
MV
397 scm_i_thread *t = suspend ();
398 scm_i_pthread_mutex_unlock (&t->heap_mutex);
399 return (scm_t_guile_ticket) t;
d823b11b
MV
400}
401
9de87eea
MV
402static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZER;
403static scm_i_thread *all_threads = NULL;
404static int thread_count;
405
406static SCM scm_i_default_dynamic_state;
407
408/* Perform first stage of thread initialisation, in non-guile mode.
d823b11b 409 */
9de87eea
MV
410static void
411guilify_self_1 (SCM_STACKITEM *base)
d823b11b 412{
9de87eea
MV
413 scm_i_thread *t = malloc (sizeof (scm_i_thread));
414
415 t->pthread = scm_i_pthread_self ();
416 t->handle = SCM_BOOL_F;
417 t->result = SCM_BOOL_F;
418 t->join_queue = SCM_EOL;
419 t->dynamic_state = SCM_BOOL_F;
420 t->dynwinds = SCM_EOL;
421 t->active_asyncs = SCM_EOL;
9de87eea
MV
422 t->block_asyncs = 1;
423 t->pending_asyncs = 1;
424 t->last_debug_frame = NULL;
425 t->base = base;
0c97d7dd 426 t->continuation_root = SCM_EOL;
9de87eea
MV
427 t->continuation_base = base;
428 scm_i_pthread_cond_init (&t->sleep_cond, NULL);
429 t->sleep_mutex = NULL;
430 t->sleep_object = SCM_BOOL_F;
431 t->sleep_fd = -1;
0c97d7dd 432 /* XXX - check for errors. */
9de87eea
MV
433 pipe (t->sleep_pipe);
434 scm_i_pthread_mutex_init (&t->heap_mutex, NULL);
435 t->clear_freelists_p = 0;
1a8fdd7e 436 t->gc_running_p = 0;
9de87eea
MV
437 t->exited = 0;
438
439 t->freelist = SCM_EOL;
440 t->freelist2 = SCM_EOL;
441 SCM_SET_FREELIST_LOC (scm_i_freelist, &t->freelist);
442 SCM_SET_FREELIST_LOC (scm_i_freelist2, &t->freelist2);
443
444 scm_i_pthread_setspecific (scm_i_thread_key, t);
445
446 scm_i_pthread_mutex_lock (&t->heap_mutex);
447
448 scm_i_pthread_mutex_lock (&thread_admin_mutex);
449 t->next_thread = all_threads;
450 all_threads = t;
451 thread_count++;
452 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
d823b11b
MV
453}
454
9de87eea 455/* Perform second stage of thread initialisation, in guile mode.
d823b11b 456 */
9de87eea
MV
457static void
458guilify_self_2 (SCM parent)
d823b11b 459{
9de87eea
MV
460 scm_i_thread *t = SCM_I_CURRENT_THREAD;
461
462 SCM_NEWSMOB (t->handle, scm_tc16_thread, t);
463 scm_gc_register_collectable_memory (t, sizeof (scm_i_thread), "thread");
464 t->continuation_root = scm_cons (t->handle, SCM_EOL);
465 t->continuation_base = t->base;
466
467 if (scm_is_true (parent))
468 t->dynamic_state = scm_make_dynamic_state (parent);
469 else
470 t->dynamic_state = scm_i_make_initial_dynamic_state ();
471
472 t->join_queue = make_queue ();
473 t->block_asyncs = 0;
d823b11b
MV
474}
475
9de87eea 476/* Perform thread tear-down, in guile mode.
d823b11b 477 */
9de87eea
MV
478static void *
479do_thread_exit (void *v)
480{
0c97d7dd 481 scm_i_thread *t = (scm_i_thread *)v;
9de87eea
MV
482
483 scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
484
485 t->exited = 1;
0c97d7dd
MV
486 close (t->sleep_pipe[0]);
487 close (t->sleep_pipe[1]);
9de87eea
MV
488 while (scm_is_true (unblock_from_queue (t->join_queue)))
489 ;
9de87eea
MV
490
491 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
492 return NULL;
493}
494
d823b11b 495static void
9de87eea 496on_thread_exit (void *v)
d823b11b 497{
29776e85 498 /* This handler is executed in non-guile mode. */
0c97d7dd
MV
499 scm_i_thread *t = (scm_i_thread *)v, **tp;
500
9de87eea 501 scm_i_pthread_setspecific (scm_i_thread_key, v);
0c97d7dd
MV
502
503 /* Unblocking the joining threads needs to happen in guile mode
29776e85 504 since the queue is a SCM data structure. */
9de87eea 505 scm_with_guile (do_thread_exit, v);
0c97d7dd
MV
506
507 /* Removing ourself from the list of all threads needs to happen in
508 non-guile mode since all SCM values on our stack become
29776e85 509 unprotected once we are no longer in the list. */
0c97d7dd
MV
510 scm_i_pthread_mutex_lock (&thread_admin_mutex);
511 for (tp = &all_threads; *tp; tp = &(*tp)->next_thread)
512 if (*tp == t)
513 {
514 *tp = t->next_thread;
515 break;
516 }
517 thread_count--;
518 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
519
9de87eea 520 scm_i_pthread_setspecific (scm_i_thread_key, NULL);
d823b11b
MV
521}
522
9de87eea 523static scm_i_pthread_once_t init_thread_key_once = SCM_I_PTHREAD_ONCE_INIT;
d823b11b 524
9de87eea
MV
525static void
526init_thread_key (void)
527{
528 scm_i_pthread_key_create (&scm_i_thread_key, on_thread_exit);
529}
d823b11b 530
9de87eea
MV
531/* Perform any initializations necessary to bring the current thread
532 into guile mode, initializing Guile itself, if necessary.
a54a94b3 533
9de87eea
MV
534 BASE is the stack base to use with GC.
535
536 PARENT is the dynamic state to use as the parent, ot SCM_BOOL_F in
537 which case the default dynamic state is used.
538
539 Return zero when the thread was in guile mode already; otherwise
540 return 1.
541*/
542
543static int
544scm_i_init_thread_for_guile (SCM_STACKITEM *base, SCM parent)
d823b11b 545{
9de87eea
MV
546 scm_i_thread *t;
547
548 scm_i_pthread_once (&init_thread_key_once, init_thread_key);
549
550 if ((t = SCM_I_CURRENT_THREAD) == NULL)
551 {
552 /* This thread has not been guilified yet.
553 */
554
555 scm_i_pthread_mutex_lock (&scm_i_init_mutex);
556 if (scm_initialized_p == 0)
557 {
558 /* First thread ever to enter Guile. Run the full
559 initialization.
560 */
561 scm_i_init_guile (base);
562 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
563 }
564 else
565 {
566 /* Guile is already initialized, but this thread enters it for
567 the first time. Only initialize this thread.
568 */
569 scm_i_pthread_mutex_unlock (&scm_i_init_mutex);
570 guilify_self_1 (base);
571 guilify_self_2 (parent);
572 }
573 return 1;
574 }
575 else if (t->top)
576 {
577 /* This thread is already guilified but not in guile mode, just
578 resume it.
579
580 XXX - base might be lower than when this thread was first
581 guilified.
582 */
583 scm_enter_guile ((scm_t_guile_ticket) t);
584 return 1;
585 }
586 else
587 {
588 /* Thread is already in guile mode. Nothing to do.
589 */
590 return 0;
591 }
d823b11b
MV
592}
593
9de87eea 594#if SCM_USE_PTHREAD_THREADS
9de87eea 595
23d72566
KR
596#if HAVE_PTHREAD_ATTR_GETSTACK && HAVE_PTHREAD_GETATTR_NP
597/* This method for GNU/Linux and perhaps some other systems.
598 It's not for MacOS X or Solaris 10, since pthread_getattr_np is not
599 available on them. */
9de87eea
MV
600#define HAVE_GET_THREAD_STACK_BASE
601
602static SCM_STACKITEM *
603get_thread_stack_base ()
d823b11b 604{
9de87eea
MV
605 pthread_attr_t attr;
606 void *start, *end;
607 size_t size;
608
9de87eea
MV
609 pthread_getattr_np (pthread_self (), &attr);
610 pthread_attr_getstack (&attr, &start, &size);
611 end = (char *)start + size;
612
2b829bbb
KR
613 /* XXX - pthread_getattr_np from LinuxThreads does not seem to work
614 for the main thread, but we can use scm_get_stack_base in that
615 case.
616 */
617
618#ifndef PTHREAD_ATTR_GETSTACK_WORKS
9de87eea 619 if ((void *)&attr < start || (void *)&attr >= end)
2b829bbb 620 return scm_get_stack_base ();
9de87eea 621 else
2b829bbb 622#endif
9de87eea
MV
623 {
624#if SCM_STACK_GROWS_UP
625 return start;
626#else
627 return end;
628#endif
629 }
a54a94b3
MV
630}
631
23d72566
KR
632#elif HAVE_PTHREAD_GET_STACKADDR_NP
633/* This method for MacOS X.
634 It'd be nice if there was some documentation on pthread_get_stackaddr_np,
635 but as of 2006 there's nothing obvious at apple.com. */
636#define HAVE_GET_THREAD_STACK_BASE
637static SCM_STACKITEM *
638get_thread_stack_base ()
639{
640 return pthread_get_stackaddr_np (pthread_self ());
641}
642
643#elif defined (__MINGW32__)
644/* This method for mingw. In mingw the basic scm_get_stack_base can be used
645 in any thread. We don't like hard-coding the name of a system, but there
646 doesn't seem to be a cleaner way of knowing scm_get_stack_base can
647 work. */
648#define HAVE_GET_THREAD_STACK_BASE
649static SCM_STACKITEM *
650get_thread_stack_base ()
651{
652 return scm_get_stack_base ();
653}
654
655#endif /* pthread methods of get_thread_stack_base */
9de87eea
MV
656
657#else /* !SCM_USE_PTHREAD_THREADS */
658
659#define HAVE_GET_THREAD_STACK_BASE
660
661static SCM_STACKITEM *
662get_thread_stack_base ()
a54a94b3 663{
2b829bbb 664 return scm_get_stack_base ();
d823b11b
MV
665}
666
9de87eea 667#endif /* !SCM_USE_PTHREAD_THREADS */
9de87eea
MV
668
669#ifdef HAVE_GET_THREAD_STACK_BASE
670
671void
672scm_init_guile ()
d823b11b 673{
9de87eea
MV
674 scm_i_init_thread_for_guile (get_thread_stack_base (),
675 scm_i_default_dynamic_state);
d823b11b
MV
676}
677
9de87eea
MV
678#endif
679
680void *
681scm_with_guile (void *(*func)(void *), void *data)
682{
683 return scm_i_with_guile_and_parent (func, data,
684 scm_i_default_dynamic_state);
685}
686
687void *
688scm_i_with_guile_and_parent (void *(*func)(void *), void *data,
689 SCM parent)
690{
691 void *res;
692 int really_entered;
693 SCM_STACKITEM base_item;
694 really_entered = scm_i_init_thread_for_guile (&base_item, parent);
695 res = scm_c_with_continuation_barrier (func, data);
696 if (really_entered)
697 scm_leave_guile ();
698 return res;
699}
700
701void *
702scm_without_guile (void *(*func)(void *), void *data)
d823b11b 703{
9de87eea
MV
704 void *res;
705 scm_t_guile_ticket t;
706 t = scm_leave_guile ();
707 res = func (data);
708 scm_enter_guile (t);
709 return res;
710}
711
712/*** Thread creation */
713
714typedef struct {
715 SCM parent;
716 SCM thunk;
717 SCM handler;
76da80e7 718 SCM thread;
9de87eea
MV
719 scm_i_pthread_mutex_t mutex;
720 scm_i_pthread_cond_t cond;
721} launch_data;
d823b11b 722
9de87eea
MV
723static void *
724really_launch (void *d)
725{
726 launch_data *data = (launch_data *)d;
727 SCM thunk = data->thunk, handler = data->handler;
728 scm_i_thread *t;
d823b11b 729
9de87eea 730 t = SCM_I_CURRENT_THREAD;
a54a94b3 731
9de87eea
MV
732 scm_i_scm_pthread_mutex_lock (&data->mutex);
733 data->thread = scm_current_thread ();
734 scm_i_pthread_cond_signal (&data->cond);
735 scm_i_pthread_mutex_unlock (&data->mutex);
736
737 if (SCM_UNBNDP (handler))
738 t->result = scm_call_0 (thunk);
739 else
740 t->result = scm_catch (SCM_BOOL_T, thunk, handler);
741
742 return 0;
d823b11b
MV
743}
744
9de87eea
MV
745static void *
746launch_thread (void *d)
747{
748 launch_data *data = (launch_data *)d;
749 scm_i_pthread_detach (scm_i_pthread_self ());
750 scm_i_with_guile_and_parent (really_launch, d, data->parent);
751 return NULL;
752}
753
754SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 1, 1, 0,
d823b11b 755 (SCM thunk, SCM handler),
9de87eea
MV
756 "Call @code{thunk} in a new thread and with a new dynamic state,\n"
757 "returning a new thread object representing the thread. The procedure\n"
758 "@var{thunk} is called via @code{with-continuation-barrier}.\n"
759 "\n"
760 "When @var{handler} is specified, then @var{thunk} is called from\n"
761 "within a @code{catch} with tag @code{#t} that has @var{handler} as its\n"
762 "handler. This catch is established inside the continuation barrier.\n"
763 "\n"
764 "Once @var{thunk} or @var{handler} returns, the return value is made\n"
765 "the @emph{exit value} of the thread and the thread is terminated.")
d823b11b
MV
766#define FUNC_NAME s_scm_call_with_new_thread
767{
9de87eea
MV
768 launch_data data;
769 scm_i_pthread_t id;
770 int err;
d823b11b 771
9de87eea
MV
772 SCM_ASSERT (scm_is_true (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
773 SCM_ASSERT (SCM_UNBNDP (handler) || scm_is_true (scm_procedure_p (handler)),
774 handler, SCM_ARG2, FUNC_NAME);
775
776 data.parent = scm_current_dynamic_state ();
777 data.thunk = thunk;
778 data.handler = handler;
779 data.thread = SCM_BOOL_F;
780 scm_i_pthread_mutex_init (&data.mutex, NULL);
781 scm_i_pthread_cond_init (&data.cond, NULL);
782
783 scm_i_scm_pthread_mutex_lock (&data.mutex);
784 err = scm_i_pthread_create (&id, NULL, launch_thread, &data);
785 if (err)
786 {
787 scm_i_pthread_mutex_unlock (&data.mutex);
788 errno = err;
789 scm_syserror (NULL);
790 }
791 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
792 scm_i_pthread_mutex_unlock (&data.mutex);
793
794 return data.thread;
d823b11b
MV
795}
796#undef FUNC_NAME
797
9de87eea
MV
798typedef struct {
799 SCM parent;
800 scm_t_catch_body body;
801 void *body_data;
802 scm_t_catch_handler handler;
803 void *handler_data;
804 SCM thread;
805 scm_i_pthread_mutex_t mutex;
806 scm_i_pthread_cond_t cond;
807} spawn_data;
808
809static void *
810really_spawn (void *d)
811{
812 spawn_data *data = (spawn_data *)d;
813 scm_t_catch_body body = data->body;
814 void *body_data = data->body_data;
815 scm_t_catch_handler handler = data->handler;
816 void *handler_data = data->handler_data;
817 scm_i_thread *t = SCM_I_CURRENT_THREAD;
818
819 scm_i_scm_pthread_mutex_lock (&data->mutex);
820 data->thread = scm_current_thread ();
821 scm_i_pthread_cond_signal (&data->cond);
822 scm_i_pthread_mutex_unlock (&data->mutex);
823
824 if (handler == NULL)
825 t->result = body (body_data);
826 else
827 t->result = scm_internal_catch (SCM_BOOL_T,
828 body, body_data,
829 handler, handler_data);
830
831 return 0;
832}
833
834static void *
835spawn_thread (void *d)
836{
837 spawn_data *data = (spawn_data *)d;
838 scm_i_pthread_detach (scm_i_pthread_self ());
839 scm_i_with_guile_and_parent (really_spawn, d, data->parent);
840 return NULL;
841}
842
843SCM
844scm_spawn_thread (scm_t_catch_body body, void *body_data,
845 scm_t_catch_handler handler, void *handler_data)
846{
847 spawn_data data;
848 scm_i_pthread_t id;
849 int err;
850
851 data.parent = scm_current_dynamic_state ();
852 data.body = body;
853 data.body_data = body_data;
854 data.handler = handler;
855 data.handler_data = handler_data;
856 data.thread = SCM_BOOL_F;
857 scm_i_pthread_mutex_init (&data.mutex, NULL);
858 scm_i_pthread_cond_init (&data.cond, NULL);
859
860 scm_i_scm_pthread_mutex_lock (&data.mutex);
861 err = scm_i_pthread_create (&id, NULL, spawn_thread, &data);
862 if (err)
863 {
864 scm_i_pthread_mutex_unlock (&data.mutex);
865 errno = err;
866 scm_syserror (NULL);
867 }
868 scm_i_scm_pthread_cond_wait (&data.cond, &data.mutex);
869 scm_i_pthread_mutex_unlock (&data.mutex);
870
871 return data.thread;
872}
873
29717c89
MD
874SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
875 (),
876"Move the calling thread to the end of the scheduling queue.")
877#define FUNC_NAME s_scm_yield
878{
9de87eea 879 return scm_from_bool (scm_i_sched_yield ());
29717c89
MD
880}
881#undef FUNC_NAME
882
d823b11b 883SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
5f05c406 884 (SCM thread),
d823b11b
MV
885"Suspend execution of the calling thread until the target @var{thread} "
886"terminates, unless the target @var{thread} has already terminated. ")
887#define FUNC_NAME s_scm_join_thread
5f05c406 888{
9de87eea 889 scm_i_thread *t;
d823b11b
MV
890 SCM res;
891
892 SCM_VALIDATE_THREAD (1, thread);
9de87eea 893 if (scm_is_eq (scm_current_thread (), thread))
d823b11b
MV
894 SCM_MISC_ERROR ("can not join the current thread", SCM_EOL);
895
9de87eea
MV
896 scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
897
898 t = SCM_I_THREAD_DATA (thread);
d823b11b
MV
899 if (!t->exited)
900 {
9de87eea
MV
901 while (1)
902 {
903 block_self (t->join_queue, thread, &thread_admin_mutex, NULL);
904 if (t->exited)
905 break;
906 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
907 SCM_TICK;
908 scm_i_scm_pthread_mutex_lock (&thread_admin_mutex);
909 }
d823b11b
MV
910 }
911 res = t->result;
9de87eea
MV
912
913 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
d823b11b 914 return res;
5f05c406
MV
915}
916#undef FUNC_NAME
917
9de87eea 918/*** Fat mutexes */
4079f87e 919
d823b11b
MV
920/* We implement our own mutex type since we want them to be 'fair', we
921 want to do fancy things while waiting for them (like running
9de87eea
MV
922 asyncs) and we might want to add things that are nice for
923 debugging.
d823b11b 924*/
4079f87e 925
9de87eea
MV
926typedef struct {
927 scm_i_pthread_mutex_t lock;
d823b11b 928 SCM owner;
9de87eea
MV
929 int level; /* how much the owner owns us.
930 < 0 for non-recursive mutexes */
931 SCM waiting; /* the threads waiting for this mutex. */
932} fat_mutex;
933
934#define SCM_MUTEXP(x) SCM_SMOB_PREDICATE (scm_tc16_mutex, x)
935#define SCM_MUTEX_DATA(x) ((fat_mutex *) SCM_SMOB_DATA (x))
5f05c406 936
d823b11b 937static SCM
9de87eea 938fat_mutex_mark (SCM mx)
d823b11b 939{
9de87eea 940 fat_mutex *m = SCM_MUTEX_DATA (mx);
d823b11b
MV
941 scm_gc_mark (m->owner);
942 return m->waiting;
943}
4079f87e 944
9de87eea
MV
945static size_t
946fat_mutex_free (SCM mx)
76da80e7 947{
9de87eea
MV
948 fat_mutex *m = SCM_MUTEX_DATA (mx);
949 scm_i_pthread_mutex_destroy (&m->lock);
950 scm_gc_free (m, sizeof (fat_mutex), "mutex");
76da80e7
MV
951 return 0;
952}
953
954static int
9de87eea 955fat_mutex_print (SCM mx, SCM port, scm_print_state *pstate SCM_UNUSED)
76da80e7 956{
9de87eea
MV
957 fat_mutex *m = SCM_MUTEX_DATA (mx);
958 scm_puts ("#<mutex ", port);
959 scm_uintprint ((scm_t_bits)m, 16, port);
960 scm_puts (">", port);
961 return 1;
76da80e7
MV
962}
963
76da80e7 964static SCM
9de87eea 965make_fat_mutex (int recursive)
76da80e7 966{
9de87eea
MV
967 fat_mutex *m;
968 SCM mx;
969
970 m = scm_gc_malloc (sizeof (fat_mutex), "mutex");
971 scm_i_pthread_mutex_init (&m->lock, NULL);
972 m->owner = SCM_BOOL_F;
973 m->level = recursive? 0 : -1;
974 m->waiting = SCM_EOL;
975 SCM_NEWSMOB (mx, scm_tc16_mutex, (scm_t_bits) m);
976 m->waiting = make_queue ();
977 return mx;
76da80e7
MV
978}
979
9de87eea 980SCM_DEFINE (scm_make_mutex, "make-mutex", 0, 0, 0,
76da80e7 981 (void),
9de87eea
MV
982 "Create a new mutex. ")
983#define FUNC_NAME s_scm_make_mutex
76da80e7 984{
9de87eea 985 return make_fat_mutex (0);
76da80e7
MV
986}
987#undef FUNC_NAME
988
9de87eea 989SCM_DEFINE (scm_make_recursive_mutex, "make-recursive-mutex", 0, 0, 0,
9bc4701c 990 (void),
9de87eea
MV
991 "Create a new recursive mutex. ")
992#define FUNC_NAME s_scm_make_recursive_mutex
9bc4701c 993{
9de87eea 994 return make_fat_mutex (1);
9bc4701c
MD
995}
996#undef FUNC_NAME
997
9de87eea
MV
998static char *
999fat_mutex_lock (SCM mutex)
1000{
1001 fat_mutex *m = SCM_MUTEX_DATA (mutex);
1002 SCM thread = scm_current_thread ();
1003 char *msg = NULL;
1004
1005 scm_i_scm_pthread_mutex_lock (&m->lock);
1006 if (scm_is_false (m->owner))
1007 m->owner = thread;
1008 else if (scm_is_eq (m->owner, thread))
1009 {
1010 if (m->level >= 0)
1011 m->level++;
1012 else
1013 msg = "mutex already locked by current thread";
1014 }
1015 else
1016 {
1017 while (1)
1018 {
1019 block_self (m->waiting, mutex, &m->lock, NULL);
1020 if (scm_is_eq (m->owner, thread))
1021 break;
1022 scm_i_pthread_mutex_unlock (&m->lock);
1023 SCM_TICK;
1024 scm_i_scm_pthread_mutex_lock (&m->lock);
1025 }
1026 }
1027 scm_i_pthread_mutex_unlock (&m->lock);
1028 return msg;
1029}
1030
9bc4701c
MD
1031SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
1032 (SCM mx),
1033"Lock @var{mutex}. If the mutex is already locked, the calling thread "
1034"blocks until the mutex becomes available. The function returns when "
1035"the calling thread owns the lock on @var{mutex}. Locking a mutex that "
1036"a thread already owns will succeed right away and will not block the "
1037"thread. That is, Guile's mutexes are @emph{recursive}. ")
1038#define FUNC_NAME s_scm_lock_mutex
1039{
9de87eea 1040 char *msg;
76da80e7 1041
b01532af 1042 SCM_VALIDATE_MUTEX (1, mx);
9de87eea
MV
1043 msg = fat_mutex_lock (mx);
1044 if (msg)
1045 scm_misc_error (NULL, msg, SCM_EOL);
76da80e7 1046 return SCM_BOOL_T;
9bc4701c 1047}
76da80e7 1048#undef FUNC_NAME
9bc4701c 1049
a4d106c7 1050void
661ae7ab 1051scm_dynwind_lock_mutex (SCM mutex)
a4d106c7 1052{
661ae7ab
MV
1053 scm_dynwind_unwind_handler_with_scm ((void(*)(SCM))scm_unlock_mutex, mutex,
1054 SCM_F_WIND_EXPLICITLY);
1055 scm_dynwind_rewind_handler_with_scm ((void(*)(SCM))scm_lock_mutex, mutex,
1056 SCM_F_WIND_EXPLICITLY);
a4d106c7
MV
1057}
1058
9de87eea
MV
1059static char *
1060fat_mutex_trylock (fat_mutex *m, int *resp)
1061{
1062 char *msg = NULL;
1063 SCM thread = scm_current_thread ();
1064
1065 *resp = 1;
1066 scm_i_pthread_mutex_lock (&m->lock);
1067 if (scm_is_false (m->owner))
1068 m->owner = thread;
1069 else if (scm_is_eq (m->owner, thread))
1070 {
1071 if (m->level >= 0)
1072 m->level++;
1073 else
1074 msg = "mutex already locked by current thread";
1075 }
1076 else
1077 *resp = 0;
1078 scm_i_pthread_mutex_unlock (&m->lock);
1079 return msg;
1080}
1081
9bc4701c 1082SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
ba1b7223 1083 (SCM mutex),
9bc4701c
MD
1084"Try to lock @var{mutex}. If the mutex is already locked by someone "
1085"else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
1086#define FUNC_NAME s_scm_try_mutex
1087{
9de87eea
MV
1088 char *msg;
1089 int res;
1090
ba1b7223 1091 SCM_VALIDATE_MUTEX (1, mutex);
9bc4701c 1092
ba1b7223 1093 msg = fat_mutex_trylock (SCM_MUTEX_DATA (mutex), &res);
9de87eea
MV
1094 if (msg)
1095 scm_misc_error (NULL, msg, SCM_EOL);
1096 return scm_from_bool (res);
1097}
1098#undef FUNC_NAME
76da80e7 1099
9de87eea
MV
1100static char *
1101fat_mutex_unlock (fat_mutex *m)
1102{
1103 char *msg = NULL;
1104
1105 scm_i_scm_pthread_mutex_lock (&m->lock);
1106 if (!scm_is_eq (m->owner, scm_current_thread ()))
9bc4701c 1107 {
9de87eea
MV
1108 if (scm_is_false (m->owner))
1109 msg = "mutex not locked";
1110 else
1111 msg = "mutex not locked by current thread";
9bc4701c 1112 }
9de87eea
MV
1113 else if (m->level > 0)
1114 m->level--;
1115 else
1116 m->owner = unblock_from_queue (m->waiting);
1117 scm_i_pthread_mutex_unlock (&m->lock);
1118
1119 return msg;
9bc4701c 1120}
9bc4701c
MD
1121
1122SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
1123 (SCM mx),
1124"Unlocks @var{mutex} if the calling thread owns the lock on "
1125"@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
1126"thread results in undefined behaviour. Once a mutex has been unlocked, "
1127"one thread blocked on @var{mutex} is awakened and grabs the mutex "
1128"lock. Every call to @code{lock-mutex} by this thread must be matched "
1129"with a call to @code{unlock-mutex}. Only the last call to "
1130"@code{unlock-mutex} will actually unlock the mutex. ")
1131#define FUNC_NAME s_scm_unlock_mutex
1132{
9de87eea 1133 char *msg;
9bc4701c
MD
1134 SCM_VALIDATE_MUTEX (1, mx);
1135
9de87eea
MV
1136 msg = fat_mutex_unlock (SCM_MUTEX_DATA (mx));
1137 if (msg)
1138 scm_misc_error (NULL, msg, SCM_EOL);
9bc4701c
MD
1139 return SCM_BOOL_T;
1140}
1141#undef FUNC_NAME
1142
9de87eea
MV
1143#if 0
1144
1145SCM_DEFINE (scm_mutex_owner, "mutex-owner", 1, 0, 0,
1146 (SCM mx),
1147 "Return the thread owning @var{mx}, or @code{#f}.")
1148#define FUNC_NAME s_scm_mutex_owner
1149{
1150 SCM_VALIDATE_MUTEX (1, mx);
1151 return (SCM_MUTEX_DATA(mx))->owner;
1152}
1153#undef FUNC_NAME
1154
1155SCM_DEFINE (scm_mutex_level, "mutex-level", 1, 0, 0,
1156 (SCM mx),
1157 "Return the lock level of a recursive mutex, or -1\n"
1158 "for a standard mutex.")
1159#define FUNC_NAME s_scm_mutex_level
1160{
1161 SCM_VALIDATE_MUTEX (1, mx);
1162 return scm_from_int (SCM_MUTEX_DATA(mx)->level);
1163}
1164#undef FUNC_NAME
1165
1166#endif
1167
1168/*** Fat condition variables */
1169
1170typedef struct {
1171 scm_i_pthread_mutex_t lock;
1172 SCM waiting; /* the threads waiting for this condition. */
1173} fat_cond;
1174
1175#define SCM_CONDVARP(x) SCM_SMOB_PREDICATE (scm_tc16_condvar, x)
1176#define SCM_CONDVAR_DATA(x) ((fat_cond *) SCM_SMOB_DATA (x))
1177
1178static SCM
1179fat_cond_mark (SCM cv)
1180{
1181 fat_cond *c = SCM_CONDVAR_DATA (cv);
1182 return c->waiting;
1183}
1184
1185static size_t
1186fat_cond_free (SCM mx)
1187{
1188 fat_cond *c = SCM_CONDVAR_DATA (mx);
1189 scm_i_pthread_mutex_destroy (&c->lock);
1190 scm_gc_free (c, sizeof (fat_cond), "condition-variable");
1191 return 0;
1192}
1193
1194static int
1195fat_cond_print (SCM cv, SCM port, scm_print_state *pstate SCM_UNUSED)
1196{
1197 fat_cond *c = SCM_CONDVAR_DATA (cv);
1198 scm_puts ("#<condition-variable ", port);
1199 scm_uintprint ((scm_t_bits)c, 16, port);
1200 scm_puts (">", port);
1201 return 1;
1202}
9bc4701c 1203
d823b11b
MV
1204SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
1205 (void),
1206 "Make a new condition variable.")
1207#define FUNC_NAME s_scm_make_condition_variable
5f05c406 1208{
9de87eea
MV
1209 fat_cond *c;
1210 SCM cv;
1211
1212 c = scm_gc_malloc (sizeof (fat_cond), "condition variable");
1213 scm_i_pthread_mutex_init (&c->lock, 0);
1214 c->waiting = SCM_EOL;
1215 SCM_NEWSMOB (cv, scm_tc16_condvar, (scm_t_bits) c);
1216 c->waiting = make_queue ();
d823b11b 1217 return cv;
5f05c406 1218}
d823b11b 1219#undef FUNC_NAME
5f05c406 1220
9de87eea
MV
1221static int
1222fat_cond_timedwait (SCM cond, SCM mutex,
1223 const scm_t_timespec *waittime)
1224{
1225 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1226 fat_cond *c = SCM_CONDVAR_DATA (cond);
1227 fat_mutex *m = SCM_MUTEX_DATA (mutex);
1228 const char *msg;
1229 int err = 0;
1230
1231 while (1)
1232 {
9de87eea
MV
1233 scm_i_scm_pthread_mutex_lock (&c->lock);
1234 msg = fat_mutex_unlock (m);
1235 t->block_asyncs++;
1236 if (msg == NULL)
1237 {
1238 err = block_self (c->waiting, cond, &c->lock, waittime);
1239 scm_i_pthread_mutex_unlock (&c->lock);
9de87eea
MV
1240 fat_mutex_lock (mutex);
1241 }
1242 else
1243 scm_i_pthread_mutex_unlock (&c->lock);
1244 t->block_asyncs--;
1245 scm_async_click ();
1246
9de87eea
MV
1247 if (msg)
1248 scm_misc_error (NULL, msg, SCM_EOL);
1249
1250 scm_remember_upto_here_2 (cond, mutex);
1251
1252 if (err == 0)
1253 return 1;
1254 if (err == ETIMEDOUT)
1255 return 0;
1256 if (err != EINTR)
1257 {
1258 errno = err;
1259 scm_syserror (NULL);
1260 }
1261 }
1262}
1263
d823b11b
MV
1264SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
1265 (SCM cv, SCM mx, SCM t),
1266"Wait until @var{cond-var} has been signalled. While waiting, "
1267"@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
1268"is locked again when this function returns. When @var{time} is given, "
1269"it specifies a point in time where the waiting should be aborted. It "
1270"can be either a integer as returned by @code{current-time} or a pair "
1271"as returned by @code{gettimeofday}. When the waiting is aborted the "
1272"mutex is locked and @code{#f} is returned. When the condition "
1273"variable is in fact signalled, the mutex is also locked and @code{#t} "
1274"is returned. ")
1275#define FUNC_NAME s_scm_timed_wait_condition_variable
5f05c406 1276{
9de87eea 1277 scm_t_timespec waittime, *waitptr = NULL;
d823b11b
MV
1278
1279 SCM_VALIDATE_CONDVAR (1, cv);
1280 SCM_VALIDATE_MUTEX (2, mx);
9bc4701c 1281
d823b11b
MV
1282 if (!SCM_UNBNDP (t))
1283 {
d2e53ed6 1284 if (scm_is_pair (t))
d823b11b 1285 {
9de87eea
MV
1286 waittime.tv_sec = scm_to_ulong (SCM_CAR (t));
1287 waittime.tv_nsec = scm_to_ulong (SCM_CAR (t)) * 1000;
d823b11b
MV
1288 }
1289 else
1290 {
9de87eea 1291 waittime.tv_sec = scm_to_ulong (t);
d823b11b
MV
1292 waittime.tv_nsec = 0;
1293 }
9de87eea 1294 waitptr = &waittime;
d823b11b
MV
1295 }
1296
9de87eea 1297 return scm_from_bool (fat_cond_timedwait (cv, mx, waitptr));
5f05c406 1298}
d823b11b 1299#undef FUNC_NAME
5f05c406 1300
9de87eea
MV
1301static void
1302fat_cond_signal (fat_cond *c)
1303{
9de87eea
MV
1304 scm_i_scm_pthread_mutex_lock (&c->lock);
1305 unblock_from_queue (c->waiting);
1306 scm_i_pthread_mutex_unlock (&c->lock);
1307}
1308
d823b11b
MV
1309SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
1310 (SCM cv),
1311 "Wake up one thread that is waiting for @var{cv}")
1312#define FUNC_NAME s_scm_signal_condition_variable
5f05c406 1313{
d823b11b 1314 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1315 fat_cond_signal (SCM_CONDVAR_DATA (cv));
d823b11b 1316 return SCM_BOOL_T;
5f05c406 1317}
d823b11b 1318#undef FUNC_NAME
5f05c406 1319
9de87eea
MV
1320static void
1321fat_cond_broadcast (fat_cond *c)
1322{
1323 scm_i_scm_pthread_mutex_lock (&c->lock);
1324 while (scm_is_true (unblock_from_queue (c->waiting)))
1325 ;
1326 scm_i_pthread_mutex_unlock (&c->lock);
1327}
1328
d823b11b
MV
1329SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
1330 (SCM cv),
1331 "Wake up all threads that are waiting for @var{cv}. ")
1332#define FUNC_NAME s_scm_broadcast_condition_variable
5f05c406 1333{
d823b11b 1334 SCM_VALIDATE_CONDVAR (1, cv);
9de87eea 1335 fat_cond_broadcast (SCM_CONDVAR_DATA (cv));
d823b11b 1336 return SCM_BOOL_T;
5f05c406 1337}
d823b11b 1338#undef FUNC_NAME
5f05c406 1339
d823b11b
MV
1340/*** Marking stacks */
1341
1342/* XXX - what to do with this? Do we need to handle this for blocked
1343 threads as well?
1344*/
1345#ifdef __ia64__
1346# define SCM_MARK_BACKING_STORE() do { \
1347 ucontext_t ctx; \
1348 SCM_STACKITEM * top, * bot; \
1349 getcontext (&ctx); \
1350 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
1351 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
1352 / sizeof (SCM_STACKITEM))); \
9a5fa6e9
NJ
1353 bot = (SCM_STACKITEM *) scm_ia64_register_backing_store_base (); \
1354 top = (SCM_STACKITEM *) scm_ia64_ar_bsp (&ctx); \
d823b11b
MV
1355 scm_mark_locations (bot, top - bot); } while (0)
1356#else
1357# define SCM_MARK_BACKING_STORE()
1358#endif
1359
1360void
1361scm_threads_mark_stacks (void)
5f05c406 1362{
9de87eea
MV
1363 scm_i_thread *t;
1364 for (t = all_threads; t; t = t->next_thread)
d823b11b 1365 {
9de87eea
MV
1366 /* Check that thread has indeed been suspended.
1367 */
1368 assert (t->top);
6087fad9 1369
9de87eea 1370 scm_gc_mark (t->handle);
6087fad9 1371
d028af45 1372#if SCM_STACK_GROWS_UP
9de87eea 1373 scm_mark_locations (t->base, t->top - t->base);
d823b11b 1374#else
9de87eea 1375 scm_mark_locations (t->top, t->base - t->top);
d823b11b 1376#endif
6087fad9
MV
1377 scm_mark_locations ((SCM_STACKITEM *) t->regs,
1378 ((size_t) sizeof(t->regs)
1379 / sizeof (SCM_STACKITEM)));
d823b11b 1380 }
59152722
MV
1381
1382 SCM_MARK_BACKING_STORE ();
5f05c406
MV
1383}
1384
d823b11b
MV
1385/*** Select */
1386
911782b7 1387int
9de87eea
MV
1388scm_std_select (int nfds,
1389 SELECT_TYPE *readfds,
1390 SELECT_TYPE *writefds,
1391 SELECT_TYPE *exceptfds,
1392 struct timeval *timeout)
1393{
1394 fd_set my_readfds;
1395 int res, eno, wakeup_fd;
1396 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1397 scm_t_guile_ticket ticket;
1398
1399 if (readfds == NULL)
1400 {
1401 FD_ZERO (&my_readfds);
1402 readfds = &my_readfds;
1403 }
1404
1405 while (scm_i_setup_sleep (t, SCM_BOOL_F, NULL, t->sleep_pipe[1]))
1406 SCM_TICK;
1407
1408 wakeup_fd = t->sleep_pipe[0];
1409 ticket = scm_leave_guile ();
1410 FD_SET (wakeup_fd, readfds);
1411 if (wakeup_fd >= nfds)
1412 nfds = wakeup_fd+1;
1413 res = select (nfds, readfds, writefds, exceptfds, timeout);
1414 t->sleep_fd = -1;
d823b11b 1415 eno = errno;
9de87eea
MV
1416 scm_enter_guile (ticket);
1417
1418 scm_i_reset_sleep (t);
1419
1420 if (res > 0 && FD_ISSET (wakeup_fd, readfds))
1421 {
1422 char dummy;
1423 read (wakeup_fd, &dummy, 1);
1424 FD_CLR (wakeup_fd, readfds);
1425 res -= 1;
1426 if (res == 0)
1427 {
1428 eno = EINTR;
1429 res = -1;
1430 }
1431 }
d823b11b
MV
1432 errno = eno;
1433 return res;
5f05c406
MV
1434}
1435
9de87eea 1436/* Convenience API for blocking while in guile mode. */
76da80e7 1437
9de87eea 1438#if SCM_USE_PTHREAD_THREADS
92e64b87 1439
9bc4701c 1440int
9de87eea 1441scm_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
9bc4701c 1442{
9de87eea
MV
1443 scm_t_guile_ticket t = scm_leave_guile ();
1444 int res = scm_i_pthread_mutex_lock (mutex);
1445 scm_enter_guile (t);
9bc4701c
MD
1446 return res;
1447}
1448
9de87eea 1449static void
2b829bbb 1450do_unlock (void *data)
28d52ebb 1451{
9de87eea 1452 scm_i_pthread_mutex_unlock ((scm_i_pthread_mutex_t *)data);
28d52ebb
MD
1453}
1454
1455void
661ae7ab 1456scm_dynwind_pthread_mutex_lock (scm_i_pthread_mutex_t *mutex)
28d52ebb 1457{
9de87eea 1458 scm_i_scm_pthread_mutex_lock (mutex);
2b829bbb 1459 scm_dynwind_unwind_handler (do_unlock, mutex, SCM_F_WIND_EXPLICITLY);
28d52ebb
MD
1460}
1461
9bc4701c 1462int
9de87eea 1463scm_pthread_cond_wait (scm_i_pthread_cond_t *cond, scm_i_pthread_mutex_t *mutex)
9bc4701c 1464{
9de87eea
MV
1465 scm_t_guile_ticket t = scm_leave_guile ();
1466 int res = scm_i_pthread_cond_wait (cond, mutex);
1467 scm_enter_guile (t);
9bc4701c
MD
1468 return res;
1469}
9bc4701c 1470
76da80e7 1471int
9de87eea
MV
1472scm_pthread_cond_timedwait (scm_i_pthread_cond_t *cond,
1473 scm_i_pthread_mutex_t *mutex,
1474 const scm_t_timespec *wt)
76da80e7 1475{
9de87eea
MV
1476 scm_t_guile_ticket t = scm_leave_guile ();
1477 int res = scm_i_pthread_cond_timedwait (cond, mutex, wt);
1478 scm_enter_guile (t);
1479 return res;
76da80e7
MV
1480}
1481
9de87eea 1482#endif
76da80e7 1483
d823b11b 1484unsigned long
9de87eea 1485scm_std_usleep (unsigned long usecs)
5f05c406 1486{
d823b11b
MV
1487 struct timeval tv;
1488 tv.tv_usec = usecs % 1000000;
1489 tv.tv_sec = usecs / 1000000;
9de87eea
MV
1490 scm_std_select (0, NULL, NULL, NULL, &tv);
1491 return tv.tv_sec * 1000000 + tv.tv_usec;
5f05c406
MV
1492}
1493
9de87eea
MV
1494unsigned int
1495scm_std_sleep (unsigned int secs)
6c214b62 1496{
d823b11b
MV
1497 struct timeval tv;
1498 tv.tv_usec = 0;
1499 tv.tv_sec = secs;
9de87eea 1500 scm_std_select (0, NULL, NULL, NULL, &tv);
d823b11b 1501 return tv.tv_sec;
6c214b62
MD
1502}
1503
d823b11b
MV
1504/*** Misc */
1505
1506SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1507 (void),
1508 "Return the thread that called this function.")
1509#define FUNC_NAME s_scm_current_thread
1510{
9de87eea 1511 return SCM_I_CURRENT_THREAD->handle;
d823b11b
MV
1512}
1513#undef FUNC_NAME
1514
9de87eea
MV
1515static SCM
1516scm_c_make_list (size_t n, SCM fill)
1517{
1518 SCM res = SCM_EOL;
1519 while (n-- > 0)
1520 res = scm_cons (fill, res);
1521 return res;
1522}
1523
d823b11b
MV
1524SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1525 (void),
1526 "Return a list of all threads.")
9bc4701c 1527#define FUNC_NAME s_scm_all_threads
d823b11b 1528{
9de87eea
MV
1529 /* We can not allocate while holding the thread_admin_mutex because
1530 of the way GC is done.
1531 */
1532 int n = thread_count;
1533 scm_i_thread *t;
1534 SCM list = scm_c_make_list (n, SCM_UNSPECIFIED), *l;
d823b11b 1535
9de87eea
MV
1536 scm_i_pthread_mutex_lock (&thread_admin_mutex);
1537 l = &list;
1538 for (t = all_threads; t && n > 0; t = t->next_thread)
1539 {
1540 SCM_SETCAR (*l, t->handle);
1541 l = SCM_CDRLOC (*l);
1542 n--;
1543 }
1544 *l = SCM_EOL;
1545 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
1546 return list;
d823b11b 1547}
9de87eea 1548#undef FUNC_NAME
d823b11b
MV
1549
1550SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1551 (SCM thread),
1552 "Return @code{#t} iff @var{thread} has exited.\n")
1553#define FUNC_NAME s_scm_thread_exited_p
1554{
7888309b 1555 return scm_from_bool (scm_c_thread_exited_p (thread));
d823b11b
MV
1556}
1557#undef FUNC_NAME
1558
911782b7 1559int
d823b11b
MV
1560scm_c_thread_exited_p (SCM thread)
1561#define FUNC_NAME s_scm_thread_exited_p
5f05c406 1562{
9de87eea 1563 scm_i_thread *t;
d823b11b 1564 SCM_VALIDATE_THREAD (1, thread);
9de87eea 1565 t = SCM_I_THREAD_DATA (thread);
d823b11b 1566 return t->exited;
5f05c406 1567}
d823b11b 1568#undef FUNC_NAME
5f05c406 1569
9de87eea 1570static scm_i_pthread_cond_t wake_up_cond;
9bc4701c 1571int scm_i_thread_go_to_sleep;
9bc4701c
MD
1572static int threads_initialized_p = 0;
1573
1574void
1575scm_i_thread_put_to_sleep ()
1576{
6087fad9 1577 if (threads_initialized_p)
9bc4701c 1578 {
9de87eea 1579 scm_i_thread *t;
6087fad9 1580
9de87eea
MV
1581 scm_leave_guile ();
1582 scm_i_pthread_mutex_lock (&thread_admin_mutex);
1583
0c97d7dd
MV
1584 /* Signal all threads to go to sleep
1585 */
1586 scm_i_thread_go_to_sleep = 1;
1587 for (t = all_threads; t; t = t->next_thread)
1588 scm_i_pthread_mutex_lock (&t->heap_mutex);
1589 scm_i_thread_go_to_sleep = 0;
9bc4701c
MD
1590 }
1591}
1592
b0dc3d71
MD
1593void
1594scm_i_thread_invalidate_freelists ()
1595{
9de87eea
MV
1596 /* thread_admin_mutex is already locked. */
1597
1598 scm_i_thread *t;
1599 for (t = all_threads; t; t = t->next_thread)
1600 if (t != SCM_I_CURRENT_THREAD)
1601 t->clear_freelists_p = 1;
b0dc3d71
MD
1602}
1603
9bc4701c
MD
1604void
1605scm_i_thread_wake_up ()
1606{
6087fad9 1607 if (threads_initialized_p)
9bc4701c 1608 {
9de87eea 1609 scm_i_thread *t;
9de87eea 1610
0c97d7dd
MV
1611 scm_i_pthread_cond_broadcast (&wake_up_cond);
1612 for (t = all_threads; t; t = t->next_thread)
1613 scm_i_pthread_mutex_unlock (&t->heap_mutex);
9de87eea
MV
1614 scm_i_pthread_mutex_unlock (&thread_admin_mutex);
1615 scm_enter_guile ((scm_t_guile_ticket) SCM_I_CURRENT_THREAD);
9bc4701c 1616 }
9bc4701c
MD
1617}
1618
1619void
1620scm_i_thread_sleep_for_gc ()
1621{
9de87eea
MV
1622 scm_i_thread *t = suspend ();
1623 scm_i_pthread_cond_wait (&wake_up_cond, &t->heap_mutex);
b0dc3d71 1624 resume (t);
9bc4701c
MD
1625}
1626
a4d106c7
MV
1627/* This mutex is used by SCM_CRITICAL_SECTION_START/END.
1628 */
d1138028 1629scm_i_pthread_mutex_t scm_i_critical_section_mutex;
a4d106c7
MV
1630int scm_i_critical_section_level = 0;
1631
661ae7ab 1632static SCM dynwind_critical_section_mutex;
a54a94b3 1633
9bc4701c 1634void
661ae7ab 1635scm_dynwind_critical_section (SCM mutex)
76da80e7 1636{
a4d106c7 1637 if (scm_is_false (mutex))
661ae7ab
MV
1638 mutex = dynwind_critical_section_mutex;
1639 scm_dynwind_lock_mutex (mutex);
1640 scm_dynwind_block_asyncs ();
9de87eea
MV
1641}
1642
1643/*** Initialization */
1644
1645scm_i_pthread_key_t scm_i_freelist, scm_i_freelist2;
1646scm_i_pthread_mutex_t scm_i_misc_mutex;
1647
d1138028
MV
1648#if SCM_USE_PTHREAD_THREADS
1649pthread_mutexattr_t scm_i_pthread_mutexattr_recursive[1];
1650#endif
1651
9de87eea
MV
1652void
1653scm_threads_prehistory (SCM_STACKITEM *base)
1654{
d1138028
MV
1655#if SCM_USE_PTHREAD_THREADS
1656 pthread_mutexattr_init (scm_i_pthread_mutexattr_recursive);
1657 pthread_mutexattr_settype (scm_i_pthread_mutexattr_recursive,
1658 PTHREAD_MUTEX_RECURSIVE);
1659#endif
1660
1661 scm_i_pthread_mutex_init (&scm_i_critical_section_mutex,
1662 scm_i_pthread_mutexattr_recursive);
9de87eea
MV
1663 scm_i_pthread_mutex_init (&scm_i_misc_mutex, NULL);
1664 scm_i_pthread_cond_init (&wake_up_cond, NULL);
9de87eea
MV
1665 scm_i_pthread_key_create (&scm_i_freelist, NULL);
1666 scm_i_pthread_key_create (&scm_i_freelist2, NULL);
1667
1668 guilify_self_1 (base);
9bc4701c
MD
1669}
1670
d823b11b
MV
1671scm_t_bits scm_tc16_thread;
1672scm_t_bits scm_tc16_mutex;
1673scm_t_bits scm_tc16_condvar;
7bfd3b9e 1674
7bfd3b9e 1675void
9de87eea 1676scm_init_threads ()
7bfd3b9e 1677{
9de87eea 1678 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_i_thread));
d823b11b
MV
1679 scm_set_smob_mark (scm_tc16_thread, thread_mark);
1680 scm_set_smob_print (scm_tc16_thread, thread_print);
1681 scm_set_smob_free (scm_tc16_thread, thread_free);
1682
9de87eea
MV
1683 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (fat_mutex));
1684 scm_set_smob_mark (scm_tc16_mutex, fat_mutex_mark);
1685 scm_set_smob_print (scm_tc16_mutex, fat_mutex_print);
1686 scm_set_smob_free (scm_tc16_mutex, fat_mutex_free);
9bc4701c 1687
9de87eea
MV
1688 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
1689 sizeof (fat_cond));
1690 scm_set_smob_mark (scm_tc16_condvar, fat_cond_mark);
1691 scm_set_smob_print (scm_tc16_condvar, fat_cond_print);
1692 scm_set_smob_free (scm_tc16_condvar, fat_cond_free);
d823b11b 1693
9de87eea
MV
1694 scm_i_default_dynamic_state = SCM_BOOL_F;
1695 guilify_self_2 (SCM_BOOL_F);
9bc4701c 1696 threads_initialized_p = 1;
a4d106c7 1697
661ae7ab 1698 dynwind_critical_section_mutex =
a4d106c7 1699 scm_permanent_object (scm_make_recursive_mutex ());
7bfd3b9e 1700}
89e00824 1701
5f05c406 1702void
9de87eea 1703scm_init_threads_default_dynamic_state ()
5f05c406 1704{
9de87eea
MV
1705 SCM state = scm_make_dynamic_state (scm_current_dynamic_state ());
1706 scm_i_default_dynamic_state = scm_permanent_object (state);
5f05c406
MV
1707}
1708
d823b11b 1709void
9de87eea 1710scm_init_thread_procs ()
d823b11b 1711{
9de87eea 1712#include "libguile/threads.x"
d823b11b
MV
1713}
1714
89e00824
ML
1715/*
1716 Local Variables:
1717 c-file-style: "gnu"
1718 End:
1719*/