aboutsummaryrefslogtreecommitdiffstats
path: root/src/thread.c
diff options
context:
space:
mode:
authorEli Zaretskii2016-12-10 18:54:43 +0200
committerEli Zaretskii2016-12-10 18:54:43 +0200
commit2412a1fc05fe9f89b171d0781c2d530923f48adc (patch)
treed42a5d2608e65a10b1cc23c6b4609d54bef25d49 /src/thread.c
parentfc0fd24c105bde4c001ebebe4b8b7e1f96cd2871 (diff)
parent828b4560cd4a0d8cb9b7a7a3e20ff0c53ba86cfa (diff)
downloademacs-2412a1fc05fe9f89b171d0781c2d530923f48adc.tar.gz
emacs-2412a1fc05fe9f89b171d0781c2d530923f48adc.zip
Support concurrency in Emacs Lisp
Merge branch 'test-concurrency' * src/thread.c: * src/thread.h: * src/systhread.c: * src/systhread.h: New files. * src/xgselect.c (xg_select): Avoid using SAFE_NALLOCA and use xnmalloc unconditionally. * src/window.c (struct save_window_data): Rename current_buffer to f_current_buffer. * src/w32proc.c (sys_select): Change the function signature to closer fit 'pselect' on Posix hosts. * src/search.c: * src/regex.h: Convert some globals to macros that reference thread-specific values. * src/process.c (pset_thread, add_non_keyboard_read_fd) (add_process_read_fd, add_non_blocking_write_fd) (recompute_input_desc, compute_input_wait_mask) (compute_non_process_wait_mask, compute_non_keyboard_wait_mask) (compute_write_mask, clear_waiting_thread_info) (update_processes_for_thread_death, Fset_process_thread) (Fprocess_thread): New functions. (enum fd_bits): New enumeration. (fd_callback_data): Add 'thread' and 'waiting_thread', rename 'condition' to 'flags'. (set_process_filter_masks, create_process, create_pty) (Fmake_serial_process, finish_after_tls_connection) (connect_network_socket, deactivate_process) (server_accept_connection, wait_reading_process_output) (Fcontinue_process, Fstop_process, keyboard_bit_set) (add_timer_wait_descriptor, add_keyboard_wait_descriptor) (delete_keyboard_wait_descriptor): Use the new functions instead of manipulating fd flags and masks directly. (syms_of_process): Defsubr the new primitives. * src/print.c (print_object): Print threads, mutexes, and conditional variables. * src/lisp.h (enum pvec_type): New values PVEC_THREAD, PVEC_MUTEX, and PVEC_CONDVAR. (XTHREAD, XMUTEX, XCONDVAR, THREADP, MUTEXP, CONDVARP) (CHECK_THREAD, CHECK_MUTEX, CHECK_CONDVAR): New inline functions. (XSETTHREAD, XSETMUTEX, XSETCONDVAR): New macros. (struct handler): Add back byte_stack. Rename lisp_eval_depth to f_lisp_eval_depth. * src/eval.c (specpdl_kind, specpdl_arg, do_specbind) (rebind_for_thread_switch, do_one_unbind) (unbind_for_thread_switch): New functions. (init_eval): 'handlerlist' is not malloc'ed. (specbind): Call do_specbind. (unbind_to): Call do_one_unbind. (mark_specpdl): Accept 2 arguments. (mark_specpdl): Mark the saved value in a let-binding. * src/emacs.c (main): Call init_threads_once, init_threads, and syms_of_threads. * src/data.c (Ftype_of): Support thread, mutex, and condvar objects. (Fthreadp, Fmutexp, Fcondition_variable_p): New functions. (syms_of_data): DEFSYM and defsubr new symbols and primitives. * src/bytecode.c (struct byte_stack, FETCH, CHECK_RANGE) (BYTE_CODE_QUIT): Add back. (exec_byte_code): Add back byte stack manipulation. * src/alloc.c (cleanup_vector): Handle threads, mutexes, and conditional variables. (mark_stack): Now extern; accept additional argument 'bottom'. (flush_stack_call_func): New function. (garbage_collect_1): Call mark_threads and unmark_threads. Don't mark handlers. * src/.gdbinit (xbytecode): Add back. * test/src/thread-tests.el: New tests. * test/src/data-tests.el (binding-test-manual) (binding-test-setq-default, binding-test-makunbound) (binding-test-defvar-bool, binding-test-defvar-int) (binding-test-set-constant-t, binding-test-set-constant-nil) (binding-test-set-constant-keyword) (binding-test-set-constant-nil): New tests. * doc/lispref/processes.texi (Processes and Threads): New subsection. * doc/lispref/threads.texi: New file * doc/lispref/elisp.texi (Top): Include it. * doc/lispref/objects.texi (Thread Type, Mutex Type) (Condition Variable Type): New subsections. (Type Predicates): Add thread-related predicates. * doc/lispref/objects.texi (Editing Types): * doc/lispref/elisp.texi (Top): Update higher-level menus. * etc/NEWS: Mention concurrency features.
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c970
1 files changed, 970 insertions, 0 deletions
diff --git a/src/thread.c b/src/thread.c
new file mode 100644
index 00000000000..ae2ce3dc02b
--- /dev/null
+++ b/src/thread.c
@@ -0,0 +1,970 @@
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 if (mutex->owner != current_thread)
147 error ("Cannot unlock mutex owned by another thread");
148
149 if (--mutex->count > 0)
150 return 0;
151
152 mutex->owner = NULL;
153 sys_cond_broadcast (&mutex->condition);
154
155 return 1;
156}
157
158static unsigned int
159lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex)
160{
161 unsigned int result = mutex->count;
162
163 /* Ensured by condvar code. */
164 eassert (mutex->owner == current_thread);
165
166 mutex->count = 0;
167 mutex->owner = NULL;
168 sys_cond_broadcast (&mutex->condition);
169
170 return result;
171}
172
173static void
174lisp_mutex_destroy (lisp_mutex_t *mutex)
175{
176 sys_cond_destroy (&mutex->condition);
177}
178
179static int
180lisp_mutex_owned_p (lisp_mutex_t *mutex)
181{
182 return mutex->owner == current_thread;
183}
184
185
186
187DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0,
188 doc: /* Create a mutex.
189A mutex provides a synchronization point for threads.
190Only one thread at a time can hold a mutex. Other threads attempting
191to acquire it will block until the mutex is available.
192
193A thread can acquire a mutex any number of times.
194
195NAME, if given, is used as the name of the mutex. The name is
196informational only. */)
197 (Lisp_Object name)
198{
199 struct Lisp_Mutex *mutex;
200 Lisp_Object result;
201
202 if (!NILP (name))
203 CHECK_STRING (name);
204
205 mutex = ALLOCATE_PSEUDOVECTOR (struct Lisp_Mutex, mutex, PVEC_MUTEX);
206 memset ((char *) mutex + offsetof (struct Lisp_Mutex, mutex),
207 0, sizeof (struct Lisp_Mutex) - offsetof (struct Lisp_Mutex,
208 mutex));
209 mutex->name = name;
210 lisp_mutex_init (&mutex->mutex);
211
212 XSETMUTEX (result, mutex);
213 return result;
214}
215
216static void
217mutex_lock_callback (void *arg)
218{
219 struct Lisp_Mutex *mutex = arg;
220 struct thread_state *self = current_thread;
221
222 if (lisp_mutex_lock (&mutex->mutex, 0))
223 post_acquire_global_lock (self);
224}
225
226static void
227do_unwind_mutex_lock (void)
228{
229 current_thread->event_object = Qnil;
230}
231
232DEFUN ("mutex-lock", Fmutex_lock, Smutex_lock, 1, 1, 0,
233 doc: /* Acquire a mutex.
234If the current thread already owns MUTEX, increment the count and
235return.
236Otherwise, if no thread owns MUTEX, make the current thread own it.
237Otherwise, block until MUTEX is available, or until the current thread
238is signalled using `thread-signal'.
239Note that calls to `mutex-lock' and `mutex-unlock' must be paired. */)
240 (Lisp_Object mutex)
241{
242 struct Lisp_Mutex *lmutex;
243 ptrdiff_t count = SPECPDL_INDEX ();
244
245 CHECK_MUTEX (mutex);
246 lmutex = XMUTEX (mutex);
247
248 current_thread->event_object = mutex;
249 record_unwind_protect_void (do_unwind_mutex_lock);
250 flush_stack_call_func (mutex_lock_callback, lmutex);
251 return unbind_to (count, Qnil);
252}
253
254static void
255mutex_unlock_callback (void *arg)
256{
257 struct Lisp_Mutex *mutex = arg;
258 struct thread_state *self = current_thread;
259
260 if (lisp_mutex_unlock (&mutex->mutex))
261 post_acquire_global_lock (self);
262}
263
264DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0,
265 doc: /* Release the mutex.
266If this thread does not own MUTEX, signal an error.
267Otherwise, decrement the mutex's count. If the count is zero,
268release MUTEX. */)
269 (Lisp_Object mutex)
270{
271 struct Lisp_Mutex *lmutex;
272
273 CHECK_MUTEX (mutex);
274 lmutex = XMUTEX (mutex);
275
276 flush_stack_call_func (mutex_unlock_callback, lmutex);
277 return Qnil;
278}
279
280DEFUN ("mutex-name", Fmutex_name, Smutex_name, 1, 1, 0,
281 doc: /* Return the name of MUTEX.
282If no name was given when MUTEX was created, return nil. */)
283 (Lisp_Object mutex)
284{
285 struct Lisp_Mutex *lmutex;
286
287 CHECK_MUTEX (mutex);
288 lmutex = XMUTEX (mutex);
289
290 return lmutex->name;
291}
292
293void
294finalize_one_mutex (struct Lisp_Mutex *mutex)
295{
296 lisp_mutex_destroy (&mutex->mutex);
297}
298
299
300
301DEFUN ("make-condition-variable",
302 Fmake_condition_variable, Smake_condition_variable,
303 1, 2, 0,
304 doc: /* Make a condition variable associated with MUTEX.
305A condition variable provides a way for a thread to sleep while
306waiting for a state change.
307
308MUTEX is the mutex associated with this condition variable.
309NAME, if given, is the name of this condition variable. The name is
310informational only. */)
311 (Lisp_Object mutex, Lisp_Object name)
312{
313 struct Lisp_CondVar *condvar;
314 Lisp_Object result;
315
316 CHECK_MUTEX (mutex);
317 if (!NILP (name))
318 CHECK_STRING (name);
319
320 condvar = ALLOCATE_PSEUDOVECTOR (struct Lisp_CondVar, cond, PVEC_CONDVAR);
321 memset ((char *) condvar + offsetof (struct Lisp_CondVar, cond),
322 0, sizeof (struct Lisp_CondVar) - offsetof (struct Lisp_CondVar,
323 cond));
324 condvar->mutex = mutex;
325 condvar->name = name;
326 sys_cond_init (&condvar->cond);
327
328 XSETCONDVAR (result, condvar);
329 return result;
330}
331
332static void
333condition_wait_callback (void *arg)
334{
335 struct Lisp_CondVar *cvar = arg;
336 struct Lisp_Mutex *mutex = XMUTEX (cvar->mutex);
337 struct thread_state *self = current_thread;
338 unsigned int saved_count;
339 Lisp_Object cond;
340
341 XSETCONDVAR (cond, cvar);
342 self->event_object = cond;
343 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
344 /* If we were signalled while unlocking, we skip the wait, but we
345 still must reacquire our lock. */
346 if (NILP (self->error_symbol))
347 {
348 self->wait_condvar = &cvar->cond;
349 sys_cond_wait (&cvar->cond, &global_lock);
350 self->wait_condvar = NULL;
351 }
352 lisp_mutex_lock (&mutex->mutex, saved_count);
353 self->event_object = Qnil;
354 post_acquire_global_lock (self);
355}
356
357DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0,
358 doc: /* Wait for the condition variable COND to be notified.
359COND is the condition variable to wait on.
360
361The mutex associated with COND must be held when this is called.
362It is an error if it is not held.
363
364This releases the mutex and waits for COND to be notified or for
365this thread to be signalled with `thread-signal'. When
366`condition-wait' returns, COND's mutex will again be locked by
367this thread. */)
368 (Lisp_Object cond)
369{
370 struct Lisp_CondVar *cvar;
371 struct Lisp_Mutex *mutex;
372
373 CHECK_CONDVAR (cond);
374 cvar = XCONDVAR (cond);
375
376 mutex = XMUTEX (cvar->mutex);
377 if (!lisp_mutex_owned_p (&mutex->mutex))
378 error ("Condition variable's mutex is not held by current thread");
379
380 flush_stack_call_func (condition_wait_callback, cvar);
381
382 return Qnil;
383}
384
385/* Used to communicate argumnets to condition_notify_callback. */
386struct notify_args
387{
388 struct Lisp_CondVar *cvar;
389 int all;
390};
391
392static void
393condition_notify_callback (void *arg)
394{
395 struct notify_args *na = arg;
396 struct Lisp_Mutex *mutex = XMUTEX (na->cvar->mutex);
397 struct thread_state *self = current_thread;
398 unsigned int saved_count;
399 Lisp_Object cond;
400
401 XSETCONDVAR (cond, na->cvar);
402 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
403 if (na->all)
404 sys_cond_broadcast (&na->cvar->cond);
405 else
406 sys_cond_signal (&na->cvar->cond);
407 lisp_mutex_lock (&mutex->mutex, saved_count);
408 post_acquire_global_lock (self);
409}
410
411DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0,
412 doc: /* Notify COND, a condition variable.
413This wakes a thread waiting on COND.
414If ALL is non-nil, all waiting threads are awoken.
415
416The mutex associated with COND must be held when this is called.
417It is an error if it is not held.
418
419This releases COND's mutex when notifying COND. When
420`condition-notify' returns, the mutex will again be locked by this
421thread. */)
422 (Lisp_Object cond, Lisp_Object all)
423{
424 struct Lisp_CondVar *cvar;
425 struct Lisp_Mutex *mutex;
426 struct notify_args args;
427
428 CHECK_CONDVAR (cond);
429 cvar = XCONDVAR (cond);
430
431 mutex = XMUTEX (cvar->mutex);
432 if (!lisp_mutex_owned_p (&mutex->mutex))
433 error ("Condition variable's mutex is not held by current thread");
434
435 args.cvar = cvar;
436 args.all = !NILP (all);
437 flush_stack_call_func (condition_notify_callback, &args);
438
439 return Qnil;
440}
441
442DEFUN ("condition-mutex", Fcondition_mutex, Scondition_mutex, 1, 1, 0,
443 doc: /* Return the mutex associated with condition variable COND. */)
444 (Lisp_Object cond)
445{
446 struct Lisp_CondVar *cvar;
447
448 CHECK_CONDVAR (cond);
449 cvar = XCONDVAR (cond);
450
451 return cvar->mutex;
452}
453
454DEFUN ("condition-name", Fcondition_name, Scondition_name, 1, 1, 0,
455 doc: /* Return the name of condition variable COND.
456If no name was given when COND was created, return nil. */)
457 (Lisp_Object cond)
458{
459 struct Lisp_CondVar *cvar;
460
461 CHECK_CONDVAR (cond);
462 cvar = XCONDVAR (cond);
463
464 return cvar->name;
465}
466
467void
468finalize_one_condvar (struct Lisp_CondVar *condvar)
469{
470 sys_cond_destroy (&condvar->cond);
471}
472
473
474
475struct select_args
476{
477 select_func *func;
478 int max_fds;
479 fd_set *rfds;
480 fd_set *wfds;
481 fd_set *efds;
482 struct timespec *timeout;
483 sigset_t *sigmask;
484 int result;
485};
486
487static void
488really_call_select (void *arg)
489{
490 struct select_args *sa = arg;
491 struct thread_state *self = current_thread;
492
493 release_global_lock ();
494 sa->result = (sa->func) (sa->max_fds, sa->rfds, sa->wfds, sa->efds,
495 sa->timeout, sa->sigmask);
496 acquire_global_lock (self);
497}
498
499int
500thread_select (select_func *func, int max_fds, fd_set *rfds,
501 fd_set *wfds, fd_set *efds, struct timespec *timeout,
502 sigset_t *sigmask)
503{
504 struct select_args sa;
505
506 sa.func = func;
507 sa.max_fds = max_fds;
508 sa.rfds = rfds;
509 sa.wfds = wfds;
510 sa.efds = efds;
511 sa.timeout = timeout;
512 sa.sigmask = sigmask;
513 flush_stack_call_func (really_call_select, &sa);
514 return sa.result;
515}
516
517
518
519static void
520mark_one_thread (struct thread_state *thread)
521{
522 struct handler *handler;
523 Lisp_Object tem;
524
525 mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr);
526
527 mark_stack (thread->m_stack_bottom, thread->stack_top);
528
529 for (handler = thread->m_handlerlist; handler; handler = handler->next)
530 {
531 mark_object (handler->tag_or_ch);
532 mark_object (handler->val);
533 }
534
535 if (thread->m_current_buffer)
536 {
537 XSETBUFFER (tem, thread->m_current_buffer);
538 mark_object (tem);
539 }
540
541 mark_object (thread->m_last_thing_searched);
542
543 if (!NILP (thread->m_saved_last_thing_searched))
544 mark_object (thread->m_saved_last_thing_searched);
545}
546
547static void
548mark_threads_callback (void *ignore)
549{
550 struct thread_state *iter;
551
552 for (iter = all_threads; iter; iter = iter->next_thread)
553 {
554 Lisp_Object thread_obj;
555
556 XSETTHREAD (thread_obj, iter);
557 mark_object (thread_obj);
558 mark_one_thread (iter);
559 }
560}
561
562void
563mark_threads (void)
564{
565 flush_stack_call_func (mark_threads_callback, NULL);
566}
567
568void
569unmark_threads (void)
570{
571 struct thread_state *iter;
572
573 for (iter = all_threads; iter; iter = iter->next_thread)
574 if (iter->m_byte_stack_list)
575 relocate_byte_stack (iter->m_byte_stack_list);
576}
577
578
579
580static void
581yield_callback (void *ignore)
582{
583 struct thread_state *self = current_thread;
584
585 release_global_lock ();
586 sys_thread_yield ();
587 acquire_global_lock (self);
588}
589
590DEFUN ("thread-yield", Fthread_yield, Sthread_yield, 0, 0, 0,
591 doc: /* Yield the CPU to another thread. */)
592 (void)
593{
594 flush_stack_call_func (yield_callback, NULL);
595 return Qnil;
596}
597
598static Lisp_Object
599invoke_thread_function (void)
600{
601 int count = SPECPDL_INDEX ();
602
603 Ffuncall (1, &current_thread->function);
604 return unbind_to (count, Qnil);
605}
606
607static Lisp_Object
608do_nothing (Lisp_Object whatever)
609{
610 return whatever;
611}
612
613static void *
614run_thread (void *state)
615{
616 char stack_pos;
617 struct thread_state *self = state;
618 struct thread_state **iter;
619
620 self->m_stack_bottom = &stack_pos;
621 self->stack_top = &stack_pos;
622 self->thread_id = sys_thread_self ();
623
624 acquire_global_lock (self);
625
626 { /* Put a dummy catcher at top-level so that handlerlist is never NULL.
627 This is important since handlerlist->nextfree holds the freelist
628 which would otherwise leak every time we unwind back to top-level. */
629 handlerlist_sentinel = xzalloc (sizeof (struct handler));
630 handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel;
631 struct handler *c = push_handler (Qunbound, CATCHER);
632 eassert (c == handlerlist_sentinel);
633 handlerlist_sentinel->nextfree = NULL;
634 handlerlist_sentinel->next = NULL;
635 }
636
637 /* It might be nice to do something with errors here. */
638 internal_condition_case (invoke_thread_function, Qt, do_nothing);
639
640 update_processes_for_thread_death (Fcurrent_thread ());
641
642 xfree (self->m_specpdl - 1);
643 self->m_specpdl = NULL;
644 self->m_specpdl_ptr = NULL;
645 self->m_specpdl_size = 0;
646
647 {
648 struct handler *c, *c_next;
649 for (c = handlerlist_sentinel; c; c = c_next)
650 {
651 c_next = c->nextfree;
652 xfree (c);
653 }
654 }
655
656 current_thread = NULL;
657 sys_cond_broadcast (&self->thread_condvar);
658
659 /* Unlink this thread from the list of all threads. Note that we
660 have to do this very late, after broadcasting our death.
661 Otherwise the GC may decide to reap the thread_state object,
662 leading to crashes. */
663 for (iter = &all_threads; *iter != self; iter = &(*iter)->next_thread)
664 ;
665 *iter = (*iter)->next_thread;
666
667 release_global_lock ();
668
669 return NULL;
670}
671
672void
673finalize_one_thread (struct thread_state *state)
674{
675 sys_cond_destroy (&state->thread_condvar);
676}
677
678DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0,
679 doc: /* Start a new thread and run FUNCTION in it.
680When the function exits, the thread dies.
681If NAME is given, it must be a string; it names the new thread. */)
682 (Lisp_Object function, Lisp_Object name)
683{
684 sys_thread_t thr;
685 struct thread_state *new_thread;
686 Lisp_Object result;
687 const char *c_name = NULL;
688 size_t offset = offsetof (struct thread_state, m_byte_stack_list);
689
690 /* Can't start a thread in temacs. */
691 if (!initialized)
692 emacs_abort ();
693
694 if (!NILP (name))
695 CHECK_STRING (name);
696
697 new_thread = ALLOCATE_PSEUDOVECTOR (struct thread_state, m_byte_stack_list,
698 PVEC_THREAD);
699 memset ((char *) new_thread + offset, 0,
700 sizeof (struct thread_state) - offset);
701
702 new_thread->function = function;
703 new_thread->name = name;
704 new_thread->m_last_thing_searched = Qnil; /* copy from parent? */
705 new_thread->m_saved_last_thing_searched = Qnil;
706 new_thread->m_current_buffer = current_thread->m_current_buffer;
707 new_thread->error_symbol = Qnil;
708 new_thread->error_data = Qnil;
709 new_thread->event_object = Qnil;
710
711 new_thread->m_specpdl_size = 50;
712 new_thread->m_specpdl = xmalloc ((1 + new_thread->m_specpdl_size)
713 * sizeof (union specbinding));
714 /* Skip the dummy entry. */
715 ++new_thread->m_specpdl;
716 new_thread->m_specpdl_ptr = new_thread->m_specpdl;
717
718 sys_cond_init (&new_thread->thread_condvar);
719
720 /* We'll need locking here eventually. */
721 new_thread->next_thread = all_threads;
722 all_threads = new_thread;
723
724 if (!NILP (name))
725 c_name = SSDATA (ENCODE_UTF_8 (name));
726
727 if (! sys_thread_create (&thr, c_name, run_thread, new_thread))
728 {
729 /* Restore the previous situation. */
730 all_threads = all_threads->next_thread;
731 error ("Could not start a new thread");
732 }
733
734 /* FIXME: race here where new thread might not be filled in? */
735 XSETTHREAD (result, new_thread);
736 return result;
737}
738
739DEFUN ("current-thread", Fcurrent_thread, Scurrent_thread, 0, 0, 0,
740 doc: /* Return the current thread. */)
741 (void)
742{
743 Lisp_Object result;
744 XSETTHREAD (result, current_thread);
745 return result;
746}
747
748DEFUN ("thread-name", Fthread_name, Sthread_name, 1, 1, 0,
749 doc: /* Return the name of the THREAD.
750The name is the same object that was passed to `make-thread'. */)
751 (Lisp_Object thread)
752{
753 struct thread_state *tstate;
754
755 CHECK_THREAD (thread);
756 tstate = XTHREAD (thread);
757
758 return tstate->name;
759}
760
761static void
762thread_signal_callback (void *arg)
763{
764 struct thread_state *tstate = arg;
765 struct thread_state *self = current_thread;
766
767 sys_cond_broadcast (tstate->wait_condvar);
768 post_acquire_global_lock (self);
769}
770
771DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0,
772 doc: /* Signal an error in a thread.
773This acts like `signal', but arranges for the signal to be raised
774in THREAD. If THREAD is the current thread, acts just like `signal'.
775This will interrupt a blocked call to `mutex-lock', `condition-wait',
776or `thread-join' in the target thread. */)
777 (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data)
778{
779 struct thread_state *tstate;
780
781 CHECK_THREAD (thread);
782 tstate = XTHREAD (thread);
783
784 if (tstate == current_thread)
785 Fsignal (error_symbol, data);
786
787 /* What to do if thread is already signalled? */
788 /* What if error_symbol is Qnil? */
789 tstate->error_symbol = error_symbol;
790 tstate->error_data = data;
791
792 if (tstate->wait_condvar)
793 flush_stack_call_func (thread_signal_callback, tstate);
794
795 return Qnil;
796}
797
798DEFUN ("thread-alive-p", Fthread_alive_p, Sthread_alive_p, 1, 1, 0,
799 doc: /* Return t if THREAD is alive, or nil if it has exited. */)
800 (Lisp_Object thread)
801{
802 struct thread_state *tstate;
803
804 CHECK_THREAD (thread);
805 tstate = XTHREAD (thread);
806
807 return thread_alive_p (tstate) ? Qt : Qnil;
808}
809
810DEFUN ("thread--blocker", Fthread_blocker, Sthread_blocker, 1, 1, 0,
811 doc: /* Return the object that THREAD is blocking on.
812If THREAD is blocked in `thread-join' on a second thread, return that
813thread.
814If THREAD is blocked in `mutex-lock', return the mutex.
815If THREAD is blocked in `condition-wait', return the condition variable.
816Otherwise, if THREAD is not blocked, return nil. */)
817 (Lisp_Object thread)
818{
819 struct thread_state *tstate;
820
821 CHECK_THREAD (thread);
822 tstate = XTHREAD (thread);
823
824 return tstate->event_object;
825}
826
827static void
828thread_join_callback (void *arg)
829{
830 struct thread_state *tstate = arg;
831 struct thread_state *self = current_thread;
832 Lisp_Object thread;
833
834 XSETTHREAD (thread, tstate);
835 self->event_object = thread;
836 self->wait_condvar = &tstate->thread_condvar;
837 while (thread_alive_p (tstate) && NILP (self->error_symbol))
838 sys_cond_wait (self->wait_condvar, &global_lock);
839
840 self->wait_condvar = NULL;
841 self->event_object = Qnil;
842 post_acquire_global_lock (self);
843}
844
845DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0,
846 doc: /* Wait for THREAD to exit.
847This blocks the current thread until THREAD exits or until
848the current thread is signaled.
849It is an error for a thread to try to join itself. */)
850 (Lisp_Object thread)
851{
852 struct thread_state *tstate;
853
854 CHECK_THREAD (thread);
855 tstate = XTHREAD (thread);
856
857 if (tstate == current_thread)
858 error ("Cannot join current thread");
859
860 if (thread_alive_p (tstate))
861 flush_stack_call_func (thread_join_callback, tstate);
862
863 return Qnil;
864}
865
866DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0,
867 doc: /* Return a list of all the live threads. */)
868 (void)
869{
870 Lisp_Object result = Qnil;
871 struct thread_state *iter;
872
873 for (iter = all_threads; iter; iter = iter->next_thread)
874 {
875 if (thread_alive_p (iter))
876 {
877 Lisp_Object thread;
878
879 XSETTHREAD (thread, iter);
880 result = Fcons (thread, result);
881 }
882 }
883
884 return result;
885}
886
887
888
889bool
890thread_check_current_buffer (struct buffer *buffer)
891{
892 struct thread_state *iter;
893
894 for (iter = all_threads; iter; iter = iter->next_thread)
895 {
896 if (iter == current_thread)
897 continue;
898
899 if (iter->m_current_buffer == buffer)
900 return true;
901 }
902
903 return false;
904}
905
906
907
908static void
909init_primary_thread (void)
910{
911 primary_thread.header.size
912 = PSEUDOVECSIZE (struct thread_state, m_byte_stack_list);
913 XSETPVECTYPE (&primary_thread, PVEC_THREAD);
914 primary_thread.m_last_thing_searched = Qnil;
915 primary_thread.m_saved_last_thing_searched = Qnil;
916 primary_thread.name = Qnil;
917 primary_thread.function = Qnil;
918 primary_thread.error_symbol = Qnil;
919 primary_thread.error_data = Qnil;
920 primary_thread.event_object = Qnil;
921}
922
923void
924init_threads_once (void)
925{
926 init_primary_thread ();
927}
928
929void
930init_threads (void)
931{
932 init_primary_thread ();
933 sys_cond_init (&primary_thread.thread_condvar);
934 sys_mutex_init (&global_lock);
935 sys_mutex_lock (&global_lock);
936 current_thread = &primary_thread;
937 primary_thread.thread_id = sys_thread_self ();
938}
939
940void
941syms_of_threads (void)
942{
943#ifndef THREADS_ENABLED
944 if (0)
945#endif
946 {
947 defsubr (&Sthread_yield);
948 defsubr (&Smake_thread);
949 defsubr (&Scurrent_thread);
950 defsubr (&Sthread_name);
951 defsubr (&Sthread_signal);
952 defsubr (&Sthread_alive_p);
953 defsubr (&Sthread_join);
954 defsubr (&Sthread_blocker);
955 defsubr (&Sall_threads);
956 defsubr (&Smake_mutex);
957 defsubr (&Smutex_lock);
958 defsubr (&Smutex_unlock);
959 defsubr (&Smutex_name);
960 defsubr (&Smake_condition_variable);
961 defsubr (&Scondition_wait);
962 defsubr (&Scondition_notify);
963 defsubr (&Scondition_mutex);
964 defsubr (&Scondition_name);
965 }
966
967 DEFSYM (Qthreadp, "threadp");
968 DEFSYM (Qmutexp, "mutexp");
969 DEFSYM (Qcondition_variable_p, "condition-variable-p");
970}