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