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