Changed license terms to the plain LGPL thru-out.
[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_STACKITEM *)&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_STACKITEM *)&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_STACKITEM *) (&t) -
956 (SCM_STACKITEM *) thread->base);
957
958 /* Protect from the C stack. This must be the first marking
959 * done because it provides information about what objects
960 * are "in-use" by the C code. "in-use" objects are those
961 * for which the information about length and base address must
962 * remain usable. This requirement is stricter than a liveness
963 * requirement -- in particular, it constrains the implementation
964 * of scm_resizuve.
965 */
966 SCM_FLUSH_REGISTER_WINDOWS;
967 /* This assumes that all registers are saved into the jmp_buf */
968 setjmp (scm_save_regs_gc_mark);
969 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
970 ((size_t) sizeof scm_save_regs_gc_mark
971 / sizeof (SCM_STACKITEM)));
972
973 scm_mark_locations (((size_t) t->base,
974 (sizet) stack_len));
975 #else
976 stack_len = ((SCM_STACKITEM *) t->base -
977 (SCM_STACKITEM *) (&t));
978
979 /* Protect from the C stack. This must be the first marking
980 * done because it provides information about what objects
981 * are "in-use" by the C code. "in-use" objects are those
982 * for which the information about length and base address must
983 * remain usable. This requirement is stricter than a liveness
984 * requirement -- in particular, it constrains the implementation
985 * of scm_resizuve.
986 */
987 SCM_FLUSH_REGISTER_WINDOWS;
988 /* This assumes that all registers are saved into the jmp_buf */
989 setjmp (scm_save_regs_gc_mark);
990 scm_mark_locations ((SCM_STACKITEM *) scm_save_regs_gc_mark,
991 ((size_t) sizeof scm_save_regs_gc_mark
992 / sizeof (SCM_STACKITEM)));
993
994 scm_mark_locations ((SCM_STACKITEM *) &t,
995 stack_len);
996 #endif
997 }
998 else
999 {
1000 /* Suspended thread */
1001 #if SCM_STACK_GROWS_UP
1002 long stack_len = t->top - t->base;
1003 scm_mark_locations (t->base, stack_len);
1004 #else
1005 long stack_len = t->base - t->top;
1006 scm_mark_locations (t->top, stack_len);
1007 #endif
1008 scm_mark_locations ((SCM_STACKITEM *) t->regs,
1009 ((size_t) sizeof(t->regs)
1010 / sizeof (SCM_STACKITEM)));
1011 }
1012 }
1013 }
1014
1015 /*** Select */
1016
1017 int
1018 scm_internal_select (int nfds,
1019 SELECT_TYPE *readfds,
1020 SELECT_TYPE *writefds,
1021 SELECT_TYPE *exceptfds,
1022 struct timeval *timeout)
1023 {
1024 int res, eno;
1025 scm_thread *c = scm_i_leave_guile ();
1026 res = scm_i_plugin_select (nfds, readfds, writefds, exceptfds, timeout);
1027 eno = errno;
1028 scm_i_enter_guile (c);
1029 SCM_ASYNC_TICK;
1030 errno = eno;
1031 return res;
1032 }
1033
1034 /* Low-level C API */
1035
1036 SCM
1037 scm_spawn_thread (scm_t_catch_body body, void *body_data,
1038 scm_t_catch_handler handler, void *handler_data)
1039 {
1040 return create_thread (body, body_data, handler, handler_data, SCM_BOOL_F);
1041 }
1042
1043 int
1044 scm_mutex_lock (scm_t_mutex *m)
1045 {
1046 scm_thread *t = scm_i_leave_guile ();
1047 int res = scm_i_plugin_mutex_lock (m);
1048 scm_i_enter_guile (t);
1049 return res;
1050 }
1051
1052 scm_t_rec_mutex *
1053 scm_make_rec_mutex ()
1054 {
1055 scm_t_rec_mutex *m = scm_malloc (sizeof (scm_t_rec_mutex));
1056 scm_i_plugin_rec_mutex_init (m, &scm_i_plugin_rec_mutex);
1057 return m;
1058 }
1059
1060 void
1061 scm_rec_mutex_free (scm_t_rec_mutex *m)
1062 {
1063 scm_i_plugin_rec_mutex_destroy (m);
1064 free (m);
1065 }
1066
1067 int
1068 scm_rec_mutex_lock (scm_t_rec_mutex *m)
1069 {
1070 scm_thread *t = scm_i_leave_guile ();
1071 int res = scm_i_plugin_rec_mutex_lock (m);
1072 scm_i_enter_guile (t);
1073 return res;
1074 }
1075
1076 int
1077 scm_cond_wait (scm_t_cond *c, scm_t_mutex *m)
1078 {
1079 scm_thread *t = scm_i_leave_guile ();
1080 scm_i_plugin_cond_wait (c, m);
1081 scm_i_enter_guile (t);
1082 return 0;
1083 }
1084
1085 int
1086 scm_cond_timedwait (scm_t_cond *c, scm_t_mutex *m, const scm_t_timespec *wt)
1087 {
1088 scm_thread *t = scm_i_leave_guile ();
1089 int res = scm_i_plugin_cond_timedwait (c, m, wt);
1090 scm_i_enter_guile (t);
1091 return res;
1092 }
1093
1094 void
1095 scm_enter_guile ()
1096 {
1097 scm_i_enter_guile (SCM_CURRENT_THREAD);
1098 }
1099
1100 void
1101 scm_leave_guile ()
1102 {
1103 scm_i_leave_guile ();
1104 }
1105
1106 unsigned long
1107 scm_thread_usleep (unsigned long usecs)
1108 {
1109 struct timeval tv;
1110 tv.tv_usec = usecs % 1000000;
1111 tv.tv_sec = usecs / 1000000;
1112 scm_internal_select (0, NULL, NULL, NULL, &tv);
1113 return tv.tv_usec + tv.tv_sec*1000000;
1114 }
1115
1116 unsigned long
1117 scm_thread_sleep (unsigned long secs)
1118 {
1119 struct timeval tv;
1120 tv.tv_usec = 0;
1121 tv.tv_sec = secs;
1122 scm_internal_select (0, NULL, NULL, NULL, &tv);
1123 return tv.tv_sec;
1124 }
1125
1126 /*** Misc */
1127
1128 SCM_DEFINE (scm_current_thread, "current-thread", 0, 0, 0,
1129 (void),
1130 "Return the thread that called this function.")
1131 #define FUNC_NAME s_scm_current_thread
1132 {
1133 return cur_thread;
1134 }
1135 #undef FUNC_NAME
1136
1137 SCM_DEFINE (scm_all_threads, "all-threads", 0, 0, 0,
1138 (void),
1139 "Return a list of all threads.")
1140 #define FUNC_NAME s_scm_all_threads
1141 {
1142 return scm_list_copy (all_threads);
1143 }
1144 #undef FUNC_NAME
1145
1146 scm_root_state *
1147 scm_i_thread_root (SCM thread)
1148 {
1149 return ((scm_thread *) SCM_THREAD_DATA (thread))->root;
1150 }
1151
1152 SCM_DEFINE (scm_thread_exited_p, "thread-exited?", 1, 0, 0,
1153 (SCM thread),
1154 "Return @code{#t} iff @var{thread} has exited.\n")
1155 #define FUNC_NAME s_scm_thread_exited_p
1156 {
1157 return SCM_BOOL (scm_c_thread_exited_p (thread));
1158 }
1159 #undef FUNC_NAME
1160
1161 int
1162 scm_c_thread_exited_p (SCM thread)
1163 #define FUNC_NAME s_scm_thread_exited_p
1164 {
1165 scm_thread *t;
1166 SCM_VALIDATE_THREAD (1, thread);
1167 t = SCM_THREAD_DATA (thread);
1168 return t->exited;
1169 }
1170 #undef FUNC_NAME
1171
1172 static scm_t_cond wake_up_cond;
1173 int scm_i_thread_go_to_sleep;
1174 static int gc_section_count = 0;
1175 static int threads_initialized_p = 0;
1176
1177 void
1178 scm_i_thread_put_to_sleep ()
1179 {
1180 if (threads_initialized_p && !gc_section_count++)
1181 {
1182 SCM threads;
1183 scm_i_plugin_mutex_lock (&thread_admin_mutex);
1184 threads = all_threads;
1185 /* Signal all threads to go to sleep */
1186 scm_i_thread_go_to_sleep = 1;
1187 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1188 if (SCM_CAR (threads) != cur_thread)
1189 {
1190 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1191 scm_i_plugin_mutex_lock (&t->heap_mutex);
1192 }
1193 scm_i_thread_go_to_sleep = 0;
1194 }
1195 }
1196
1197 void
1198 scm_i_thread_invalidate_freelists ()
1199 {
1200 /* Don't need to lock thread_admin_mutex here since we are single threaded */
1201 SCM threads = all_threads;
1202 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1203 if (SCM_CAR (threads) != cur_thread)
1204 {
1205 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1206 t->clear_freelists_p = 1;
1207 }
1208 }
1209
1210 void
1211 scm_i_thread_wake_up ()
1212 {
1213 if (threads_initialized_p && !--gc_section_count)
1214 {
1215 SCM threads;
1216 threads = all_threads;
1217 scm_i_plugin_cond_broadcast (&wake_up_cond);
1218 for (; !SCM_NULLP (threads); threads = SCM_CDR (threads))
1219 if (SCM_CAR (threads) != cur_thread)
1220 {
1221 scm_thread *t = SCM_THREAD_DATA (SCM_CAR (threads));
1222 scm_i_plugin_mutex_unlock (&t->heap_mutex);
1223 }
1224 scm_i_plugin_mutex_unlock (&thread_admin_mutex);
1225 }
1226 }
1227
1228 void
1229 scm_i_thread_sleep_for_gc ()
1230 {
1231 scm_thread *t;
1232 t = suspend ();
1233 scm_i_plugin_cond_wait (&wake_up_cond, &t->heap_mutex);
1234 resume (t);
1235 }
1236
1237 scm_t_mutex scm_i_critical_section_mutex;
1238 scm_t_rec_mutex scm_i_defer_mutex;
1239
1240 #if SCM_USE_PTHREAD_THREADS
1241 # include "libguile/pthread-threads.c"
1242 #endif
1243 #include "libguile/threads-plugin.c"
1244
1245 /*** Initialization */
1246
1247 void
1248 scm_threads_prehistory ()
1249 {
1250 scm_thread *t;
1251 #if SCM_USE_PTHREAD_THREADS
1252 /* Must be called before any initialization of a mutex. */
1253 scm_init_pthread_threads ();
1254 #endif
1255 scm_i_plugin_mutex_init (&thread_admin_mutex, &scm_i_plugin_mutex);
1256 scm_i_plugin_cond_init (&wake_up_cond, 0);
1257 scm_i_plugin_mutex_init (&scm_i_critical_section_mutex, &scm_i_plugin_mutex);
1258 thread_count = 1;
1259 scm_i_plugin_key_create (&scm_i_thread_key, 0);
1260 scm_i_plugin_key_create (&scm_i_root_state_key, 0);
1261 scm_i_plugin_rec_mutex_init (&scm_i_defer_mutex, &scm_i_plugin_rec_mutex);
1262 /* Allocate a fake thread object to be used during bootup. */
1263 t = malloc (sizeof (scm_thread));
1264 t->base = NULL;
1265 t->clear_freelists_p = 0;
1266 scm_i_plugin_mutex_init (&t->heap_mutex, &scm_i_plugin_mutex);
1267 scm_setspecific (scm_i_thread_key, t);
1268 scm_i_enter_guile (t);
1269 }
1270
1271 scm_t_bits scm_tc16_thread;
1272 scm_t_bits scm_tc16_future;
1273 scm_t_bits scm_tc16_mutex;
1274 scm_t_bits scm_tc16_fair_mutex;
1275 scm_t_bits scm_tc16_condvar;
1276 scm_t_bits scm_tc16_fair_condvar;
1277
1278 void
1279 scm_init_threads (SCM_STACKITEM *base)
1280 {
1281 SCM thread;
1282 scm_tc16_thread = scm_make_smob_type ("thread", sizeof (scm_thread));
1283 scm_tc16_mutex = scm_make_smob_type ("mutex", sizeof (scm_t_mutex));
1284 scm_tc16_fair_mutex = scm_make_smob_type ("fair-mutex",
1285 sizeof (fair_mutex));
1286 scm_tc16_condvar = scm_make_smob_type ("condition-variable",
1287 sizeof (scm_t_cond));
1288 scm_tc16_fair_condvar = scm_make_smob_type ("fair-condition-variable",
1289 sizeof (fair_cond));
1290
1291 thread = make_thread (SCM_BOOL_F);
1292 /* Replace initial fake thread with a real thread object */
1293 free (SCM_CURRENT_THREAD);
1294 scm_setspecific (scm_i_thread_key, SCM_THREAD_DATA (thread));
1295 scm_i_enter_guile (SCM_CURRENT_THREAD);
1296
1297 /* root is set later from init.c */
1298 init_thread_creatant (thread, base);
1299 thread_count = 1;
1300 scm_gc_register_root (&all_threads);
1301 all_threads = scm_cons (thread, SCM_EOL);
1302
1303 scm_set_smob_mark (scm_tc16_thread, thread_mark);
1304 scm_set_smob_print (scm_tc16_thread, thread_print);
1305 scm_set_smob_free (scm_tc16_thread, thread_free);
1306
1307 scm_set_smob_mark (scm_tc16_fair_mutex, fair_mutex_mark);
1308
1309 scm_set_smob_mark (scm_tc16_fair_condvar, fair_cond_mark);
1310
1311 threads_initialized_p = 1;
1312 }
1313
1314 void
1315 scm_init_thread_procs ()
1316 {
1317 #include "libguile/threads.x"
1318 }
1319
1320 /* XXX */
1321
1322 void
1323 scm_init_iselect ()
1324 {
1325 }
1326
1327 /*
1328 Local Variables:
1329 c-file-style: "gnu"
1330 End:
1331 */