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