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