summaryrefslogtreecommitdiff
path: root/src/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread.c')
-rw-r--r--src/thread.c210
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, &current_thread->function);
+ current_thread->result = Ffuncall (1, &current_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
}