2 Copyright (C) 2012 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
23 #include "character.h"
27 static struct thread_state primary_thread
;
29 struct thread_state
*current_thread
= &primary_thread
;
31 static struct thread_state
*all_threads
= &primary_thread
;
33 static sys_mutex_t global_lock
;
35 Lisp_Object Qthreadp
, Qmutexp
, Qcondition_variablep
;
40 release_global_lock (void)
42 sys_mutex_unlock (&global_lock
);
45 /* You must call this after acquiring the global lock.
46 acquire_global_lock does it for you. */
48 post_acquire_global_lock (struct thread_state
*self
)
52 if (self
!= current_thread
)
54 unbind_for_thread_switch ();
55 current_thread
= self
;
56 rebind_for_thread_switch ();
59 /* We need special handling to re-set the buffer. */
60 XSETBUFFER (buffer
, self
->m_current_buffer
);
61 self
->m_current_buffer
= 0;
62 set_buffer_internal (XBUFFER (buffer
));
64 if (!NILP (current_thread
->error_symbol
))
66 Lisp_Object sym
= current_thread
->error_symbol
;
67 Lisp_Object data
= current_thread
->error_data
;
69 current_thread
->error_symbol
= Qnil
;
70 current_thread
->error_data
= Qnil
;
76 acquire_global_lock (struct thread_state
*self
)
78 sys_mutex_lock (&global_lock
);
79 post_acquire_global_lock (self
);
85 lisp_mutex_init (lisp_mutex_t
*mutex
)
89 sys_cond_init (&mutex
->condition
);
93 lisp_mutex_lock (lisp_mutex_t
*mutex
, int new_count
)
95 struct thread_state
*self
;
97 if (mutex
->owner
== NULL
)
99 mutex
->owner
= current_thread
;
100 mutex
->count
= new_count
== 0 ? 1 : new_count
;
103 if (mutex
->owner
== current_thread
)
105 eassert (new_count
== 0);
110 self
= current_thread
;
111 self
->wait_condvar
= &mutex
->condition
;
112 while (mutex
->owner
!= NULL
&& (new_count
!= 0
113 || NILP (self
->error_symbol
)))
114 sys_cond_wait (&mutex
->condition
, &global_lock
);
115 self
->wait_condvar
= NULL
;
117 if (new_count
== 0 && !NILP (self
->error_symbol
))
121 mutex
->count
= new_count
== 0 ? 1 : new_count
;
127 lisp_mutex_unlock (lisp_mutex_t
*mutex
)
129 struct thread_state
*self
= current_thread
;
131 if (mutex
->owner
!= current_thread
)
134 if (--mutex
->count
> 0)
138 sys_cond_broadcast (&mutex
->condition
);
144 lisp_mutex_unlock_for_wait (lisp_mutex_t
*mutex
)
146 struct thread_state
*self
= current_thread
;
147 unsigned int result
= mutex
->count
;
149 /* Ensured by condvar code. */
150 eassert (mutex
->owner
== current_thread
);
154 sys_cond_broadcast (&mutex
->condition
);
160 lisp_mutex_destroy (lisp_mutex_t
*mutex
)
162 sys_cond_destroy (&mutex
->condition
);
166 lisp_mutex_owned_p (lisp_mutex_t
*mutex
)
168 return mutex
->owner
== current_thread
;
173 DEFUN ("make-mutex", Fmake_mutex
, Smake_mutex
, 0, 1, 0,
174 doc
: /* Create a mutex.
175 A mutex provides a synchronization point for threads.
176 Only one thread at a time can hold a mutex. Other threads attempting
177 to acquire it will block until the mutex is available.
179 A thread can acquire a mutex any number of times.
181 NAME, if given, is used as the name of the mutex. The name is
182 informational only. */)
185 struct Lisp_Mutex
*mutex
;
191 mutex
= ALLOCATE_PSEUDOVECTOR (struct Lisp_Mutex
, mutex
, PVEC_MUTEX
);
192 memset ((char *) mutex
+ offsetof (struct Lisp_Mutex
, mutex
),
193 0, sizeof (struct Lisp_Mutex
) - offsetof (struct Lisp_Mutex
,
196 lisp_mutex_init (&mutex
->mutex
);
198 XSETMUTEX (result
, mutex
);
203 mutex_lock_callback (void *arg
)
205 struct Lisp_Mutex
*mutex
= arg
;
206 struct thread_state
*self
= current_thread
;
208 if (lisp_mutex_lock (&mutex
->mutex
, 0))
209 post_acquire_global_lock (self
);
213 do_unwind_mutex_lock (Lisp_Object ignore
)
215 current_thread
->event_object
= Qnil
;
219 DEFUN ("mutex-lock", Fmutex_lock
, Smutex_lock
, 1, 1, 0,
220 doc
: /* Acquire a mutex.
221 If the current thread already owns MUTEX, increment the count and
223 Otherwise, if no thread owns MUTEX, make the current thread own it.
224 Otherwise, block until MUTEX is available, or until the current thread
225 is signalled using `thread-signal'.
226 Note that calls to `mutex-lock' and `mutex-unlock' must be paired. */)
229 struct Lisp_Mutex
*lmutex
;
230 ptrdiff_t count
= SPECPDL_INDEX ();
233 lmutex
= XMUTEX (mutex
);
235 current_thread
->event_object
= mutex
;
236 record_unwind_protect (do_unwind_mutex_lock
, Qnil
);
237 flush_stack_call_func (mutex_lock_callback
, lmutex
);
238 return unbind_to (count
, Qnil
);
242 mutex_unlock_callback (void *arg
)
244 struct Lisp_Mutex
*mutex
= arg
;
245 struct thread_state
*self
= current_thread
;
247 if (lisp_mutex_unlock (&mutex
->mutex
))
248 post_acquire_global_lock (self
);
251 DEFUN ("mutex-unlock", Fmutex_unlock
, Smutex_unlock
, 1, 1, 0,
252 doc
: /* Release the mutex.
253 If this thread does not own MUTEX, signal an error.
254 Otherwise, decrement the mutex's count. If the count is zero,
258 struct Lisp_Mutex
*lmutex
;
261 lmutex
= XMUTEX (mutex
);
263 flush_stack_call_func (mutex_unlock_callback
, lmutex
);
267 DEFUN ("mutex-name", Fmutex_name
, Smutex_name
, 1, 1, 0,
268 doc
: /* Return the name of MUTEX.
269 If no name was given when MUTEX was created, return nil. */)
272 struct Lisp_Mutex
*lmutex
;
275 lmutex
= XMUTEX (mutex
);
281 finalize_one_mutex (struct Lisp_Mutex
*mutex
)
283 lisp_mutex_destroy (&mutex
->mutex
);
288 DEFUN ("make-condition-variable",
289 Fmake_condition_variable
, Smake_condition_variable
,
291 doc
: /* Make a condition variable.
292 A condition variable provides a way for a thread to sleep while
293 waiting for a state change.
295 MUTEX is the mutex associated with this condition variable.
296 NAME, if given, is the name of this condition variable. The name is
297 informational only. */)
298 (Lisp_Object mutex
, Lisp_Object name
)
300 struct Lisp_CondVar
*condvar
;
307 condvar
= ALLOCATE_PSEUDOVECTOR (struct Lisp_CondVar
, cond
, PVEC_CONDVAR
);
308 memset ((char *) condvar
+ offsetof (struct Lisp_CondVar
, cond
),
309 0, sizeof (struct Lisp_CondVar
) - offsetof (struct Lisp_CondVar
,
311 condvar
->mutex
= mutex
;
312 condvar
->name
= name
;
313 sys_cond_init (&condvar
->cond
);
315 XSETCONDVAR (result
, condvar
);
320 condition_wait_callback (void *arg
)
322 struct Lisp_CondVar
*cvar
= arg
;
323 struct Lisp_Mutex
*mutex
= XMUTEX (cvar
->mutex
);
324 struct thread_state
*self
= current_thread
;
325 unsigned int saved_count
;
328 XSETCONDVAR (cond
, cvar
);
329 current_thread
->event_object
= cond
;
330 saved_count
= lisp_mutex_unlock_for_wait (&mutex
->mutex
);
331 /* If we were signalled while unlocking, we skip the wait, but we
332 still must reacquire our lock. */
333 if (NILP (self
->error_symbol
))
335 self
->wait_condvar
= &cvar
->cond
;
336 sys_cond_wait (&cvar
->cond
, &global_lock
);
337 self
->wait_condvar
= NULL
;
339 lisp_mutex_lock (&mutex
->mutex
, saved_count
);
340 current_thread
->event_object
= Qnil
;
341 post_acquire_global_lock (self
);
344 DEFUN ("condition-wait", Fcondition_wait
, Scondition_wait
, 1, 1, 0,
345 doc
: /* Wait for the condition variable to be notified.
346 CONDITION is the condition variable to wait on.
348 The mutex associated with CONDITION must be held when this is called.
349 It is an error if it is not held.
351 This releases the mutex and waits for CONDITION to be notified or for
352 this thread to be signalled with `thread-signal'. When
353 `condition-wait' returns, the mutex will again be locked by this
355 (Lisp_Object condition
)
357 struct Lisp_CondVar
*cvar
;
358 struct Lisp_Mutex
*mutex
;
360 CHECK_CONDVAR (condition
);
361 cvar
= XCONDVAR (condition
);
363 mutex
= XMUTEX (cvar
->mutex
);
364 if (!lisp_mutex_owned_p (&mutex
->mutex
))
367 flush_stack_call_func (condition_wait_callback
, cvar
);
372 /* Used to communicate argumnets to condition_notify_callback. */
375 struct Lisp_CondVar
*cvar
;
380 condition_notify_callback (void *arg
)
382 struct notify_args
*na
= arg
;
383 struct Lisp_Mutex
*mutex
= XMUTEX (na
->cvar
->mutex
);
384 struct thread_state
*self
= current_thread
;
385 unsigned int saved_count
;
388 XSETCONDVAR (cond
, na
->cvar
);
389 saved_count
= lisp_mutex_unlock_for_wait (&mutex
->mutex
);
391 sys_cond_broadcast (&na
->cvar
->cond
);
393 sys_cond_signal (&na
->cvar
->cond
);
394 lisp_mutex_lock (&mutex
->mutex
, saved_count
);
395 post_acquire_global_lock (self
);
398 DEFUN ("condition-notify", Fcondition_notify
, Scondition_notify
, 1, 2, 0,
399 doc
: /* Notify a condition variable.
400 This wakes a thread waiting on CONDITION.
401 If ALL is non-nil, all waiting threads are awoken.
403 The mutex associated with CONDITION must be held when this is called.
404 It is an error if it is not held.
406 This releases the mutex when notifying CONDITION. When
407 `condition-notify' returns, the mutex will again be locked by this
409 (Lisp_Object condition
, Lisp_Object all
)
411 struct Lisp_CondVar
*cvar
;
412 struct Lisp_Mutex
*mutex
;
413 struct notify_args args
;
415 CHECK_CONDVAR (condition
);
416 cvar
= XCONDVAR (condition
);
418 mutex
= XMUTEX (cvar
->mutex
);
419 if (!lisp_mutex_owned_p (&mutex
->mutex
))
423 args
.all
= !NILP (all
);
424 flush_stack_call_func (condition_notify_callback
, &args
);
429 DEFUN ("condition-mutex", Fcondition_mutex
, Scondition_mutex
, 1, 1, 0,
430 doc
: /* Return the mutex associated with CONDITION. */)
431 (Lisp_Object condition
)
433 struct Lisp_CondVar
*cvar
;
435 CHECK_CONDVAR (condition
);
436 cvar
= XCONDVAR (condition
);
441 DEFUN ("condition-name", Fcondition_name
, Scondition_name
, 1, 1, 0,
442 doc
: /* Return the name of CONDITION.
443 If no name was given when CONDITION was created, return nil. */)
444 (Lisp_Object condition
)
446 struct Lisp_CondVar
*cvar
;
448 CHECK_CONDVAR (condition
);
449 cvar
= XCONDVAR (condition
);
455 finalize_one_condvar (struct Lisp_CondVar
*condvar
)
457 sys_cond_destroy (&condvar
->cond
);
475 really_call_select (void *arg
)
477 struct select_args
*sa
= arg
;
478 struct thread_state
*self
= current_thread
;
480 release_global_lock ();
481 sa
->result
= (sa
->func
) (sa
->max_fds
, sa
->rfds
, sa
->wfds
, sa
->efds
,
482 sa
->timeout
, sa
->sigmask
);
483 acquire_global_lock (self
);
487 thread_select (select_func
*func
, int max_fds
, SELECT_TYPE
*rfds
,
488 SELECT_TYPE
*wfds
, SELECT_TYPE
*efds
, EMACS_TIME
*timeout
,
491 struct select_args sa
;
494 sa
.max_fds
= max_fds
;
498 sa
.timeout
= timeout
;
499 sa
.sigmask
= sigmask
;
500 flush_stack_call_func (really_call_select
, &sa
);
507 mark_one_thread (struct thread_state
*thread
)
509 struct specbinding
*bind
;
510 struct handler
*handler
;
513 for (bind
= thread
->m_specpdl
; bind
!= thread
->m_specpdl_ptr
; bind
++)
515 mark_object (bind
->symbol
);
516 mark_object (bind
->old_value
);
517 mark_object (bind
->saved_value
);
520 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
521 || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
522 mark_stack (thread
->m_stack_bottom
, thread
->stack_top
);
526 for (tail
= thread
->m_gcprolist
; tail
; tail
= tail
->next
)
527 for (i
= 0; i
< tail
->nvars
; i
++)
528 mark_object (tail
->var
[i
]);
532 if (thread
->m_byte_stack_list
)
533 mark_byte_stack (thread
->m_byte_stack_list
);
536 mark_catchlist (thread
->m_catchlist
);
538 for (handler
= thread
->m_handlerlist
; handler
; handler
= handler
->next
)
540 mark_object (handler
->handler
);
541 mark_object (handler
->var
);
544 mark_backtrace (thread
->m_backtrace_list
);
547 if (thread
->m_current_buffer
)
549 XSETBUFFER (tem
, thread
->m_current_buffer
);
553 mark_object (thread
->m_last_thing_searched
);
555 if (thread
->m_saved_last_thing_searched
)
556 mark_object (thread
->m_saved_last_thing_searched
);
560 mark_threads_callback (void *ignore
)
562 struct thread_state
*iter
;
564 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
566 Lisp_Object thread_obj
;
568 XSETTHREAD (thread_obj
, iter
);
569 mark_object (thread_obj
);
570 mark_one_thread (iter
);
577 flush_stack_call_func (mark_threads_callback
, NULL
);
581 unmark_threads (void)
583 struct thread_state
*iter
;
585 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
586 if (iter
->m_byte_stack_list
)
587 unmark_byte_stack (iter
->m_byte_stack_list
);
593 yield_callback (void *ignore
)
595 struct thread_state
*self
= current_thread
;
597 release_global_lock ();
599 acquire_global_lock (self
);
602 DEFUN ("thread-yield", Fthread_yield
, Sthread_yield
, 0, 0, 0,
603 doc
: /* Yield the CPU to another thread. */)
606 flush_stack_call_func (yield_callback
, NULL
);
611 invoke_thread_function (void)
615 int count
= SPECPDL_INDEX ();
617 Ffuncall (1, ¤t_thread
->function
);
618 return unbind_to (count
, Qnil
);
622 do_nothing (Lisp_Object whatever
)
628 run_thread (void *state
)
631 struct thread_state
*self
= state
;
632 struct thread_state
**iter
;
634 self
->m_stack_bottom
= &stack_pos
;
635 self
->stack_top
= self
->m_stack_bottom
= &stack_pos
;
636 self
->thread_id
= sys_thread_self ();
638 acquire_global_lock (self
);
640 /* It might be nice to do something with errors here. */
641 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
643 unbind_for_thread_switch ();
645 update_processes_for_thread_death (Fcurrent_thread ());
647 /* Unlink this thread from the list of all threads. */
648 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
650 *iter
= (*iter
)->next_thread
;
652 self
->m_last_thing_searched
= Qnil
;
653 self
->m_saved_last_thing_searched
= Qnil
;
655 self
->function
= Qnil
;
656 self
->error_symbol
= Qnil
;
657 self
->error_data
= Qnil
;
658 xfree (self
->m_specpdl
);
659 self
->m_specpdl
= NULL
;
660 self
->m_specpdl_ptr
= NULL
;
661 self
->m_specpdl_size
= 0;
663 sys_cond_broadcast (&self
->thread_condvar
);
665 release_global_lock ();
671 finalize_one_thread (struct thread_state
*state
)
673 sys_cond_destroy (&state
->thread_condvar
);
676 DEFUN ("make-thread", Fmake_thread
, Smake_thread
, 1, 2, 0,
677 doc
: /* Start a new thread and run FUNCTION in it.
678 When the function exits, the thread dies.
679 If NAME is given, it names the new thread. */)
680 (Lisp_Object function
, Lisp_Object name
)
683 struct thread_state
*new_thread
;
686 /* Can't start a thread in temacs. */
693 new_thread
= ALLOCATE_PSEUDOVECTOR (struct thread_state
, m_gcprolist
,
695 memset ((char *) new_thread
+ offsetof (struct thread_state
, m_gcprolist
),
696 0, sizeof (struct thread_state
) - offsetof (struct thread_state
,
699 new_thread
->function
= function
;
700 new_thread
->name
= name
;
701 new_thread
->m_last_thing_searched
= Qnil
; /* copy from parent? */
702 new_thread
->m_saved_last_thing_searched
= Qnil
;
703 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
704 new_thread
->error_symbol
= Qnil
;
705 new_thread
->error_data
= Qnil
;
706 new_thread
->event_object
= Qnil
;
708 new_thread
->m_specpdl_size
= 50;
709 new_thread
->m_specpdl
= xmalloc (new_thread
->m_specpdl_size
710 * sizeof (struct specbinding
));
711 new_thread
->m_specpdl_ptr
= new_thread
->m_specpdl
;
713 sys_cond_init (&new_thread
->thread_condvar
);
715 /* We'll need locking here eventually. */
716 new_thread
->next_thread
= all_threads
;
717 all_threads
= new_thread
;
719 if (! sys_thread_create (&thr
, run_thread
, new_thread
))
721 /* Restore the previous situation. */
722 all_threads
= all_threads
->next_thread
;
723 error ("Could not start a new thread");
726 /* FIXME: race here where new thread might not be filled in? */
727 XSETTHREAD (result
, new_thread
);
731 DEFUN ("current-thread", Fcurrent_thread
, Scurrent_thread
, 0, 0, 0,
732 doc
: /* Return the current thread. */)
736 XSETTHREAD (result
, current_thread
);
740 DEFUN ("thread-name", Fthread_name
, Sthread_name
, 1, 1, 0,
741 doc
: /* Return the name of the THREAD.
742 The name is the same object that was passed to `make-thread'. */)
745 struct thread_state
*tstate
;
747 CHECK_THREAD (thread
);
748 tstate
= XTHREAD (thread
);
754 thread_signal_callback (void *arg
)
756 struct thread_state
*tstate
= arg
;
757 struct thread_state
*self
= current_thread
;
759 sys_cond_broadcast (tstate
->wait_condvar
);
760 post_acquire_global_lock (self
);
763 DEFUN ("thread-signal", Fthread_signal
, Sthread_signal
, 3, 3, 0,
764 doc
: /* Signal an error in a thread.
765 This acts like `signal', but arranges for the signal to be raised
766 in THREAD. If THREAD is the current thread, acts just like `signal'.
767 This will interrupt a blocked call to `mutex-lock', `condition-wait',
768 or `thread-join' in the target thread. */)
769 (Lisp_Object thread
, Lisp_Object error_symbol
, Lisp_Object data
)
771 struct thread_state
*tstate
;
773 CHECK_THREAD (thread
);
774 tstate
= XTHREAD (thread
);
776 if (tstate
== current_thread
)
777 Fsignal (error_symbol
, data
);
779 /* What to do if thread is already signalled? */
780 /* What if error_symbol is Qnil? */
781 tstate
->error_symbol
= error_symbol
;
782 tstate
->error_data
= data
;
784 if (tstate
->wait_condvar
)
785 flush_stack_call_func (thread_signal_callback
, tstate
);
790 DEFUN ("thread-alive-p", Fthread_alive_p
, Sthread_alive_p
, 1, 1, 0,
791 doc
: /* Return t if THREAD is alive, or nil if it has exited. */)
794 struct thread_state
*tstate
;
796 CHECK_THREAD (thread
);
797 tstate
= XTHREAD (thread
);
799 /* m_specpdl is set when the thread is created and cleared when the
801 return tstate
->m_specpdl
== NULL
? Qnil
: Qt
;
804 DEFUN ("thread-blocker", Fthread_blocker
, Sthread_blocker
, 1, 1, 0,
805 doc
: /* Return the object that THREAD is blocking on.
806 If THREAD is blocked in `thread-join' on a second thread, return that
808 If THREAD is blocked in `mutex-lock', return the mutex.
809 If THREAD is blocked in `condition-wait', return the condition variable.
810 Otherwise, if THREAD is not blocked, return nil. */)
813 struct thread_state
*tstate
;
815 CHECK_THREAD (thread
);
816 tstate
= XTHREAD (thread
);
818 return tstate
->event_object
;
822 thread_join_callback (void *arg
)
824 struct thread_state
*tstate
= arg
;
825 struct thread_state
*self
= current_thread
;
828 XSETTHREAD (thread
, tstate
);
829 self
->event_object
= thread
;
830 self
->wait_condvar
= &tstate
->thread_condvar
;
831 while (tstate
->m_specpdl
!= NULL
&& NILP (self
->error_symbol
))
832 sys_cond_wait (self
->wait_condvar
, &global_lock
);
834 self
->wait_condvar
= NULL
;
835 self
->event_object
= Qnil
;
836 post_acquire_global_lock (self
);
839 DEFUN ("thread-join", Fthread_join
, Sthread_join
, 1, 1, 0,
840 doc
: /* Wait for a thread to exit.
841 This blocks the current thread until THREAD exits.
842 It is an error for a thread to try to join itself. */)
845 struct thread_state
*tstate
;
847 CHECK_THREAD (thread
);
848 tstate
= XTHREAD (thread
);
850 if (tstate
->m_specpdl
!= NULL
)
851 flush_stack_call_func (thread_join_callback
, tstate
);
856 DEFUN ("all-threads", Fall_threads
, Sall_threads
, 0, 0, 0,
857 doc
: /* Return a list of all threads. */)
860 Lisp_Object result
= Qnil
;
861 struct thread_state
*iter
;
863 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
867 XSETTHREAD (thread
, iter
);
868 result
= Fcons (thread
, result
);
877 init_primary_thread (void)
879 primary_thread
.header
.size
880 = PSEUDOVECSIZE (struct thread_state
, m_gcprolist
);
881 XSETPVECTYPE (&primary_thread
, PVEC_THREAD
);
882 primary_thread
.m_last_thing_searched
= Qnil
;
883 primary_thread
.m_saved_last_thing_searched
= Qnil
;
884 primary_thread
.name
= Qnil
;
885 primary_thread
.function
= Qnil
;
886 primary_thread
.error_symbol
= Qnil
;
887 primary_thread
.error_data
= Qnil
;
888 primary_thread
.event_object
= Qnil
;
890 sys_cond_init (&primary_thread
.thread_condvar
);
894 init_threads_once (void)
896 init_primary_thread ();
902 init_primary_thread ();
904 sys_mutex_init (&global_lock
);
905 sys_mutex_lock (&global_lock
);
909 syms_of_threads (void)
911 defsubr (&Sthread_yield
);
912 defsubr (&Smake_thread
);
913 defsubr (&Scurrent_thread
);
914 defsubr (&Sthread_name
);
915 defsubr (&Sthread_signal
);
916 defsubr (&Sthread_alive_p
);
917 defsubr (&Sthread_join
);
918 defsubr (&Sthread_blocker
);
919 defsubr (&Sall_threads
);
920 defsubr (&Smake_mutex
);
921 defsubr (&Smutex_lock
);
922 defsubr (&Smutex_unlock
);
923 defsubr (&Smutex_name
);
924 defsubr (&Smake_condition_variable
);
925 defsubr (&Scondition_wait
);
926 defsubr (&Scondition_notify
);
927 defsubr (&Scondition_mutex
);
928 defsubr (&Scondition_name
);
930 Qthreadp
= intern_c_string ("threadp");
931 staticpro (&Qthreadp
);
932 Qmutexp
= intern_c_string ("mutexp");
933 staticpro (&Qmutexp
);
934 Qcondition_variablep
= intern_c_string ("condition-variablep");
935 staticpro (&Qcondition_variablep
);