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