aboutsummaryrefslogtreecommitdiffstats
path: root/src/thread.c
diff options
context:
space:
mode:
authorEli Zaretskii2016-12-04 19:59:17 +0200
committerEli Zaretskii2016-12-04 19:59:17 +0200
commitde4624c99ea5bbe38ad5aff7b6461cc5c740d0be (patch)
tree1b57de9e769cdb695cb2cecf157b50f7dea9cfe5 /src/thread.c
parenta486fabb41cdbaa5813c2687fd4008945297d71d (diff)
parente7bde34e939451d87fb42a36195086bdbe48b5e1 (diff)
downloademacs-de4624c99ea5bbe38ad5aff7b6461cc5c740d0be.tar.gz
emacs-de4624c99ea5bbe38ad5aff7b6461cc5c740d0be.zip
Merge branch 'concurrency'
Conflicts (resolved): configure.ac src/Makefile.in src/alloc.c src/bytecode.c src/emacs.c src/eval.c src/lisp.h src/process.c src/regex.c src/regex.h
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c975
1 files changed, 975 insertions, 0 deletions
diff --git a/src/thread.c b/src/thread.c
new file mode 100644
index 00000000000..f5b04e4b231
--- /dev/null
+++ b/src/thread.c
@@ -0,0 +1,975 @@
1/* Threading code.
2 Copyright (C) 2012, 2013 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19
20#include <config.h>
21#include <setjmp.h>
22#include "lisp.h"
23#include "character.h"
24#include "buffer.h"
25#include "process.h"
26#include "coding.h"
27
28static struct thread_state primary_thread;
29
30struct thread_state *current_thread = &primary_thread;
31
32static struct thread_state *all_threads = &primary_thread;
33
34static sys_mutex_t global_lock;
35
36extern int poll_suppress_count;
37extern volatile int interrupt_input_blocked;
38
39
40
41/* m_specpdl is set when the thread is created and cleared when the
42 thread dies. */
43#define thread_alive_p(STATE) ((STATE)->m_specpdl != NULL)
44
45
46
47static void
48release_global_lock (void)
49{
50 sys_mutex_unlock (&global_lock);
51}
52
53/* You must call this after acquiring the global lock.
54 acquire_global_lock does it for you. */
55static void
56post_acquire_global_lock (struct thread_state *self)
57{
58 Lisp_Object buffer;
59 struct thread_state *prev_thread = current_thread;
60
61 /* Do this early on, so that code below could signal errors (e.g.,
62 unbind_for_thread_switch might) correctly, because we are already
63 running in the context of the thread pointed by SELF. */
64 current_thread = self;
65
66 if (prev_thread != current_thread)
67 {
68 /* PREV_THREAD is NULL if the previously current thread
69 exited. In this case, there is no reason to unbind, and
70 trying will crash. */
71 if (prev_thread != NULL)
72 unbind_for_thread_switch (prev_thread);
73 rebind_for_thread_switch ();
74 }
75
76 /* We need special handling to re-set the buffer. */
77 XSETBUFFER (buffer, self->m_current_buffer);
78 self->m_current_buffer = 0;
79 set_buffer_internal (XBUFFER (buffer));
80
81 if (!NILP (current_thread->error_symbol))
82 {
83 Lisp_Object sym = current_thread->error_symbol;
84 Lisp_Object data = current_thread->error_data;
85
86 current_thread->error_symbol = Qnil;
87 current_thread->error_data = Qnil;
88 Fsignal (sym, data);
89 }
90}
91
92static void
93acquire_global_lock (struct thread_state *self)
94{
95 sys_mutex_lock (&global_lock);
96 post_acquire_global_lock (self);
97}
98
99
100
101static void
102lisp_mutex_init (lisp_mutex_t *mutex)
103{
104 mutex->owner = NULL;
105 mutex->count = 0;
106 sys_cond_init (&mutex->condition);
107}
108
109static int
110lisp_mutex_lock (lisp_mutex_t *mutex, int new_count)
111{
112 struct thread_state *self;
113
114 if (mutex->owner == NULL)
115 {
116 mutex->owner = current_thread;
117 mutex->count = new_count == 0 ? 1 : new_count;
118 return 0;
119 }
120 if (mutex->owner == current_thread)
121 {
122 eassert (new_count == 0);
123 ++mutex->count;
124 return 0;
125 }
126
127 self = current_thread;
128 self->wait_condvar = &mutex->condition;
129 while (mutex->owner != NULL && (new_count != 0
130 || NILP (self->error_symbol)))
131 sys_cond_wait (&mutex->condition, &global_lock);
132 self->wait_condvar = NULL;
133
134 if (new_count == 0 && !NILP (self->error_symbol))
135 return 1;
136
137 mutex->owner = self;
138 mutex->count = new_count == 0 ? 1 : new_count;
139
140 return 1;
141}
142
143static int
144lisp_mutex_unlock (lisp_mutex_t *mutex)
145{
146 struct thread_state *self = current_thread;
147
148 if (mutex->owner != current_thread)
149 error ("blah");
150
151 if (--mutex->count > 0)
152 return 0;
153
154 mutex->owner = NULL;
155 sys_cond_broadcast (&mutex->condition);
156
157 return 1;
158}
159
160static unsigned int
161lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex)
162{
163 struct thread_state *self = current_thread;
164 unsigned int result = mutex->count;
165
166 /* Ensured by condvar code. */
167 eassert (mutex->owner == current_thread);
168
169 mutex->count = 0;
170 mutex->owner = NULL;
171 sys_cond_broadcast (&mutex->condition);
172
173 return result;
174}
175
176static void
177lisp_mutex_destroy (lisp_mutex_t *mutex)
178{
179 sys_cond_destroy (&mutex->condition);
180}
181
182static int
183lisp_mutex_owned_p (lisp_mutex_t *mutex)
184{
185 return mutex->owner == current_thread;
186}
187
188
189
190DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0,
191 doc: /* Create a mutex.
192A mutex provides a synchronization point for threads.
193Only one thread at a time can hold a mutex. Other threads attempting
194to acquire it will block until the mutex is available.
195
196A thread can acquire a mutex any number of times.
197
198NAME, if given, is used as the name of the mutex. The name is
199informational only. */)
200 (Lisp_Object name)
201{
202 struct Lisp_Mutex *mutex;
203 Lisp_Object result;
204
205 if (!NILP (name))
206 CHECK_STRING (name);
207
208 mutex = ALLOCATE_PSEUDOVECTOR (struct Lisp_Mutex, mutex, PVEC_MUTEX);
209 memset ((char *) mutex + offsetof (struct Lisp_Mutex, mutex),
210 0, sizeof (struct Lisp_Mutex) - offsetof (struct Lisp_Mutex,
211 mutex));
212 mutex->name = name;
213 lisp_mutex_init (&mutex->mutex);
214
215 XSETMUTEX (result, mutex);
216 return result;
217}
218
219static void
220mutex_lock_callback (void *arg)
221{
222 struct Lisp_Mutex *mutex = arg;
223 struct thread_state *self = current_thread;
224
225 if (lisp_mutex_lock (&mutex->mutex, 0))
226 post_acquire_global_lock (self);
227}
228
229static void
230do_unwind_mutex_lock (void)
231{
232 current_thread->event_object = Qnil;
233}
234
235DEFUN ("mutex-lock", Fmutex_lock, Smutex_lock, 1, 1, 0,
236 doc: /* Acquire a mutex.
237If the current thread already owns MUTEX, increment the count and
238return.
239Otherwise, if no thread owns MUTEX, make the current thread own it.
240Otherwise, block until MUTEX is available, or until the current thread
241is signalled using `thread-signal'.
242Note that calls to `mutex-lock' and `mutex-unlock' must be paired. */)
243 (Lisp_Object mutex)
244{
245 struct Lisp_Mutex *lmutex;
246 ptrdiff_t count = SPECPDL_INDEX ();
247
248 CHECK_MUTEX (mutex);
249 lmutex = XMUTEX (mutex);
250
251 current_thread->event_object = mutex;
252 record_unwind_protect_void (do_unwind_mutex_lock);
253 flush_stack_call_func (mutex_lock_callback, lmutex);
254 return unbind_to (count, Qnil);
255}
256
257static void
258mutex_unlock_callback (void *arg)
259{
260 struct Lisp_Mutex *mutex = arg;
261 struct thread_state *self = current_thread;
262
263 if (lisp_mutex_unlock (&mutex->mutex))
264 post_acquire_global_lock (self);
265}
266
267DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0,
268 doc: /* Release the mutex.
269If this thread does not own MUTEX, signal an error.
270Otherwise, decrement the mutex's count. If the count is zero,
271release MUTEX. */)
272 (Lisp_Object mutex)
273{
274 struct Lisp_Mutex *lmutex;
275
276 CHECK_MUTEX (mutex);
277 lmutex = XMUTEX (mutex);
278
279 flush_stack_call_func (mutex_unlock_callback, lmutex);
280 return Qnil;
281}
282
283DEFUN ("mutex-name", Fmutex_name, Smutex_name, 1, 1, 0,
284 doc: /* Return the name of MUTEX.
285If no name was given when MUTEX was created, return nil. */)
286 (Lisp_Object mutex)
287{
288 struct Lisp_Mutex *lmutex;
289
290 CHECK_MUTEX (mutex);
291 lmutex = XMUTEX (mutex);
292
293 return lmutex->name;
294}
295
296void
297finalize_one_mutex (struct Lisp_Mutex *mutex)
298{
299 lisp_mutex_destroy (&mutex->mutex);
300}
301
302
303
304DEFUN ("make-condition-variable",
305 Fmake_condition_variable, Smake_condition_variable,
306 1, 2, 0,
307 doc: /* Make a condition variable.
308A condition variable provides a way for a thread to sleep while
309waiting for a state change.
310
311MUTEX is the mutex associated with this condition variable.
312NAME, if given, is the name of this condition variable. The name is
313informational only. */)
314 (Lisp_Object mutex, Lisp_Object name)
315{
316 struct Lisp_CondVar *condvar;
317 Lisp_Object result;
318
319 CHECK_MUTEX (mutex);
320 if (!NILP (name))
321 CHECK_STRING (name);
322
323 condvar = ALLOCATE_PSEUDOVECTOR (struct Lisp_CondVar, cond, PVEC_CONDVAR);
324 memset ((char *) condvar + offsetof (struct Lisp_CondVar, cond),
325 0, sizeof (struct Lisp_CondVar) - offsetof (struct Lisp_CondVar,
326 cond));
327 condvar->mutex = mutex;
328 condvar->name = name;
329 sys_cond_init (&condvar->cond);
330
331 XSETCONDVAR (result, condvar);
332 return result;
333}
334
335static void
336condition_wait_callback (void *arg)
337{
338 struct Lisp_CondVar *cvar = arg;
339 struct Lisp_Mutex *mutex = XMUTEX (cvar->mutex);
340 struct thread_state *self = current_thread;
341 unsigned int saved_count;
342 Lisp_Object cond;
343
344 XSETCONDVAR (cond, cvar);
345 self->event_object = cond;
346 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
347 /* If we were signalled while unlocking, we skip the wait, but we
348 still must reacquire our lock. */
349 if (NILP (self->error_symbol))
350 {
351 self->wait_condvar = &cvar->cond;
352 sys_cond_wait (&cvar->cond, &global_lock);
353 self->wait_condvar = NULL;
354 }
355 lisp_mutex_lock (&mutex->mutex, saved_count);
356 self->event_object = Qnil;
357 post_acquire_global_lock (self);
358}
359
360DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0,
361 doc: /* Wait for the condition variable to be notified.
362CONDITION is the condition variable to wait on.
363
364The mutex associated with CONDITION must be held when this is called.
365It is an error if it is not held.
366
367This releases the mutex and waits for CONDITION to be notified or for
368this thread to be signalled with `thread-signal'. When
369`condition-wait' returns, the mutex will again be locked by this
370thread. */)
371 (Lisp_Object condition)
372{
373 struct Lisp_CondVar *cvar;
374 struct Lisp_Mutex *mutex;
375
376 CHECK_CONDVAR (condition);
377 cvar = XCONDVAR (condition);
378
379 mutex = XMUTEX (cvar->mutex);
380 if (!lisp_mutex_owned_p (&mutex->mutex))
381 error ("fixme");
382
383 flush_stack_call_func (condition_wait_callback, cvar);
384
385 return Qnil;
386}
387
388/* Used to communicate argumnets to condition_notify_callback. */
389struct notify_args
390{
391 struct Lisp_CondVar *cvar;
392 int all;
393};
394
395static void
396condition_notify_callback (void *arg)
397{
398 struct notify_args *na = arg;
399 struct Lisp_Mutex *mutex = XMUTEX (na->cvar->mutex);
400 struct thread_state *self = current_thread;
401 unsigned int saved_count;
402 Lisp_Object cond;
403
404 XSETCONDVAR (cond, na->cvar);
405 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
406 if (na->all)
407 sys_cond_broadcast (&na->cvar->cond);
408 else
409 sys_cond_signal (&na->cvar->cond);
410 lisp_mutex_lock (&mutex->mutex, saved_count);
411 post_acquire_global_lock (self);
412}
413
414DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0,
415 doc: /* Notify a condition variable.
416This wakes a thread waiting on CONDITION.
417If ALL is non-nil, all waiting threads are awoken.
418
419The mutex associated with CONDITION must be held when this is called.
420It is an error if it is not held.
421
422This releases the mutex when notifying CONDITION. When
423`condition-notify' returns, the mutex will again be locked by this
424thread. */)
425 (Lisp_Object condition, Lisp_Object all)
426{
427 struct Lisp_CondVar *cvar;
428 struct Lisp_Mutex *mutex;
429 struct notify_args args;
430
431 CHECK_CONDVAR (condition);
432 cvar = XCONDVAR (condition);
433
434 mutex = XMUTEX (cvar->mutex);
435 if (!lisp_mutex_owned_p (&mutex->mutex))
436 error ("fixme");
437
438 args.cvar = cvar;
439 args.all = !NILP (all);
440 flush_stack_call_func (condition_notify_callback, &args);
441
442 return Qnil;
443}
444
445DEFUN ("condition-mutex", Fcondition_mutex, Scondition_mutex, 1, 1, 0,
446 doc: /* Return the mutex associated with CONDITION. */)
447 (Lisp_Object condition)
448{
449 struct Lisp_CondVar *cvar;
450
451 CHECK_CONDVAR (condition);
452 cvar = XCONDVAR (condition);
453
454 return cvar->mutex;
455}
456
457DEFUN ("condition-name", Fcondition_name, Scondition_name, 1, 1, 0,
458 doc: /* Return the name of CONDITION.
459If no name was given when CONDITION was created, return nil. */)
460 (Lisp_Object condition)
461{
462 struct Lisp_CondVar *cvar;
463
464 CHECK_CONDVAR (condition);
465 cvar = XCONDVAR (condition);
466
467 return cvar->name;
468}
469
470void
471finalize_one_condvar (struct Lisp_CondVar *condvar)
472{
473 sys_cond_destroy (&condvar->cond);
474}
475
476
477
478struct select_args
479{
480 select_func *func;
481 int max_fds;
482 fd_set *rfds;
483 fd_set *wfds;
484 fd_set *efds;
485 struct timespec *timeout;
486 sigset_t *sigmask;
487 int result;
488};
489
490static void
491really_call_select (void *arg)
492{
493 struct select_args *sa = arg;
494 struct thread_state *self = current_thread;
495
496 release_global_lock ();
497 sa->result = (sa->func) (sa->max_fds, sa->rfds, sa->wfds, sa->efds,
498 sa->timeout, sa->sigmask);
499 acquire_global_lock (self);
500}
501
502int
503thread_select (select_func *func, int max_fds, fd_set *rfds,
504 fd_set *wfds, fd_set *efds, struct timespec *timeout,
505 sigset_t *sigmask)
506{
507 struct select_args sa;
508
509 sa.func = func;
510 sa.max_fds = max_fds;
511 sa.rfds = rfds;
512 sa.wfds = wfds;
513 sa.efds = efds;
514 sa.timeout = timeout;
515 sa.sigmask = sigmask;
516 flush_stack_call_func (really_call_select, &sa);
517 return sa.result;
518}
519
520
521
522static void
523mark_one_thread (struct thread_state *thread)
524{
525 struct handler *handler;
526 Lisp_Object tem;
527
528 mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr);
529
530 mark_stack (thread->m_stack_bottom, thread->stack_top);
531
532 for (handler = thread->m_handlerlist; handler; handler = handler->next)
533 {
534 mark_object (handler->tag_or_ch);
535 mark_object (handler->val);
536 }
537
538 if (thread->m_current_buffer)
539 {
540 XSETBUFFER (tem, thread->m_current_buffer);
541 mark_object (tem);
542 }
543
544 mark_object (thread->m_last_thing_searched);
545
546 if (thread->m_saved_last_thing_searched)
547 mark_object (thread->m_saved_last_thing_searched);
548}
549
550static void
551mark_threads_callback (void *ignore)
552{
553 struct thread_state *iter;
554
555 for (iter = all_threads; iter; iter = iter->next_thread)
556 {
557 Lisp_Object thread_obj;
558
559 XSETTHREAD (thread_obj, iter);
560 mark_object (thread_obj);
561 mark_one_thread (iter);
562 }
563}
564
565void
566mark_threads (void)
567{
568 flush_stack_call_func (mark_threads_callback, NULL);
569}
570
571void
572unmark_threads (void)
573{
574 struct thread_state *iter;
575
576 for (iter = all_threads; iter; iter = iter->next_thread)
577 if (iter->m_byte_stack_list)
578 relocate_byte_stack (iter->m_byte_stack_list);
579}
580
581
582
583static void
584yield_callback (void *ignore)
585{
586 struct thread_state *self = current_thread;
587
588 release_global_lock ();
589 sys_thread_yield ();
590 acquire_global_lock (self);
591}
592
593DEFUN ("thread-yield", Fthread_yield, Sthread_yield, 0, 0, 0,
594 doc: /* Yield the CPU to another thread. */)
595 (void)
596{
597 flush_stack_call_func (yield_callback, NULL);
598 return Qnil;
599}
600
601static Lisp_Object
602invoke_thread_function (void)
603{
604 Lisp_Object iter;
605 volatile struct thread_state *self = current_thread;
606
607 int count = SPECPDL_INDEX ();
608
609 Ffuncall (1, &current_thread->function);
610 return unbind_to (count, Qnil);
611}
612
613static Lisp_Object
614do_nothing (Lisp_Object whatever)
615{
616 return whatever;
617}
618
619static void *
620run_thread (void *state)
621{
622 char stack_pos;
623 struct thread_state *self = state;
624 struct thread_state **iter;
625
626 self->m_stack_bottom = &stack_pos;
627 self->stack_top = &stack_pos;
628 self->thread_id = sys_thread_self ();
629
630 acquire_global_lock (self);
631
632 { /* Put a dummy catcher at top-level so that handlerlist is never NULL.
633 This is important since handlerlist->nextfree holds the freelist
634 which would otherwise leak every time we unwind back to top-level. */
635 handlerlist_sentinel = xzalloc (sizeof (struct handler));
636 handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel;
637 struct handler *c = push_handler (Qunbound, CATCHER);
638 eassert (c == handlerlist_sentinel);
639 handlerlist_sentinel->nextfree = NULL;
640 handlerlist_sentinel->next = NULL;
641 }
642
643 /* It might be nice to do something with errors here. */
644 internal_condition_case (invoke_thread_function, Qt, do_nothing);
645
646 update_processes_for_thread_death (Fcurrent_thread ());
647
648 xfree (self->m_specpdl - 1);
649 self->m_specpdl = NULL;
650 self->m_specpdl_ptr = NULL;
651 self->m_specpdl_size = 0;
652
653 {
654 struct handler *c, *c_next;
655 for (c = handlerlist_sentinel; c; c = c_next)
656 {
657 c_next = c->nextfree;
658 xfree (c);
659 }
660 }
661
662 current_thread = NULL;
663 sys_cond_broadcast (&self->thread_condvar);
664
665 /* Unlink this thread from the list of all threads. Note that we
666 have to do this very late, after broadcasting our death.
667 Otherwise the GC may decide to reap the thread_state object,
668 leading to crashes. */
669 for (iter = &all_threads; *iter != self; iter = &(*iter)->next_thread)
670 ;
671 *iter = (*iter)->next_thread;
672
673 release_global_lock ();
674
675 return NULL;
676}
677
678void
679finalize_one_thread (struct thread_state *state)
680{
681 sys_cond_destroy (&state->thread_condvar);
682}
683
684DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0,
685 doc: /* Start a new thread and run FUNCTION in it.
686When the function exits, the thread dies.
687If NAME is given, it names the new thread. */)
688 (Lisp_Object function, Lisp_Object name)
689{
690 sys_thread_t thr;
691 struct thread_state *new_thread;
692 Lisp_Object result;
693 const char *c_name = NULL;
694 size_t offset = offsetof (struct thread_state, m_byte_stack_list);
695
696 /* Can't start a thread in temacs. */
697 if (!initialized)
698 abort ();
699
700 if (!NILP (name))
701 CHECK_STRING (name);
702
703 new_thread = ALLOCATE_PSEUDOVECTOR (struct thread_state, m_byte_stack_list,
704 PVEC_THREAD);
705 memset ((char *) new_thread + offset, 0,
706 sizeof (struct thread_state) - offset);
707
708 new_thread->function = function;
709 new_thread->name = name;
710 new_thread->m_last_thing_searched = Qnil; /* copy from parent? */
711 new_thread->m_saved_last_thing_searched = Qnil;
712 new_thread->m_current_buffer = current_thread->m_current_buffer;
713 new_thread->error_symbol = Qnil;
714 new_thread->error_data = Qnil;
715 new_thread->event_object = Qnil;
716
717 new_thread->m_specpdl_size = 50;
718 new_thread->m_specpdl = xmalloc ((1 + new_thread->m_specpdl_size)
719 * sizeof (union specbinding));
720 /* Skip the dummy entry. */
721 ++new_thread->m_specpdl;
722 new_thread->m_specpdl_ptr = new_thread->m_specpdl;
723
724 sys_cond_init (&new_thread->thread_condvar);
725
726 /* We'll need locking here eventually. */
727 new_thread->next_thread = all_threads;
728 all_threads = new_thread;
729
730 if (!NILP (name))
731 c_name = SSDATA (ENCODE_UTF_8 (name));
732
733 if (! sys_thread_create (&thr, c_name, run_thread, new_thread))
734 {
735 /* Restore the previous situation. */
736 all_threads = all_threads->next_thread;
737 error ("Could not start a new thread");
738 }
739
740 /* FIXME: race here where new thread might not be filled in? */
741 XSETTHREAD (result, new_thread);
742 return result;
743}
744
745DEFUN ("current-thread", Fcurrent_thread, Scurrent_thread, 0, 0, 0,
746 doc: /* Return the current thread. */)
747 (void)
748{
749 Lisp_Object result;
750 XSETTHREAD (result, current_thread);
751 return result;
752}
753
754DEFUN ("thread-name", Fthread_name, Sthread_name, 1, 1, 0,
755 doc: /* Return the name of the THREAD.
756The name is the same object that was passed to `make-thread'. */)
757 (Lisp_Object thread)
758{
759 struct thread_state *tstate;
760
761 CHECK_THREAD (thread);
762 tstate = XTHREAD (thread);
763
764 return tstate->name;
765}
766
767static void
768thread_signal_callback (void *arg)
769{
770 struct thread_state *tstate = arg;
771 struct thread_state *self = current_thread;
772
773 sys_cond_broadcast (tstate->wait_condvar);
774 post_acquire_global_lock (self);
775}
776
777DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0,
778 doc: /* Signal an error in a thread.
779This acts like `signal', but arranges for the signal to be raised
780in THREAD. If THREAD is the current thread, acts just like `signal'.
781This will interrupt a blocked call to `mutex-lock', `condition-wait',
782or `thread-join' in the target thread. */)
783 (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data)
784{
785 struct thread_state *tstate;
786
787 CHECK_THREAD (thread);
788 tstate = XTHREAD (thread);
789
790 if (tstate == current_thread)
791 Fsignal (error_symbol, data);
792
793 /* What to do if thread is already signalled? */
794 /* What if error_symbol is Qnil? */
795 tstate->error_symbol = error_symbol;
796 tstate->error_data = data;
797
798 if (tstate->wait_condvar)
799 flush_stack_call_func (thread_signal_callback, tstate);
800
801 return Qnil;
802}
803
804DEFUN ("thread-alive-p", Fthread_alive_p, Sthread_alive_p, 1, 1, 0,
805 doc: /* Return t if THREAD is alive, or nil if it has exited. */)
806 (Lisp_Object thread)
807{
808 struct thread_state *tstate;
809
810 CHECK_THREAD (thread);
811 tstate = XTHREAD (thread);
812
813 return thread_alive_p (tstate) ? Qt : Qnil;
814}
815
816DEFUN ("thread--blocker", Fthread_blocker, Sthread_blocker, 1, 1, 0,
817 doc: /* Return the object that THREAD is blocking on.
818If THREAD is blocked in `thread-join' on a second thread, return that
819thread.
820If THREAD is blocked in `mutex-lock', return the mutex.
821If THREAD is blocked in `condition-wait', return the condition variable.
822Otherwise, if THREAD is not blocked, return nil. */)
823 (Lisp_Object thread)
824{
825 struct thread_state *tstate;
826
827 CHECK_THREAD (thread);
828 tstate = XTHREAD (thread);
829
830 return tstate->event_object;
831}
832
833static void
834thread_join_callback (void *arg)
835{
836 struct thread_state *tstate = arg;
837 struct thread_state *self = current_thread;
838 Lisp_Object thread;
839
840 XSETTHREAD (thread, tstate);
841 self->event_object = thread;
842 self->wait_condvar = &tstate->thread_condvar;
843 while (thread_alive_p (tstate) && NILP (self->error_symbol))
844 sys_cond_wait (self->wait_condvar, &global_lock);
845
846 self->wait_condvar = NULL;
847 self->event_object = Qnil;
848 post_acquire_global_lock (self);
849}
850
851DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0,
852 doc: /* Wait for a thread to exit.
853This blocks the current thread until THREAD exits.
854It is an error for a thread to try to join itself. */)
855 (Lisp_Object thread)
856{
857 struct thread_state *tstate;
858
859 CHECK_THREAD (thread);
860 tstate = XTHREAD (thread);
861
862 if (tstate == current_thread)
863 error ("cannot join current thread");
864
865 if (thread_alive_p (tstate))
866 flush_stack_call_func (thread_join_callback, tstate);
867
868 return Qnil;
869}
870
871DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0,
872 doc: /* Return a list of all threads. */)
873 (void)
874{
875 Lisp_Object result = Qnil;
876 struct thread_state *iter;
877
878 for (iter = all_threads; iter; iter = iter->next_thread)
879 {
880 if (thread_alive_p (iter))
881 {
882 Lisp_Object thread;
883
884 XSETTHREAD (thread, iter);
885 result = Fcons (thread, result);
886 }
887 }
888
889 return result;
890}
891
892
893
894bool
895thread_check_current_buffer (struct buffer *buffer)
896{
897 struct thread_state *iter;
898
899 for (iter = all_threads; iter; iter = iter->next_thread)
900 {
901 if (iter == current_thread)
902 continue;
903
904 if (iter->m_current_buffer == buffer)
905 return true;
906 }
907
908 return false;
909}
910
911
912
913static void
914init_primary_thread (void)
915{
916 primary_thread.header.size
917 = PSEUDOVECSIZE (struct thread_state, m_byte_stack_list);
918 XSETPVECTYPE (&primary_thread, PVEC_THREAD);
919 primary_thread.m_last_thing_searched = Qnil;
920 primary_thread.m_saved_last_thing_searched = Qnil;
921 primary_thread.name = Qnil;
922 primary_thread.function = Qnil;
923 primary_thread.error_symbol = Qnil;
924 primary_thread.error_data = Qnil;
925 primary_thread.event_object = Qnil;
926}
927
928void
929init_threads_once (void)
930{
931 init_primary_thread ();
932}
933
934void
935init_threads (void)
936{
937 init_primary_thread ();
938 sys_cond_init (&primary_thread.thread_condvar);
939 sys_mutex_init (&global_lock);
940 sys_mutex_lock (&global_lock);
941 current_thread = &primary_thread;
942 primary_thread.thread_id = sys_thread_self ();
943}
944
945void
946syms_of_threads (void)
947{
948#ifndef THREADS_ENABLED
949 if (0)
950#endif
951 {
952 defsubr (&Sthread_yield);
953 defsubr (&Smake_thread);
954 defsubr (&Scurrent_thread);
955 defsubr (&Sthread_name);
956 defsubr (&Sthread_signal);
957 defsubr (&Sthread_alive_p);
958 defsubr (&Sthread_join);
959 defsubr (&Sthread_blocker);
960 defsubr (&Sall_threads);
961 defsubr (&Smake_mutex);
962 defsubr (&Smutex_lock);
963 defsubr (&Smutex_unlock);
964 defsubr (&Smutex_name);
965 defsubr (&Smake_condition_variable);
966 defsubr (&Scondition_wait);
967 defsubr (&Scondition_notify);
968 defsubr (&Scondition_mutex);
969 defsubr (&Scondition_name);
970 }
971
972 DEFSYM (Qthreadp, "threadp");
973 DEFSYM (Qmutexp, "mutexp");
974 DEFSYM (Qcondition_variable_p, "condition-variable-p");
975}