diff options
Diffstat (limited to 'src/thread.c')
-rw-r--r-- | src/thread.c | 210 |
1 files changed, 124 insertions, 86 deletions
diff --git a/src/thread.c b/src/thread.c index 47f55e7f67c..e2deadd7a83 100644 --- a/src/thread.c +++ b/src/thread.c @@ -25,16 +25,38 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "process.h" #include "coding.h" #include "syssignal.h" +#include "pdumper.h" +#include "keyboard.h" -static struct thread_state main_thread; - -struct thread_state *current_thread = &main_thread; - -static struct thread_state *all_threads = &main_thread; +union aligned_thread_state +{ + struct thread_state s; + GCALIGNED_UNION_MEMBER +}; +verify (GCALIGNED (union aligned_thread_state)); + +static union aligned_thread_state main_thread + = {{ + .header.size = PVECHEADERSIZE (PVEC_THREAD, + PSEUDOVECSIZE (struct thread_state, + event_object), + VECSIZE (struct thread_state)), + .m_last_thing_searched = LISPSYM_INITIALLY (Qnil), + .m_saved_last_thing_searched = LISPSYM_INITIALLY (Qnil), + .name = LISPSYM_INITIALLY (Qnil), + .function = LISPSYM_INITIALLY (Qnil), + .result = LISPSYM_INITIALLY (Qnil), + .error_symbol = LISPSYM_INITIALLY (Qnil), + .error_data = LISPSYM_INITIALLY (Qnil), + .event_object = LISPSYM_INITIALLY (Qnil), + }}; + +struct thread_state *current_thread = &main_thread.s; + +static struct thread_state *all_threads = &main_thread.s; static sys_mutex_t global_lock; -extern int poll_suppress_count; extern volatile int interrupt_input_blocked; @@ -113,7 +135,7 @@ maybe_reacquire_global_lock (void) /* SIGINT handler is always run on the main thread, see deliver_process_signal, so reflect that in our thread-tracking variables. */ - current_thread = &main_thread; + current_thread = &main_thread.s; if (current_thread->not_holding_lock) { @@ -253,19 +275,15 @@ NAME, if given, is used as the name of the mutex. The name is informational only. */) (Lisp_Object name) { - struct Lisp_Mutex *mutex; - Lisp_Object result; - if (!NILP (name)) CHECK_STRING (name); - mutex = ALLOCATE_PSEUDOVECTOR (struct Lisp_Mutex, mutex, PVEC_MUTEX); - memset ((char *) mutex + offsetof (struct Lisp_Mutex, mutex), - 0, sizeof (struct Lisp_Mutex) - offsetof (struct Lisp_Mutex, - mutex)); + struct Lisp_Mutex *mutex + = ALLOCATE_ZEROED_PSEUDOVECTOR (struct Lisp_Mutex, name, PVEC_MUTEX); mutex->name = name; lisp_mutex_init (&mutex->mutex); + Lisp_Object result; XSETMUTEX (result, mutex); return result; } @@ -371,21 +389,17 @@ NAME, if given, is the name of this condition variable. The name is informational only. */) (Lisp_Object mutex, Lisp_Object name) { - struct Lisp_CondVar *condvar; - Lisp_Object result; - CHECK_MUTEX (mutex); if (!NILP (name)) CHECK_STRING (name); - condvar = ALLOCATE_PSEUDOVECTOR (struct Lisp_CondVar, cond, PVEC_CONDVAR); - memset ((char *) condvar + offsetof (struct Lisp_CondVar, cond), - 0, sizeof (struct Lisp_CondVar) - offsetof (struct Lisp_CondVar, - cond)); + struct Lisp_CondVar *condvar + = ALLOCATE_ZEROED_PSEUDOVECTOR (struct Lisp_CondVar, name, PVEC_CONDVAR); condvar->mutex = mutex; condvar->name = name; sys_cond_init (&condvar->cond); + Lisp_Object result; XSETCONDVAR (result, condvar); return result; } @@ -609,7 +623,7 @@ static void mark_one_thread (struct thread_state *thread) { /* Get the stack top now, in case mark_specpdl changes it. */ - void *stack_top = thread->stack_top; + void const *stack_top = thread->stack_top; mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr); @@ -629,10 +643,8 @@ mark_one_thread (struct thread_state *thread) mark_object (tem); } - mark_object (thread->m_last_thing_searched); - - if (!NILP (thread->m_saved_last_thing_searched)) - mark_object (thread->m_saved_last_thing_searched); + /* No need to mark Lisp_Object members like m_last_thing_searched, + as mark_threads_callback does that by calling mark_object. */ } static void @@ -659,7 +671,7 @@ mark_threads (void) void unmark_main_thread (void) { - main_thread.header.size &= ~ARRAY_MARK_FLAG; + main_thread.s.header.size &= ~ARRAY_MARK_FLAG; } @@ -687,7 +699,7 @@ invoke_thread_function (void) { ptrdiff_t count = SPECPDL_INDEX (); - Ffuncall (1, ¤t_thread->function); + current_thread->result = Ffuncall (1, ¤t_thread->function); return unbind_to (count, Qnil); } @@ -760,9 +772,21 @@ run_thread (void *state) return NULL; } +static void +free_search_regs (struct re_registers *regs) +{ + if (regs->num_regs != 0) + { + xfree (regs->start); + xfree (regs->end); + } +} + void finalize_one_thread (struct thread_state *state) { + free_search_regs (&state->m_search_regs); + free_search_regs (&state->m_saved_search_regs); sys_cond_destroy (&state->thread_condvar); } @@ -772,12 +796,6 @@ When the function exits, the thread dies. If NAME is given, it must be a string; it names the new thread. */) (Lisp_Object function, Lisp_Object name) { - sys_thread_t thr; - struct thread_state *new_thread; - Lisp_Object result; - const char *c_name = NULL; - size_t offset = offsetof (struct thread_state, m_stack_bottom); - /* Can't start a thread in temacs. */ if (!initialized) emacs_abort (); @@ -785,19 +803,13 @@ If NAME is given, it must be a string; it names the new thread. */) if (!NILP (name)) CHECK_STRING (name); - new_thread = ALLOCATE_PSEUDOVECTOR (struct thread_state, m_stack_bottom, - PVEC_THREAD); - memset ((char *) new_thread + offset, 0, - sizeof (struct thread_state) - offset); - + struct thread_state *new_thread + = ALLOCATE_ZEROED_PSEUDOVECTOR (struct thread_state, event_object, + PVEC_THREAD); new_thread->function = function; new_thread->name = name; - new_thread->m_last_thing_searched = Qnil; /* copy from parent? */ - new_thread->m_saved_last_thing_searched = Qnil; + /* Perhaps copy m_last_thing_searched from parent? */ new_thread->m_current_buffer = current_thread->m_current_buffer; - new_thread->error_symbol = Qnil; - new_thread->error_data = Qnil; - new_thread->event_object = Qnil; new_thread->m_specpdl_size = 50; new_thread->m_specpdl = xmalloc ((1 + new_thread->m_specpdl_size) @@ -812,9 +824,8 @@ If NAME is given, it must be a string; it names the new thread. */) new_thread->next_thread = all_threads; all_threads = new_thread; - if (!NILP (name)) - c_name = SSDATA (ENCODE_UTF_8 (name)); - + char const *c_name = !NILP (name) ? SSDATA (ENCODE_UTF_8 (name)) : NULL; + sys_thread_t thr; if (! sys_thread_create (&thr, c_name, run_thread, new_thread)) { /* Restore the previous situation. */ @@ -827,6 +838,7 @@ If NAME is given, it must be a string; it names the new thread. */) } /* FIXME: race here where new thread might not be filled in? */ + Lisp_Object result; XSETTHREAD (result, new_thread); return result; } @@ -868,7 +880,8 @@ DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0, This acts like `signal', but arranges for the signal to be raised in THREAD. If THREAD is the current thread, acts just like `signal'. This will interrupt a blocked call to `mutex-lock', `condition-wait', -or `thread-join' in the target thread. */) +or `thread-join' in the target thread. +If THREAD is the main thread, just the error message is shown. */) (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data) { struct thread_state *tstate; @@ -879,13 +892,31 @@ or `thread-join' in the target thread. */) if (tstate == current_thread) Fsignal (error_symbol, data); - /* What to do if thread is already signaled? */ - /* What if error_symbol is Qnil? */ - tstate->error_symbol = error_symbol; - tstate->error_data = data; +#ifdef THREADS_ENABLED + if (main_thread_p (tstate)) + { + /* Construct an event. */ + struct input_event event; + EVENT_INIT (event); + event.kind = THREAD_EVENT; + event.frame_or_window = Qnil; + event.arg = list3 (Fcurrent_thread (), error_symbol, data); + + /* Store it into the input event queue. */ + kbd_buffer_store_event (&event); + } - if (tstate->wait_condvar) - flush_stack_call_func (thread_signal_callback, tstate); + else +#endif + { + /* What to do if thread is already signaled? */ + /* What if error_symbol is Qnil? */ + tstate->error_symbol = error_symbol; + tstate->error_data = data; + + if (tstate->wait_condvar) + flush_stack_call_func (thread_signal_callback, tstate); + } return Qnil; } @@ -939,12 +970,13 @@ thread_join_callback (void *arg) DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0, doc: /* Wait for THREAD to exit. -This blocks the current thread until THREAD exits or until -the current thread is signaled. -It is an error for a thread to try to join itself. */) +This blocks the current thread until THREAD exits or until the current +thread is signaled. It returns the result of the THREAD function. It +is an error for a thread to try to join itself. */) (Lisp_Object thread) { struct thread_state *tstate; + Lisp_Object error_symbol, error_data; CHECK_THREAD (thread); tstate = XTHREAD (thread); @@ -952,10 +984,16 @@ It is an error for a thread to try to join itself. */) if (tstate == current_thread) error ("Cannot join current thread"); + error_symbol = tstate->error_symbol; + error_data = tstate->error_data; + if (thread_live_p (tstate)) flush_stack_call_func (thread_join_callback, tstate); - return Qnil; + if (!NILP (error_symbol)) + Fsignal (error_symbol, error_data); + + return tstate->result; } DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0, @@ -979,11 +1017,17 @@ DEFUN ("all-threads", Fall_threads, Sall_threads, 0, 0, 0, return result; } -DEFUN ("thread-last-error", Fthread_last_error, Sthread_last_error, 0, 0, 0, - doc: /* Return the last error form recorded by a dying thread. */) - (void) +DEFUN ("thread-last-error", Fthread_last_error, Sthread_last_error, 0, 1, 0, + doc: /* Return the last error form recorded by a dying thread. +If CLEANUP is non-nil, remove this error form from history. */) + (Lisp_Object cleanup) { - return last_thread_error; + Lisp_Object result = last_thread_error; + + if (!NILP (cleanup)) + last_thread_error = Qnil; + + return result; } @@ -1007,42 +1051,28 @@ thread_check_current_buffer (struct buffer *buffer) -static void -init_main_thread (void) -{ - main_thread.header.size - = PSEUDOVECSIZE (struct thread_state, m_stack_bottom); - XSETPVECTYPE (&main_thread, PVEC_THREAD); - main_thread.m_last_thing_searched = Qnil; - main_thread.m_saved_last_thing_searched = Qnil; - main_thread.name = Qnil; - main_thread.function = Qnil; - main_thread.error_symbol = Qnil; - main_thread.error_data = Qnil; - main_thread.event_object = Qnil; -} - bool -main_thread_p (void *ptr) +main_thread_p (const void *ptr) { - return ptr == &main_thread; + return ptr == &main_thread.s; } -void -init_threads_once (void) +bool +in_current_thread (void) { - init_main_thread (); + if (current_thread == NULL) + return false; + return sys_thread_equal (sys_thread_self (), current_thread->thread_id); } void init_threads (void) { - init_main_thread (); - sys_cond_init (&main_thread.thread_condvar); + sys_cond_init (&main_thread.s.thread_condvar); sys_mutex_init (&global_lock); sys_mutex_lock (&global_lock); - current_thread = &main_thread; - main_thread.thread_id = sys_thread_self (); + current_thread = &main_thread.s; + main_thread.s.thread_id = sys_thread_self (); } void @@ -1084,4 +1114,12 @@ syms_of_threads (void) DEFSYM (Qthreadp, "threadp"); DEFSYM (Qmutexp, "mutexp"); DEFSYM (Qcondition_variable_p, "condition-variable-p"); + + DEFVAR_LISP ("main-thread", Vmain_thread, + doc: /* The main thread of Emacs. */); +#ifdef THREADS_ENABLED + XSETTHREAD (Vmain_thread, &main_thread.s); +#else + Vmain_thread = Qnil; +#endif } |