1 /* Copyright (C) 1995,1996,1997,1998,2000,2001, 2002, 2006 Free Software Foundation, Inc.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "libguile/_scm.h" /* config.h, _scm.h, __scm.h should be first */
28 #include "libguile/validate.h"
29 #include "libguile/coop-pthreads.h"
30 #include "libguile/root.h"
31 #include "libguile/eval.h"
32 #include "libguile/async.h"
33 #include "libguile/ports.h"
34 #include "libguile/smob.h"
43 return scm_cons (SCM_EOL
, SCM_EOL
);
47 enqueue (SCM q
, SCM t
)
49 SCM c
= scm_cons (t
, SCM_EOL
);
50 if (scm_is_null (SCM_CAR (q
)))
53 SCM_SETCDR (SCM_CDR (q
), c
);
65 SCM_SETCAR (q
, SCM_CDR (c
));
66 if (scm_is_null (SCM_CAR (q
)))
67 SCM_SETCDR (q
, SCM_EOL
);
75 typedef struct scm_copt_thread
{
77 /* A condition variable for sleeping on.
79 pthread_cond_t sleep_cond
;
81 /* A link for waiting queues.
83 struct scm_copt_thread
*next_waiting
;
92 /* For keeping track of the stack and registers. */
100 make_thread (SCM creation_protects
)
103 scm_copt_thread
*t
= scm_gc_malloc (sizeof(*t
), "thread");
107 t
->result
= creation_protects
;
109 t
->joining_threads
= make_queue ();
110 pthread_cond_init (&t
->sleep_cond
, NULL
);
115 init_thread_creator (SCM thread
, pthread_t th
, scm_root_state
*r
)
117 scm_copt_thread
*t
= SCM_THREAD_DATA(thread
);
121 // fprintf (stderr, "%ld created %ld\n", pthread_self (), th);
126 init_thread_creatant (SCM thread
, SCM_STACKITEM
*base
)
128 scm_copt_thread
*t
= SCM_THREAD_DATA(thread
);
134 thread_print (SCM exp
, SCM port
, scm_print_state
*pstate SCM_UNUSED
)
136 scm_copt_thread
*t
= SCM_THREAD_DATA (exp
);
137 scm_puts ("#<thread ", port
);
138 scm_uintprint ((scm_t_bits
)t
, 16, port
);
139 if (t
->pthread
!= -1)
141 scm_putc (' ', port
);
142 scm_intprint (t
->pthread
, 10, port
);
145 scm_puts (" (exited)", port
);
146 scm_putc ('>', port
);
151 thread_free (SCM obj
)
153 scm_copt_thread
*t
= SCM_THREAD_DATA (obj
);
154 if (t
->pthread
!= -1)
156 scm_gc_free (t
, sizeof (*t
), "thread");
162 /* POSIX mutexes are not necessarily fair but since we'd like to use a
163 mutex for scheduling, we build a fair one on top of POSIX.
166 typedef struct fair_mutex
{
167 pthread_mutex_t lock
;
168 scm_copt_thread
*owner
;
169 scm_copt_thread
*next_waiting
, *last_waiting
;
173 fair_mutex_init (fair_mutex
*m
)
175 pthread_mutex_init (&m
->lock
, NULL
);
177 m
->next_waiting
= NULL
;
178 m
->last_waiting
= NULL
;
182 fair_mutex_lock_1 (fair_mutex
*m
, scm_copt_thread
*t
)
184 if (m
->owner
== NULL
)
188 t
->next_waiting
= NULL
;
190 m
->last_waiting
->next_waiting
= t
;
196 pthread_cond_wait (&t
->sleep_cond
, &m
->lock
);
198 while (m
->owner
!= t
);
199 assert (m
->next_waiting
== t
);
200 m
->next_waiting
= t
->next_waiting
;
201 if (m
->next_waiting
== NULL
)
202 m
->last_waiting
= NULL
;
204 pthread_mutex_unlock (&m
->lock
);
208 fair_mutex_lock (fair_mutex
*m
, scm_copt_thread
*t
)
210 pthread_mutex_lock (&m
->lock
);
211 fair_mutex_lock_1 (m
, t
);
215 fair_mutex_unlock_1 (fair_mutex
*m
)
218 pthread_mutex_lock (&m
->lock
);
219 // fprintf (stderr, "%ld unlocking\n", m->owner->pthread);
220 if ((t
= m
->next_waiting
) != NULL
)
223 pthread_cond_signal (&t
->sleep_cond
);
227 // fprintf (stderr, "%ld unlocked\n", pthread_self ());
231 fair_mutex_unlock (fair_mutex
*m
)
233 fair_mutex_unlock_1 (m
);
234 pthread_mutex_unlock (&m
->lock
);
237 /* Temporarily give up the mutex. This function makes sure that we
238 are on the wait queue before starting the next thread. Otherwise
239 the next thread might preempt us and we will have a hard time
240 getting on the wait queue.
244 fair_mutex_yield (fair_mutex
*m
)
246 scm_copt_thread
*self
, *next
;
248 pthread_mutex_lock (&m
->lock
);
252 if ((next
= m
->next_waiting
) == NULL
)
254 /* No use giving it up. */
255 pthread_mutex_unlock (&m
->lock
);
262 self
->next_waiting
= NULL
;
264 m
->last_waiting
->next_waiting
= self
;
266 m
->next_waiting
= self
;
267 m
->last_waiting
= self
;
269 /* wake up next thread
273 pthread_cond_signal (&next
->sleep_cond
);
279 pthread_cond_wait (&self
->sleep_cond
, &m
->lock
);
281 while (m
->owner
!= self
);
282 assert (m
->next_waiting
== self
);
283 m
->next_waiting
= self
->next_waiting
;
284 if (m
->next_waiting
== NULL
)
285 m
->last_waiting
= NULL
;
287 pthread_mutex_unlock (&m
->lock
);
291 fair_mutex_yield (fair_mutex
*m
)
293 scm_copt_thread
*self
= m
->owner
;
294 fair_mutex_unlock_1 (m
);
295 fair_mutex_lock_1 (m
, self
);
300 fair_cond_wait (pthread_cond_t
*c
, fair_mutex
*m
)
302 scm_copt_thread
*t
= m
->owner
;
303 fair_mutex_unlock_1 (m
);
304 pthread_cond_wait (c
, &m
->lock
);
305 fair_mutex_lock_1 (m
, t
);
308 /* Return 1 when the mutex was signalled and 0 when not. */
310 fair_cond_timedwait (pthread_cond_t
*c
, fair_mutex
*m
, scm_t_timespec
*at
)
313 scm_copt_thread
*t
= m
->owner
;
314 fair_mutex_unlock_1 (m
);
315 res
= pthread_cond_timedwait (c
, &m
->lock
, at
); /* XXX - signals? */
316 fair_mutex_lock_1 (m
, t
);
322 /* When a thread wants to execute Guile functions, it locks the
326 static fair_mutex guile_mutex
;
328 static SCM cur_thread
;
329 void *scm_i_copt_thread_data
;
332 scm_i_copt_set_thread_data (void *data
)
334 scm_copt_thread
*t
= SCM_THREAD_DATA (cur_thread
);
335 scm_i_copt_thread_data
= data
;
336 t
->root
= (scm_root_state
*)data
;
340 resume (scm_copt_thread
*t
)
342 cur_thread
= t
->handle
;
343 scm_i_copt_thread_data
= t
->root
;
348 enter_guile (scm_copt_thread
*t
)
350 fair_mutex_lock (&guile_mutex
, t
);
354 static scm_copt_thread
*
357 SCM cur
= cur_thread
;
358 scm_copt_thread
*c
= SCM_THREAD_DATA (cur
);
360 /* record top of stack for the GC */
361 c
->top
= (SCM_STACKITEM
*)&c
;
362 /* save registers. */
363 SCM_FLUSH_REGISTER_WINDOWS
;
369 static scm_copt_thread
*
372 scm_copt_thread
*c
= suspend ();
373 fair_mutex_unlock (&guile_mutex
);
377 int scm_i_switch_counter
;
382 /* Testing guile_mutex.next_waiting without locking guile_mutex.lock
383 is OK since the outcome is not critical. Even when it changes
384 after the test, we do the right thing.
386 if (guile_mutex
.next_waiting
)
388 scm_copt_thread
*t
= suspend ();
389 fair_mutex_yield (&guile_mutex
);
395 /* Put the current thread to sleep until it is explicitely unblocked.
400 scm_copt_thread
*t
= suspend ();
401 fair_cond_wait (&t
->sleep_cond
, &guile_mutex
);
405 /* Put the current thread to sleep until it is explicitely unblocked
406 or until a signal arrives or until time AT (absolute time) is
407 reached. Return 1 when it has been unblocked; 0 otherwise.
410 timed_block (scm_t_timespec
*at
)
413 scm_copt_thread
*t
= suspend ();
414 res
= fair_cond_timedwait (&t
->sleep_cond
, &guile_mutex
, at
);
419 /* Unblock a sleeping thread.
422 unblock (scm_copt_thread
*t
)
424 pthread_cond_signal (&t
->sleep_cond
);
427 /*** Thread creation */
429 static SCM all_threads
;
430 static int thread_count
;
432 typedef struct launch_data
{
435 scm_t_catch_body body
;
437 scm_t_catch_handler handler
;
442 body_bootstrip (launch_data
* data
)
444 /* First save the new root continuation */
445 data
->rootcont
= scm_root
->rootcont
;
446 return (data
->body
) (data
->body_data
);
447 // return scm_call_0 (data->body);
451 handler_bootstrip (launch_data
* data
, SCM tag
, SCM throw_args
)
453 scm_root
->rootcont
= data
->rootcont
;
454 return (data
->handler
) (data
->handler_data
, tag
, throw_args
);
455 // return scm_apply_1 (data->handler, tag, throw_args);
459 really_launch (SCM_STACKITEM
*base
, launch_data
*data
)
461 SCM thread
= data
->thread
;
462 scm_copt_thread
*t
= SCM_THREAD_DATA (thread
);
463 init_thread_creatant (thread
, base
);
466 data
->rootcont
= SCM_BOOL_F
;
468 scm_internal_cwdr ((scm_t_catch_body
) body_bootstrip
,
470 (scm_t_catch_handler
) handler_bootstrip
,
474 pthread_detach (t
->pthread
);
475 all_threads
= scm_delq (thread
, all_threads
);
482 launch_thread (void *p
)
484 really_launch ((SCM_STACKITEM
*)&p
, (launch_data
*)p
);
489 create_thread (scm_t_catch_body body
, void *body_data
,
490 scm_t_catch_handler handler
, void *handler_data
,
495 /* Make new thread. The first thing the new thread will do is to
496 lock guile_mutex. Thus, we can safely complete its
497 initialization after creating it. While the new thread starts,
498 all its data is protected via all_threads.
506 /* Unwind wind chain. */
507 old_winds
= scm_dynwinds
;
508 scm_dowinds (SCM_EOL
, scm_ilength (scm_root
->dynwinds
));
510 /* Allocate thread locals. */
511 root
= scm_make_root (scm_root
->handle
);
512 data
= scm_gc_malloc (sizeof (launch_data
));
515 thread
= make_thread (protects
);
516 data
->thread
= thread
;
518 data
->body_data
= body_data
;
519 data
->handler
= handler
;
520 data
->handler_data
= handler_data
;
521 pthread_create (&th
, NULL
, launch_thread
, (void *) data
);
522 init_thread_creator (thread
, th
, SCM_ROOT_STATE (root
));
523 all_threads
= scm_cons (thread
, all_threads
);
526 /* Return to old dynamic context. */
527 scm_dowinds (old_winds
, - scm_ilength (old_winds
));
534 scm_call_with_new_thread (SCM argl
)
535 #define FUNC_NAME s_call_with_new_thread
539 /* Check arguments. */
541 register SCM args
= argl
;
542 if (!scm_is_pair (args
))
543 SCM_WRONG_NUM_ARGS ();
544 thunk
= SCM_CAR (args
);
545 SCM_ASSERT (scm_is_true (scm_thunk_p (thunk
)),
548 s_call_with_new_thread
);
549 args
= SCM_CDR (args
);
550 if (!scm_is_pair (args
))
551 SCM_WRONG_NUM_ARGS ();
552 handler
= SCM_CAR (args
);
553 SCM_ASSERT (scm_is_true (scm_procedure_p (handler
)),
556 s_call_with_new_thread
);
557 if (!scm_is_null (SCM_CDR (args
)))
558 SCM_WRONG_NUM_ARGS ();
561 return create_thread ((scm_t_catch_body
) scm_call_0
, thunk
,
562 (scm_t_catch_handler
) scm_apply_1
, handler
,
568 scm_spawn_thread (scm_t_catch_body body
, void *body_data
,
569 scm_t_catch_handler handler
, void *handler_data
)
571 return create_thread (body
, body_data
, handler
, handler_data
, SCM_BOOL_F
);
576 /* We implement our own mutex type since we want them to be 'fair', we
577 want to do fancy things while waiting for them (like running
578 asyncs) and we want to support waiting on many things at once.
579 Also, we might add things that are nice for debugging.
582 typedef struct scm_copt_mutex
{
583 /* the thread currently owning the mutex, or SCM_BOOL_F. */
585 /* how much the owner owns us. */
587 /* the threads waiting for this mutex. */
595 SCM mx
= scm_make_smob (scm_tc16_mutex
);
596 scm_copt_mutex
*m
= SCM_MUTEX_DATA (mx
);
597 m
->owner
= SCM_BOOL_F
;
599 m
->waiting
= make_queue ();
604 scm_lock_mutex (SCM mx
)
605 #define FUNC_NAME s_lock_mutex
608 SCM_ASSERT (SCM_MUTEXP (mx
), mx
, SCM_ARG1
, FUNC_NAME
);
609 m
= SCM_MUTEX_DATA (mx
);
611 if (m
->owner
== SCM_BOOL_F
)
612 m
->owner
= cur_thread
;
613 else if (m
->owner
== cur_thread
)
617 while (m
->owner
!= cur_thread
)
619 enqueue (m
->waiting
, cur_thread
);
629 scm_try_mutex (SCM mx
)
630 #define FUNC_NAME s_try_mutex
633 SCM_ASSERT (SCM_MUTEXP (mx
), mx
, SCM_ARG1
, FUNC_NAME
);
634 m
= SCM_MUTEX_DATA (mx
);
636 if (m
->owner
== SCM_BOOL_F
)
637 m
->owner
= cur_thread
;
638 else if (m
->owner
== cur_thread
)
647 scm_unlock_mutex (SCM mx
)
648 #define FUNC_NAME s_unlock_mutex
651 SCM_ASSERT (SCM_MUTEXP (mx
), mx
, SCM_ARG1
, FUNC_NAME
);
652 m
= SCM_MUTEX_DATA (mx
);
654 if (m
->owner
!= cur_thread
)
656 if (m
->owner
== SCM_BOOL_F
)
657 SCM_MISC_ERROR ("mutex not locked", SCM_EOL
);
659 SCM_MISC_ERROR ("mutex not locked by this thread", SCM_EOL
);
661 else if (m
->level
> 0)
665 SCM next
= dequeue (m
->waiting
);
666 if (scm_is_true (next
))
669 unblock (SCM_THREAD_DATA (next
));
673 m
->owner
= SCM_BOOL_F
;
679 /*** Condition variables */
681 /* Like mutexes, we implement our own condition variables using the
685 /* yeah, we don't need a structure for this, but more things (like a
686 name) will likely follow... */
688 typedef struct scm_copt_cond
{
689 /* the threads waiting for this condition. */
696 scm_copt_cond
*c
= SCM_CONDVAR_DATA (cv
);
701 scm_make_condition_variable (void)
703 SCM cv
= scm_make_smob (scm_tc16_condvar
);
704 scm_copt_cond
*c
= SCM_CONDVAR_DATA (cv
);
705 c
->waiting
= make_queue ();
710 scm_timed_wait_condition_variable (SCM cv
, SCM mx
, SCM t
)
711 #define FUNC_NAME s_wait_condition_variable
714 scm_t_timespec waittime
;
717 SCM_ASSERT (SCM_CONDVARP (cv
),
720 s_wait_condition_variable
);
721 SCM_ASSERT (SCM_MUTEXP (mx
),
724 s_wait_condition_variable
);
729 SCM_VALIDATE_UINT_COPY (3, SCM_CAR(t
), waittime
.tv_sec
);
730 SCM_VALIDATE_UINT_COPY (3, SCM_CDR(t
), waittime
.tv_nsec
);
731 waittime
.tv_nsec
*= 1000;
735 SCM_VALIDATE_UINT_COPY (3, t
, waittime
.tv_sec
);
736 waittime
.tv_nsec
= 0;
740 c
= SCM_CONDVAR_DATA (cv
);
742 enqueue (c
->waiting
, cur_thread
);
743 scm_unlock_mutex (mx
);
750 res
= timed_block (&waittime
);
752 return scm_from_bool (res
);
757 scm_signal_condition_variable (SCM cv
)
758 #define FUNC_NAME s_signal_condition_variable
762 SCM_ASSERT (SCM_CONDVARP (cv
),
765 s_signal_condition_variable
);
766 c
= SCM_CONDVAR_DATA (cv
);
767 if (scm_is_true (th
= dequeue (c
->waiting
)))
768 unblock (SCM_THREAD_DATA (th
));
774 scm_broadcast_condition_variable (SCM cv
)
775 #define FUNC_NAME s_broadcast_condition_variable
779 SCM_ASSERT (SCM_CONDVARP (cv
),
782 s_signal_condition_variable
);
783 c
= SCM_CONDVAR_DATA (cv
);
784 while (scm_is_true (th
= dequeue (c
->waiting
)))
785 unblock (SCM_THREAD_DATA (th
));
790 /*** Initialization */
793 scm_threads_init (SCM_STACKITEM
*base
)
795 scm_tc16_thread
= scm_make_smob_type ("thread", 0);
796 scm_tc16_mutex
= scm_make_smob_type ("mutex", sizeof (scm_copt_mutex
));
797 scm_tc16_condvar
= scm_make_smob_type ("condition-variable",
798 sizeof (scm_copt_cond
));
800 scm_i_switch_counter
= SCM_I_THREAD_SWITCH_COUNT
;
802 fair_mutex_init (&guile_mutex
);
804 cur_thread
= make_thread (SCM_BOOL_F
);
805 enter_guile (SCM_THREAD_DATA (cur_thread
));
806 /* root is set later from init.c */
807 init_thread_creator (cur_thread
, pthread_self(), NULL
);
808 init_thread_creatant (cur_thread
, base
);
811 scm_gc_register_root (&all_threads
);
812 all_threads
= scm_cons (cur_thread
, SCM_EOL
);
814 scm_set_smob_print (scm_tc16_thread
, thread_print
);
817 /*** Marking stacks */
819 /* XXX - what to do with this? Do we need to handle this for blocked
823 # define SCM_MARK_BACKING_STORE() do { \
825 SCM_STACKITEM * top, * bot; \
827 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
828 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
829 / sizeof (SCM_STACKITEM))); \
830 bot = (SCM_STACKITEM *) scm_ia64_register_backing_store_base (); \
831 top = (SCM_STACKITEM *) scm_ia64_ar_bsp (&ctx); \
832 scm_mark_locations (bot, top - bot); } while (0)
834 # define SCM_MARK_BACKING_STORE()
842 scm_internal_select (int nfds
,
843 SELECT_TYPE
*readfds
,
844 SELECT_TYPE
*writefds
,
845 SELECT_TYPE
*exceptfds
,
846 struct timeval
*timeout
)
849 scm_copt_thread
*c
= leave_guile ();
850 res
= select (nfds
, readfds
, writefds
, exceptfds
, timeout
);
864 scm_thread_usleep (unsigned long usec
)
866 scm_copt_thread
*c
= leave_guile ();
873 scm_thread_sleep (unsigned long sec
)
876 scm_copt_thread
*c
= leave_guile ();
885 scm_current_thread (void)
891 scm_all_threads (void)
897 scm_i_thread_root (SCM thread
)
899 if (thread
== cur_thread
)
900 return scm_i_copt_thread_data
;
902 return ((scm_copt_thread
*)SCM_THREAD_DATA (thread
))->root
;
906 scm_join_thread (SCM thread
)
907 #define FUNC_NAME s_join_thread
912 SCM_VALIDATE_THREAD (1, thread
);
914 t
= SCM_THREAD_DATA (thread
);
915 if (t
->pthread
!= -1)
917 scm_copt_thread
*c
= leave_guile ();
918 pthread_join (t
->pthread
, NULL
);
922 t
->result
= SCM_BOOL_F
;
928 scm_c_thread_exited_p (SCM thread
)
929 #define FUNC_NAME s_scm_thread_exited_p
932 SCM_VALIDATE_THREAD (1, thread
);
933 t
= SCM_THREAD_DATA (thread
);
934 return t
->pthread
== -1;