* __scm.h (SCM_STACK_PTR): New macro. (Cast argument through
[bpt/guile.git] / libguile / threads.c
1 /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2003 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18
19 \f
20
21 /* This file implements nice Scheme level threads on top of the gastly
22 C level threads.
23 */
24
25 #include "libguile/_scm.h"
26
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <assert.h>
30 #include <sys/time.h>
31
32 #include "libguile/validate.h"
33 #include "libguile/root.h"
34 #include "libguile/eval.h"
35 #include "libguile/async.h"
36 #include "libguile/ports.h"
37 #include "libguile/threads.h"
38 #include "libguile/dynwind.h"
39 #include "libguile/iselect.h"
40
41 /*** Queues */
42
43 static SCM
44 make_queue ()
45 {
46 return scm_cons (SCM_EOL, SCM_EOL);
47 }
48
49 static SCM
50 enqueue (SCM q, SCM t)
51 {
52 SCM c = scm_cons (t, SCM_EOL);
53 if (SCM_NULLP (SCM_CDR (q)))
54 SCM_SETCDR (q, c);
55 else
56 SCM_SETCDR (SCM_CAR (q), c);
57 SCM_SETCAR (q, c);
58 return c;
59 }
60
61 static void
62 remqueue (SCM q, SCM c)
63 {
64 SCM p, prev = q;
65 for (p = SCM_CDR (q); !SCM_NULLP (p); p = SCM_CDR (p))
66 {
67 if (SCM_EQ_P (p, c))
68 {
69 if (SCM_EQ_P (c, SCM_CAR (q)))
70 SCM_SETCAR (q, SCM_CDR (c));
71 SCM_SETCDR (prev, SCM_CDR (c));
72 return;
73 }
74 prev = p;
75 }
76 abort ();
77 }
78
79 static SCM
80 dequeue (SCM q)
81 {
82 SCM c = SCM_CDR (q);
83 if (SCM_NULLP (c))
84 return SCM_BOOL_F;
85 else
86 {
87 SCM_SETCDR (q, SCM_CDR (c));
88 if (SCM_NULLP (SCM_CDR (q)))
89 SCM_SETCAR (q, SCM_EOL);
90 return SCM_CAR (c);
91 }
92 }
93
94 /*** Threads */
95
96 #define THREAD_INITIALIZED_P(t) (t->base != NULL)
97
98 struct scm_thread {
99
100 /* Blocking.
101 */
102 scm_t_cond sleep_cond;
103 struct scm_thread *next_waiting;
104
105 /* This mutex represents this threads right to access the heap.
106 That right can temporarily be taken away by the GC. */
107 scm_t_mutex heap_mutex;
108 int clear_freelists_p; /* set if GC was done while thread was asleep */
109
110 scm_root_state *root;
111 SCM handle;
112 scm_t_thread thread;
113 SCM result;
114 int exited;
115
116 /* For keeping track of the stack and registers. */
117 SCM_STACKITEM *base;
118 SCM_STACKITEM *top;
119 jmp_buf regs;
120
121 };
122
123 static SCM
124 make_thread (SCM creation_protects)
125 {
126 SCM z;
127 scm_thread *t;
128 z = scm_make_smob (scm_tc16_thread);
129 t = SCM_THREAD_DATA (z);
130 t->handle = z;
131 t->result = creation_protects;
132 t->base = NULL;
133 scm_i_plugin_cond_init (&t->sleep_cond, 0);
134 scm_i_plugin_mutex_init (&t->heap_mutex, &scm_i_plugin_mutex);
135 t->clear_freelists_p = 0;
136 t->exited = 0;
137 return z;
138 }
139
140 static void
141 init_thread_creatant (SCM thread,
142 SCM_STACKITEM *base)
143 {
144 scm_thread *t = SCM_THREAD_DATA (thread);
145 t->thread = scm_thread_self ();
146 t->base = base;
147 t->top = NULL;
148 }
149
150 static SCM
151 thread_mark (SCM obj)
152 {
153 scm_thread *t = SCM_THREAD_DATA (obj);
154 scm_gc_mark (t->result);
155 return t->root->handle; /* mark root-state of this thread */
156 }
157
158 static int
159 thread_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
160 {
161 scm_thread *t = SCM_THREAD_DATA (exp);
162 scm_puts ("#<thread ", port);
163 scm_intprint ((unsigned long)t->thread, 10, port);
164 scm_puts (" (", port);
165 scm_intprint ((unsigned long)t, 16, port);
166 scm_puts (")>", port);
167 return 1;
168 }
169
170 static size_t
171 thread_free (SCM obj)
172 {
173 scm_thread *t = SCM_THREAD_DATA (obj);
174 if (!t->exited)
175 abort ();
176 scm_gc_free (t, sizeof (*t), "thread");
177 return 0;
178 }
179
180 /*** Scheduling */
181
182 #define cur_thread (SCM_CURRENT_THREAD->handle)
183 scm_t_key scm_i_thread_key;
184 scm_t_key scm_i_root_state_key;
185
186 void
187 scm_i_set_thread_data (void *data)
188 {
189 scm_thread *t = SCM_CURRENT_THREAD;
190 scm_setspecific (scm_i_root_state_key, data);
191 t->root = (scm_root_state *)data;
192 }
193
194 static void
195 resume (scm_thread *t)
196 {
197 t->top = NULL;
198 if (t->clear_freelists_p)
199 {
200 *SCM_FREELIST_LOC (scm_i_freelist) = SCM_EOL;
201 *SCM_FREELIST_LOC (scm_i_freelist2) = SCM_EOL;
202 t->clear_freelists_p = 0;
203 }
204 }
205
206 void
207 scm_i_enter_guile (scm_thread *t)
208 {
209 scm_i_plugin_mutex_lock (&t->heap_mutex);
210 resume (t);
211 }
212
213 static scm_thread *
214 suspend ()
215 {
216 scm_thread *c = SCM_CURRENT_THREAD;
217
218 /* record top of stack for the GC */
219 c->top = SCM_STACK_PTR (&c);
220 /* save registers. */
221 SCM_FLUSH_REGISTER_WINDOWS;
222 setjmp (c->regs);
223
224 return c;
225 }
226
227 scm_thread *
228 scm_i_leave_guile ()
229 {
230 scm_thread *t = suspend ();
231 scm_i_plugin_mutex_unlock (&t->heap_mutex);
232 return t;
233 }
234
235 /* Put the current thread to sleep until it is explicitely unblocked.
236 */
237 static int
238 block ()
239 {
240 int err;
241 scm_thread *t = suspend ();
242 err = scm_i_plugin_cond_wait (&t->sleep_cond, &t->heap_mutex);
243 resume (t);
244 return err;
245 }
246
247 /* Put the current thread to sleep until it is explicitely unblocked
248 or until a signal arrives or until time AT (absolute time) is
249 reached. Return 0 when it has been unblocked; errno otherwise.
250 */
251 static int
252 timed_block (const scm_t_timespec *at)
253 {
254 int err;
255 scm_thread *t = suspend ();
256 err = scm_i_plugin_cond_timedwait (&t->sleep_cond, &t->heap_mutex, at);
257 resume (t);
258 return err;
259 }
260
261 /* Unblock a sleeping thread.
262 */
263 static void
264 unblock (scm_thread *t)
265 {
266 scm_i_plugin_cond_signal (&t->sleep_cond);
267 }
268
269 /*** Thread creation */
270
271 static scm_t_mutex thread_admin_mutex;
272 static SCM all_threads;
273 static int thread_count;
274
275 typedef struct launch_data {
276 SCM thread;
277 SCM rootcont;
278 scm_t_catch_body body;
279 void *body_data;
280 scm_t_catch_handler handler;
281 void *handler_data;
282 } launch_data;
283
284 static SCM
285 body_bootstrip (launch_data* data)
286 {
287 /* First save the new root continuation */
288 data->rootcont = scm_root->rootcont;
289 return (data->body) (data->body_data);
290 }
291
292 static SCM
293 handler_bootstrip (launch_data* data, SCM tag, SCM throw_args)
294 {
295 scm_root->rootcont = data->rootcont;
296 return (data->handler) (data->handler_data, tag, throw_args);
297 }
298
299 static void
300 really_launch (SCM_STACKITEM *base, launch_data *data)
301 {
302 SCM thread;
303 scm_thread *t;
304 thread = data->thread;
305 t = SCM_THREAD_DATA (thread);
306 SCM_FREELIST_CREATE (scm_i_freelist);
307 SCM_FREELIST_CREATE (scm_i_freelist2);
308 scm_setspecific (scm_i_thread_key, t);
309 scm_setspecific (scm_i_root_state_key, t->root);
310 scm_i_plugin_mutex_lock (&t->heap_mutex); /* ensure that we "own" the heap */
311 init_thread_creatant (thread, base); /* must own the heap */
312
313 data->rootcont = SCM_BOOL_F;
314 t->result =
315 scm_internal_cwdr ((scm_t_catch_body) body_bootstrip,
316 data,
317 (scm_t_catch_handler) handler_bootstrip,
318 data, base);
319 scm_i_leave_guile (); /* release the heap */
320 free (data);
321
322 scm_i_plugin_mutex_lock (&thread_admin_mutex);
323 all_threads = scm_delq_x (thread, all_threads);
324 t->exited = 1;
325 thread_count--;
326 /* detach before unlocking in order to not become joined when detached */
327 scm_thread_detach (t->thread);
328 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
329 }
330
331 static void *
332 launch_thread (void *p)
333 {
334 really_launch (SCM_STACK_PTR (&p), (launch_data *) p);
335 return 0;
336 }
337
338 static SCM
339 create_thread (scm_t_catch_body body, void *body_data,
340 scm_t_catch_handler handler, void *handler_data,
341 SCM protects)
342 {
343 SCM thread;
344
345 /* Make new thread. The first thing the new thread will do is to
346 lock guile_mutex. Thus, we can safely complete its
347 initialization after creating it. While the new thread starts,
348 all its data is protected via all_threads.
349 */
350
351 {
352 scm_t_thread th;
353 SCM root;
354 launch_data *data;
355 scm_thread *t;
356 int err;
357
358 /* Allocate thread locals. */
359 root = scm_make_root (scm_root->handle);
360 data = scm_malloc (sizeof (launch_data));
361
362 /* Make thread. */
363 thread = make_thread (protects);
364 data->thread = thread;
365 data->body = body;
366 data->body_data = body_data;
367 data->handler = handler;
368 data->handler_data = handler_data;
369 t = SCM_THREAD_DATA (thread);
370 /* must initialize root state pointer before the thread is linked
371 into all_threads */
372 t->root = SCM_ROOT_STATE (root);
373 /* disconnect from parent, to prevent remembering dead threads */
374 t->root->parent = SCM_BOOL_F;
375 /* start with an empty dynwind chain */
376 t->root->dynwinds = SCM_EOL;
377
378 /* In order to avoid the need of synchronization between parent
379 and child thread, we need to insert the child into all_threads
380 before creation. */
381 {
382 SCM new_threads = scm_cons (thread, SCM_BOOL_F); /* could cause GC */
383 scm_thread *parent = scm_i_leave_guile (); /* to prevent deadlock */
384 scm_i_plugin_mutex_lock (&thread_admin_mutex);
385 SCM_SETCDR (new_threads, all_threads);
386 all_threads = new_threads;
387 thread_count++;
388 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
389
390 scm_remember_upto_here_1 (root);
391
392 scm_i_enter_guile (parent);
393 }
394
395 err = scm_i_plugin_thread_create (&th, 0, launch_thread, (void *) data);
396 if (err != 0)
397 {
398 scm_i_plugin_mutex_lock (&thread_admin_mutex);
399 all_threads = scm_delq_x (thread, all_threads);
400 ((scm_thread *) SCM_THREAD_DATA(thread))->exited = 1;
401 thread_count--;
402 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
403 }
404
405 if (err)
406 {
407 errno = err;
408 scm_syserror ("create-thread");
409 }
410 }
411
412 return thread;
413 }
414
415 SCM_DEFINE (scm_call_with_new_thread, "call-with-new-thread", 2, 0, 0,
416 (SCM thunk, SCM handler),
417 "Evaluate @var{(thunk)} in a new thread, and new dynamic context, "
418 "returning a new thread object representing the thread. "
419 "If an error occurs during evaluation, call error-thunk, passing it an "
420 "error code describing the condition. "
421 "If this happens, the error-thunk is called outside the scope of the new "
422 "root -- it is called in the same dynamic context in which "
423 "with-new-thread was evaluated, but not in the callers thread. "
424 "All the evaluation rules for dynamic roots apply to threads.")
425 #define FUNC_NAME s_scm_call_with_new_thread
426 {
427 SCM_ASSERT (SCM_NFALSEP (scm_thunk_p (thunk)), thunk, SCM_ARG1, FUNC_NAME);
428 SCM_ASSERT (SCM_NFALSEP (scm_procedure_p (handler)), handler, SCM_ARG2,
429 FUNC_NAME);
430
431 return create_thread ((scm_t_catch_body) scm_call_0, thunk,
432 (scm_t_catch_handler) scm_apply_1, handler,
433 scm_cons (thunk, handler));
434 }
435 #undef FUNC_NAME
436
437 SCM_DEFINE (scm_yield, "yield", 0, 0, 0,
438 (),
439 "Move the calling thread to the end of the scheduling queue.")
440 #define FUNC_NAME s_scm_yield
441 {
442 return SCM_BOOL (scm_thread_yield);
443 }
444 #undef FUNC_NAME
445
446 SCM_DEFINE (scm_join_thread, "join-thread", 1, 0, 0,
447 (SCM thread),
448 "Suspend execution of the calling thread until the target @var{thread} "
449 "terminates, unless the target @var{thread} has already terminated. ")
450 #define FUNC_NAME s_scm_join_thread
451 {
452 scm_thread *t;
453 SCM res;
454
455 SCM_VALIDATE_THREAD (1, thread);
456 if (SCM_EQ_P (cur_thread, thread))
457 SCM_MISC_ERROR ("can not join the current thread", SCM_EOL);
458
459 t = SCM_THREAD_DATA (thread);
460 if (!t->exited)
461 {
462 scm_thread *c;
463 c = scm_i_leave_guile ();
464 while (!THREAD_INITIALIZED_P (t))
465 scm_i_plugin_thread_yield ();
466 scm_thread_join (t->thread, 0);
467 scm_i_enter_guile (c);
468 }
469 res = t->result;
470 t->result = SCM_BOOL_F;
471 return res;
472 }
473 #undef FUNC_NAME
474
475 /*** Fair mutexes */
476
477 /* We implement our own mutex type since we want them to be 'fair', we
478 want to do fancy things while waiting for them (like running
479 asyncs) and we want to support waiting on many things at once.
480 Also, we might add things that are nice for debugging.
481 */
482
483 typedef struct fair_mutex {
484 /* the thread currently owning the mutex, or SCM_BOOL_F. */
485 scm_t_mutex lock;
486 int lockedp;
487 SCM owner;
488 /* how much the owner owns us. */
489 int level;
490 /* the threads waiting for this mutex. */
491 SCM waiting;
492 } fair_mutex;
493
494 static SCM
495 fair_mutex_mark (SCM mx)
496 {
497 fair_mutex *m = SCM_MUTEX_DATA (mx);
498 scm_gc_mark (m->owner);
499 return m->waiting;
500 }
501
502 SCM_DEFINE (scm_make_fair_mutex, "make-fair-mutex", 0, 0, 0,
503 (void),
504 "Create a new fair mutex object. ")
505 #define FUNC_NAME s_scm_make_fair_mutex
506 {
507 SCM mx = scm_make_smob (scm_tc16_fair_mutex);
508 fair_mutex *m = SCM_MUTEX_DATA (mx);
509 scm_i_plugin_mutex_init (&m->lock, &scm_i_plugin_mutex);
510 m->lockedp = 0;
511 m->owner = SCM_BOOL_F;
512 m->level = 0;
513 m->waiting = make_queue ();
514 return mx;
515 }
516 #undef FUNC_NAME
517
518 static int
519 fair_mutex_lock (fair_mutex *m)
520 {
521 scm_i_plugin_mutex_lock (&m->lock);
522 #if 0
523 /* Need to wait if another thread is just temporarily unlocking.
524 This is happens very seldom and only when the other thread is
525 between scm_mutex_unlock and scm_i_plugin_mutex_lock below. */
526 while (m->lockedp)
527 SCM_TICK;
528 m->lockedp = 1;
529 #endif
530
531 if (m->owner == SCM_BOOL_F)
532 m->owner = cur_thread;
533 else if (m->owner == cur_thread)
534 m->level++;
535 else
536 {
537 while (1)
538 {
539 SCM c = enqueue (m->waiting, cur_thread);
540 int err;
541 /* Note: It's important that m->lock is never locked for
542 any longer amount of time since that could prevent GC */
543 scm_i_plugin_mutex_unlock (&m->lock);
544 err = block ();
545 if (m->owner == cur_thread)
546 return 0;
547 scm_i_plugin_mutex_lock (&m->lock);
548 remqueue (m->waiting, c);
549 scm_i_plugin_mutex_unlock (&m->lock);
550 if (err)
551 return err;
552 SCM_ASYNC_TICK;
553 scm_i_plugin_mutex_lock (&m->lock);
554 }
555 }
556 scm_i_plugin_mutex_unlock (&m->lock);
557 return 0;
558 }
559
560 static int
561 fair_mutex_trylock (fair_mutex *m)
562 {
563 scm_i_plugin_mutex_lock (&m->lock);
564 if (m->owner == SCM_BOOL_F)
565 m->owner = cur_thread;
566 else if (m->owner == cur_thread)
567 m->level++;
568 else
569 {
570 scm_i_plugin_mutex_unlock (&m->lock);
571 return EBUSY;
572 }
573 scm_i_plugin_mutex_unlock (&m->lock);
574 return 0;
575 }
576
577 static int
578 fair_mutex_unlock (fair_mutex *m)
579 {
580 scm_i_plugin_mutex_lock (&m->lock);
581 if (m->owner != cur_thread)
582 {
583 scm_i_plugin_mutex_unlock (&m->lock);
584 return EPERM;
585 }
586 else if (m->level > 0)
587 m->level--;
588 else
589 {
590 SCM next = dequeue (m->waiting);
591 if (!SCM_FALSEP (next))
592 {
593 m->owner = next;
594 unblock (SCM_THREAD_DATA (next));
595 }
596 else
597 m->owner = SCM_BOOL_F;
598 }
599 scm_i_plugin_mutex_unlock (&m->lock);
600 return 0;
601 }
602
603 /*** Fair condition variables */
604
605 /* Like mutexes, we implement our own condition variables using the
606 primitives above.
607 */
608
609 typedef struct fair_cond {
610 scm_t_mutex lock;
611 /* the threads waiting for this condition. */
612 SCM waiting;
613 } fair_cond;
614
615 static SCM
616 fair_cond_mark (SCM cv)
617 {
618 fair_cond *c = SCM_CONDVAR_DATA (cv);
619 return c->waiting;
620 }
621
622 SCM_DEFINE (scm_make_fair_condition_variable, "make-fair-condition-variable", 0, 0, 0,
623 (void),
624 "Make a new fair condition variable.")
625 #define FUNC_NAME s_scm_make_fair_condition_variable
626 {
627 SCM cv = scm_make_smob (scm_tc16_fair_condvar);
628 fair_cond *c = SCM_CONDVAR_DATA (cv);
629 scm_i_plugin_mutex_init (&c->lock, 0);
630 c->waiting = make_queue ();
631 return cv;
632 }
633 #undef FUNC_NAME
634
635 static int
636 fair_cond_timedwait (fair_cond *c,
637 fair_mutex *m,
638 const scm_t_timespec *waittime)
639 {
640 int err;
641 scm_i_plugin_mutex_lock (&c->lock);
642
643 while (1)
644 {
645 enqueue (c->waiting, cur_thread);
646 scm_i_plugin_mutex_unlock (&c->lock);
647 fair_mutex_unlock (m); /*fixme* - not thread safe */
648 if (waittime == NULL)
649 err = block ();
650 else
651 err = timed_block (waittime);
652 fair_mutex_lock (m);
653 if (err)
654 return err;
655 /* XXX - check whether we have been signalled. */
656 break;
657 }
658 return err;
659 }
660
661 static int
662 fair_cond_signal (fair_cond *c)
663 {
664 SCM th;
665 scm_i_plugin_mutex_lock (&c->lock);
666 if (!SCM_FALSEP (th = dequeue (c->waiting)))
667 unblock (SCM_THREAD_DATA (th));
668 scm_i_plugin_mutex_unlock (&c->lock);
669 return 0;
670 }
671
672 static int
673 fair_cond_broadcast (fair_cond *c)
674 {
675 SCM th;
676 scm_i_plugin_mutex_lock (&c->lock);
677 while (!SCM_FALSEP (th = dequeue (c->waiting)))
678 unblock (SCM_THREAD_DATA (th));
679 scm_i_plugin_mutex_unlock (&c->lock);
680 return 0;
681 }
682
683 /*** Mutexes */
684
685 SCM_DEFINE (scm_make_mutex, "make-mutex", 0, 0, 0,
686 (void),
687 "Create a new mutex object. ")
688 #define FUNC_NAME s_scm_make_mutex
689 {
690 SCM mx = scm_make_smob (scm_tc16_mutex);
691 scm_i_plugin_mutex_init (SCM_MUTEX_DATA (mx), &scm_i_plugin_mutex);
692 return mx;
693 }
694 #undef FUNC_NAME
695
696 /*fixme* change documentation */
697 SCM_DEFINE (scm_lock_mutex, "lock-mutex", 1, 0, 0,
698 (SCM mx),
699 "Lock @var{mutex}. If the mutex is already locked, the calling thread "
700 "blocks until the mutex becomes available. The function returns when "
701 "the calling thread owns the lock on @var{mutex}. Locking a mutex that "
702 "a thread already owns will succeed right away and will not block the "
703 "thread. That is, Guile's mutexes are @emph{recursive}. ")
704 #define FUNC_NAME s_scm_lock_mutex
705 {
706 int err;
707 SCM_VALIDATE_MUTEX (1, mx);
708
709 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
710 err = fair_mutex_lock (SCM_MUTEX_DATA (mx));
711 else
712 {
713 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
714 err = scm_mutex_lock (m);
715 }
716
717 if (err)
718 {
719 errno = err;
720 SCM_SYSERROR;
721 }
722 return SCM_BOOL_T;
723 }
724 #undef FUNC_NAME
725
726 SCM_DEFINE (scm_try_mutex, "try-mutex", 1, 0, 0,
727 (SCM mx),
728 "Try to lock @var{mutex}. If the mutex is already locked by someone "
729 "else, return @code{#f}. Else lock the mutex and return @code{#t}. ")
730 #define FUNC_NAME s_scm_try_mutex
731 {
732 int err;
733 SCM_VALIDATE_MUTEX (1, mx);
734
735 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
736 err = fair_mutex_trylock (SCM_MUTEX_DATA (mx));
737 else
738 {
739 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
740 err = scm_mutex_trylock (m);
741 }
742
743 if (err == EBUSY)
744 return SCM_BOOL_F;
745
746 if (err)
747 {
748 errno = err;
749 SCM_SYSERROR;
750 }
751
752 return SCM_BOOL_T;
753 }
754 #undef FUNC_NAME
755
756 SCM_DEFINE (scm_unlock_mutex, "unlock-mutex", 1, 0, 0,
757 (SCM mx),
758 "Unlocks @var{mutex} if the calling thread owns the lock on "
759 "@var{mutex}. Calling unlock-mutex on a mutex not owned by the current "
760 "thread results in undefined behaviour. Once a mutex has been unlocked, "
761 "one thread blocked on @var{mutex} is awakened and grabs the mutex "
762 "lock. Every call to @code{lock-mutex} by this thread must be matched "
763 "with a call to @code{unlock-mutex}. Only the last call to "
764 "@code{unlock-mutex} will actually unlock the mutex. ")
765 #define FUNC_NAME s_scm_unlock_mutex
766 {
767 int err;
768 SCM_VALIDATE_MUTEX (1, mx);
769
770 if (SCM_TYP16 (mx) == scm_tc16_fair_mutex)
771 {
772 err = fair_mutex_unlock (SCM_MUTEX_DATA (mx));
773 if (err == EPERM)
774 {
775 fair_mutex *m = SCM_MUTEX_DATA (mx);
776 if (m->owner != cur_thread)
777 {
778 if (m->owner == SCM_BOOL_F)
779 SCM_MISC_ERROR ("mutex not locked", SCM_EOL);
780 else
781 SCM_MISC_ERROR ("mutex not locked by this thread", SCM_EOL);
782 }
783 }
784 }
785 else
786 {
787 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
788 err = scm_mutex_unlock (m);
789 }
790
791 if (err)
792 {
793 errno = err;
794 SCM_SYSERROR;
795 }
796 return SCM_BOOL_T;
797 }
798 #undef FUNC_NAME
799
800 /*** Condition variables */
801
802 SCM_DEFINE (scm_make_condition_variable, "make-condition-variable", 0, 0, 0,
803 (void),
804 "Make a new condition variable.")
805 #define FUNC_NAME s_scm_make_condition_variable
806 {
807 SCM cv = scm_make_smob (scm_tc16_condvar);
808 scm_i_plugin_cond_init (SCM_CONDVAR_DATA (cv), 0);
809 return cv;
810 }
811 #undef FUNC_NAME
812
813 SCM_DEFINE (scm_timed_wait_condition_variable, "wait-condition-variable", 2, 1, 0,
814 (SCM cv, SCM mx, SCM t),
815 "Wait until @var{cond-var} has been signalled. While waiting, "
816 "@var{mutex} is atomically unlocked (as with @code{unlock-mutex}) and "
817 "is locked again when this function returns. When @var{time} is given, "
818 "it specifies a point in time where the waiting should be aborted. It "
819 "can be either a integer as returned by @code{current-time} or a pair "
820 "as returned by @code{gettimeofday}. When the waiting is aborted the "
821 "mutex is locked and @code{#f} is returned. When the condition "
822 "variable is in fact signalled, the mutex is also locked and @code{#t} "
823 "is returned. ")
824 #define FUNC_NAME s_scm_timed_wait_condition_variable
825 {
826 scm_t_timespec waittime;
827 int err;
828
829 SCM_VALIDATE_CONDVAR (1, cv);
830 SCM_VALIDATE_MUTEX (2, mx);
831 if (!((SCM_TYP16 (cv) == scm_tc16_condvar
832 && SCM_TYP16 (mx) == scm_tc16_mutex)
833 || (SCM_TYP16 (cv) == scm_tc16_fair_condvar
834 && SCM_TYP16 (mx) == scm_tc16_fair_mutex)))
835 SCM_MISC_ERROR ("Condition variable and mutex are of different kinds.",
836 SCM_EOL);
837
838 if (!SCM_UNBNDP (t))
839 {
840 if (SCM_CONSP (t))
841 {
842 SCM_VALIDATE_UINT_COPY (3, SCM_CAR (t), waittime.tv_sec);
843 SCM_VALIDATE_UINT_COPY (3, SCM_CDR (t), waittime.tv_nsec);
844 waittime.tv_nsec *= 1000;
845 }
846 else
847 {
848 SCM_VALIDATE_UINT_COPY (3, t, waittime.tv_sec);
849 waittime.tv_nsec = 0;
850 }
851 }
852
853 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
854 err = fair_cond_timedwait (SCM_CONDVAR_DATA (cv),
855 SCM_MUTEX_DATA (mx),
856 SCM_UNBNDP (t) ? NULL : &waittime);
857 else
858 {
859 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
860 scm_t_mutex *m = SCM_MUTEX_DATA (mx);
861 if (SCM_UNBNDP (t))
862 err = scm_cond_wait (c, m);
863 else
864 err = scm_cond_timedwait (c, m, &waittime);
865 }
866
867 if (err)
868 {
869 if (err == ETIMEDOUT)
870 return SCM_BOOL_F;
871 errno = err;
872 SCM_SYSERROR;
873 }
874 return SCM_BOOL_T;
875 }
876 #undef FUNC_NAME
877
878 SCM_DEFINE (scm_signal_condition_variable, "signal-condition-variable", 1, 0, 0,
879 (SCM cv),
880 "Wake up one thread that is waiting for @var{cv}")
881 #define FUNC_NAME s_scm_signal_condition_variable
882 {
883 SCM_VALIDATE_CONDVAR (1, cv);
884 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
885 fair_cond_signal (SCM_CONDVAR_DATA (cv));
886 else
887 {
888 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
889 scm_cond_signal (c);
890 }
891 return SCM_BOOL_T;
892 }
893 #undef FUNC_NAME
894
895 SCM_DEFINE (scm_broadcast_condition_variable, "broadcast-condition-variable", 1, 0, 0,
896 (SCM cv),
897 "Wake up all threads that are waiting for @var{cv}. ")
898 #define FUNC_NAME s_scm_broadcast_condition_variable
899 {
900 SCM_VALIDATE_CONDVAR (1, cv);
901 if (SCM_TYP16 (cv) == scm_tc16_fair_condvar)
902 fair_cond_broadcast (SCM_CONDVAR_DATA (cv));
903 else
904 {
905 scm_t_cond *c = SCM_CONDVAR_DATA (cv);
906 scm_cond_broadcast (c);
907 }
908 return SCM_BOOL_T;
909 }
910 #undef FUNC_NAME
911
912 /*** Marking stacks */
913
914 /* XXX - what to do with this? Do we need to handle this for blocked
915 threads as well?
916 */
917 #ifdef __ia64__
918 # define SCM_MARK_BACKING_STORE() do { \
919 ucontext_t ctx; \
920 SCM_STACKITEM * top, * bot; \
921 getcontext (&ctx); \
922 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
923 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
924 / sizeof (SCM_STACKITEM))); \
925 bot = (SCM_STACKITEM *) __libc_ia64_register_backing_store_base; \
926 top = (SCM_STACKITEM *) ctx.uc_mcontext.sc_ar_bsp; \
927 scm_mark_locations (bot, top - bot); } while (0)
928 #else
929 # define SCM_MARK_BACKING_STORE()
930 #endif
931
932 void
933 scm_threads_mark_stacks (void)
934 {
935 volatile SCM c;
936 for (c = all_threads; !SCM_NULLP (c); c = SCM_CDR (c))
937 {
938 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (c));
939 if (!THREAD_INITIALIZED_P (t))
940 {
941 /* Not fully initialized yet. */
942 continue;
943 }
944 if (t->top == NULL)
945 {
946 long stack_len;
947 #ifdef SCM_DEBUG
948 if (t->thread != scm_thread_self ())
949 abort ();
950 #endif
951 /* Active thread */
952 /* stack_len is long rather than sizet in order to guarantee
953 that &stack_len is long aligned */
954 #if SCM_STACK_GROWS_UP
955 stack_len = SCM_STACK_PTR (&t) - t->base;
956
957 /* Protect from the C stack. This must be the first marking
958 * done because it provides information about what objects
959 * are "in-use" by the C code. "in-use" objects are those
960 * for which the information about length and base address must
961 * remain usable. This requirement is stricter than a liveness
962 * requirement -- in particular, it constrains the implementation
963 * of scm_resizuve.
964 */
965 SCM_FLUSH_REGISTER_WINDOWS;
966 /* This assumes that all registers are saved into the jmp_buf */
967 setjmp (scm_save_regs_gc_mark);
968 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
969 ((size_t) sizeof scm_save_regs_gc_mark
970 / sizeof (SCM_STACKITEM)));
971
972 scm_mark_locations (((size_t) t->base,
973 (sizet) stack_len));
974 #else
975 stack_len = t->base - SCM_STACK_PTR (&t);
976
977 /* Protect from the C stack. This must be the first marking
978 * done because it provides information about what objects
979 * are "in-use" by the C code. "in-use" objects are those
980 * for which the information about length and base address must
981 * remain usable. This requirement is stricter than a liveness
982 * requirement -- in particular, it constrains the implementation
983 * of scm_resizuve.
984 */
985 SCM_FLUSH_REGISTER_WINDOWS;
986 /* This assumes that all registers are saved into the jmp_buf */
987 setjmp (scm_save_regs_gc_mark);
988 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
989 ((size_t) sizeof scm_save_regs_gc_mark
990 / sizeof (SCM_STACKITEM)));
991
992 scm_mark_locations (SCM_STACK_PTR (&t), stack_len);
993 #endif
994 }
995 else
996 {
997 /* Suspended thread */
998 #if SCM_STACK_GROWS_UP
999 long stack_len = t->top - t->base;
1000 scm_mark_locations (t->base, stack_len);
1001 #else
1002 long stack_len = t->base - t->top;
1003 scm_mark_locations (t->top, stack_len);
1004 #endif
1005 scm_mark_locations ((SCM_STACKITEM *) t->regs,
1006 ((size_t) sizeof(t->regs)
1007 / sizeof (SCM_STACKITEM)));
1008 }
1009 }
1010 }
1011
1012 /*** Select */
1013
1014 int
1015 scm_internal_select (int nfds,
1016 SELECT_TYPE *readfds,
1017 SELECT_TYPE *writefds,
1018 SELECT_TYPE *exceptfds,
1019 struct timeval *timeout)
1020 {
1021 int res, eno;
1022 scm_thread *c = scm_i_leave_guile ();
1023 res = scm_i_plugin_select (nfds, readfds, writefds, exceptfds, timeout);
1024 eno = errno;
1025 scm_i_enter_guile (c);
1026 SCM_ASYNC_TICK;
1027 errno = eno;
1028 return res;
1029 }
1030
1031 /* Low-level C API */
1032
1033 SCM
1034 scm_spawn_thread (scm_t_catch_body body, void *body_data,
1035 scm_t_catch_handler handler, void *handler_data)
1036 {
1037 return create_thread (body, body_data, handler, handler_data, SCM_BOOL_F);
1038 }
1039
1040 int
1041 scm_mutex_lock (scm_t_mutex *m)
1042 {
1043 scm_thread *t = scm_i_leave_guile ();
1044 int res = scm_i_plugin_mutex_lock (m);
1045 scm_i_enter_guile (t);
1046 return res;
1047 }
1048
1049 scm_t_rec_mutex *
1050 scm_make_rec_mutex ()
1051 {
1052 scm_t_rec_mutex *m = scm_malloc (sizeof (scm_t_rec_mutex));
1053 scm_i_plugin_rec_mutex_init (m, &scm_i_plugin_rec_mutex);
1054 return m;
1055 }
1056
1057 void
1058 scm_rec_mutex_free (scm_t_rec_mutex *m)
1059 {
1060 scm_i_plugin_rec_mutex_destroy (m);
1061 free (m);
1062 }
1063
1064 int
1065 scm_rec_mutex_lock (scm_t_rec_mutex *m)
1066 {
1067 scm_thread *t = scm_i_leave_guile ();
1068 int res = scm_i_plugin_rec_mutex_lock (m);
1069 scm_i_enter_guile (t);
1070 return res;
1071 }
1072
1073 int
1074 scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
1075 {
1076 scm_thread *t = scm_i_leave_guile ();
1077 scm_i_plugin_cond_wait (c, m);
1078 scm_i_enter_guile (t);
1079 return 0;
1080 }
1081
1082 int
1083 scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, const scm_t_timespec *wt)
1084 {
1085 scm_thread *t = scm_i_leave_guile ();
1086 int res = scm_i_plugin_cond_timedwait (c, m, wt);
1087 scm_i_enter_guile (t);
1088 return res;
1089 }
1090
1091 void
1092 scm_enter_guile ()
1093 {
1094 scm_i_enter_guile (SCM_CURRENT_THREAD);
1095 }
1096
1097 void
1098 scm_leave_guile ()
1099 {
1100 scm_i_leave_guile ();
1101 }
1102
1103 unsigned long
1104 scm_thread_usleep (unsigned long usecs)
1105 {
1106 struct timeval tv;
1107 tv.tv_usec = usecs % 1000000;
1108 tv.tv_sec = usecs / 1000000;
1109 scm_internal_select (0, NULL, NULL, NULL, &tv);
1110 return tv.tv_usec + tv.tv_sec*1000000;
1111 }
1112
1113 unsigned long
1114 scm_thread_sleep (unsigned long secs)
1115 {
1116 struct timeval tv;
1117 tv.tv_usec = 0;
1118 tv.tv_sec = secs;
1119 scm_internal_select (0, NULL, NULL, NULL, &tv);
1120 return tv.tv_sec;
1121 }
1122
1123 /*** Misc */
1124
1125 SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1126 (void),
1127 "Return the thread that called this function.")
1128 #define FUNC_NAME s_scm_current_thread
1129 {
1130 return cur_thread;
1131 }
1132 #undef FUNC_NAME
1133
1134 SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1135 (void),
1136 "Return a list of all threads.")
1137 #define FUNC_NAME s_scm_all_threads
1138 {
1139 return scm_list_copy (all_threads);
1140 }
1141 #undef FUNC_NAME
1142
1143 scm_root_state *
1144 scm_i_thread_root (SCM thread)
1145 {
1146 return ((scm_thread *) SCM_THREAD_DATA (thread))->root;
1147 }
1148
1149 SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1150 (SCM thread),
1151 "Return @code{#t} iff @var{thread} has exited.\n")
1152 #define FUNC_NAME s_scm_thread_exited_p
1153 {
1154 return SCM_BOOL (scm_c_thread_exited_p (thread));
1155 }
1156 #undef FUNC_NAME
1157
1158 int
1159 scm_c_thread_exited_p (SCM thread)
1160 #define FUNC_NAME s_scm_thread_exited_p
1161 {
1162 scm_thread *t;
1163 SCM_VALIDATE_THREAD (1, thread);
1164 t = SCM_THREAD_DATA (thread);
1165 return t->exited;
1166 }
1167 #undef FUNC_NAME
1168
1169 static scm_t_cond wake_up_cond;
1170 int scm_i_thread_go_to_sleep;
1171 static int gc_section_count = 0;
1172 static int threads_initialized_p = 0;
1173
1174 void
1175 scm_i_thread_put_to_sleep ()
1176 {
1177 if (threads_initialized_p && !gc_section_count++)
1178 {
1179 SCM threads;
1180 scm_i_plugin_mutex_lock (&thread_admin_mutex);
1181 threads = all_threads;
1182 /* Signal all threads to go to sleep */
1183 scm_i_thread_go_to_sleep = 1;
1184 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1185 if (SCM_CAR (threads) != cur_thread)
1186 {
1187 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1188 scm_i_plugin_mutex_lock (&t->heap_mutex);
1189 }
1190 scm_i_thread_go_to_sleep = 0;
1191 }
1192 }
1193
1194 void
1195 scm_i_thread_invalidate_freelists ()
1196 {
1197 /* Don't need to lock thread_admin_mutex here since we are single threaded */
1198 SCM threads = all_threads;
1199 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1200 if (SCM_CAR (threads) != cur_thread)
1201 {
1202 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1203 t->clear_freelists_p = 1;
1204 }
1205 }
1206
1207 void
1208 scm_i_thread_wake_up ()
1209 {
1210 if (threads_initialized_p && !--gc_section_count)
1211 {
1212 SCM threads;
1213 threads = all_threads;
1214 scm_i_plugin_cond_broadcast (&wake_up_cond);
1215 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1216 if (SCM_CAR (threads) != cur_thread)
1217 {
1218 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1219 scm_i_plugin_mutex_unlock (&t->heap_mutex);
1220 }
1221 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
1222 }
1223 }
1224
1225 void
1226 scm_i_thread_sleep_for_gc ()
1227 {
1228 scm_thread *t;
1229 t = suspend ();
1230 scm_i_plugin_cond_wait (&wake_up_cond, &t->heap_mutex);
1231 resume (t);
1232 }
1233
1234 scm_t_mutex scm_i_critical_section_mutex;
1235 scm_t_rec_mutex scm_i_defer_mutex;
1236
1237 #if SCM_USE_PTHREAD_THREADS
1238 # include "libguile/pthread-threads.c"
1239 #endif
1240 #include "libguile/threads-plugin.c"
1241
1242 /*** Initialization */
1243
1244 void
1245 scm_threads_prehistory ()
1246 {
1247 scm_thread *t;
1248 #if SCM_USE_PTHREAD_THREADS
1249 /* Must be called before any initialization of a mutex. */
1250 scm_init_pthread_threads ();
1251 #endif
1252 scm_i_plugin_mutex_init (&thread_admin_mutex, &scm_i_plugin_mutex);
1253 scm_i_plugin_cond_init (&wake_up_cond, 0);
1254 scm_i_plugin_mutex_init (&scm_i_critical_section_mutex, &scm_i_plugin_mutex);
1255 thread_count = 1;
1256 scm_i_plugin_key_create (&scm_i_thread_key, 0);
1257 scm_i_plugin_key_create (&scm_i_root_state_key, 0);
1258 scm_i_plugin_rec_mutex_init (&scm_i_defer_mutex, &scm_i_plugin_rec_mutex);
1259 /* Allocate a fake thread object to be used during bootup. */
1260 t = malloc (sizeof (scm_thread));
1261 t->base = NULL;
1262 t->clear_freelists_p = 0;
1263 scm_i_plugin_mutex_init (&t->heap_mutex, &scm_i_plugin_mutex);
1264 scm_setspecific (scm_i_thread_key, t);
1265 scm_i_enter_guile (t);
1266 }
1267
1268 scm_t_bits scm_tc16_thread;
1269 scm_t_bits scm_tc16_future;
1270 scm_t_bits scm_tc16_mutex;
1271 scm_t_bits scm_tc16_fair_mutex;
1272 scm_t_bits scm_tc16_condvar;
1273 scm_t_bits scm_tc16_fair_condvar;
1274
1275 void
1276 scm_init_threads (SCM_STACKITEM *base)
1277 {
1278 SCM thread;
1279 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_thread));
1280 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (scm_t_mutex));
1281 scm_tc16_fair_mutex = scm_make_smob_type ("fair-mutex",
1282 sizeof (fair_mutex));
1283 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
1284 sizeof (scm_t_cond));
1285 scm_tc16_fair_condvar = scm_make_smob_type ("fair-condition-variable",
1286 sizeof (fair_cond));
1287
1288 thread = make_thread (SCM_BOOL_F);
1289 /* Replace initial fake thread with a real thread object */
1290 free (SCM_CURRENT_THREAD);
1291 scm_setspecific (scm_i_thread_key, SCM_THREAD_DATA (thread));
1292 scm_i_enter_guile (SCM_CURRENT_THREAD);
1293
1294 /* root is set later from init.c */
1295 init_thread_creatant (thread, base);
1296 thread_count = 1;
1297 scm_gc_register_root (&all_threads);
1298 all_threads = scm_cons (thread, SCM_EOL);
1299
1300 scm_set_smob_mark (scm_tc16_thread, thread_mark);
1301 scm_set_smob_print (scm_tc16_thread, thread_print);
1302 scm_set_smob_free (scm_tc16_thread, thread_free);
1303
1304 scm_set_smob_mark (scm_tc16_fair_mutex, fair_mutex_mark);
1305
1306 scm_set_smob_mark (scm_tc16_fair_condvar, fair_cond_mark);
1307
1308 threads_initialized_p = 1;
1309 }
1310
1311 void
1312 scm_init_thread_procs ()
1313 {
1314 #include "libguile/threads.x"
1315 }
1316
1317 /* XXX */
1318
1319 void
1320 scm_init_iselect ()
1321 {
1322 }
1323
1324 /*
1325 Local Variables:
1326 c-file-style: "gnu"
1327 End:
1328 */