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