mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-02 18:21:19 -08:00
dc4e6b1329; Update copyright years in more files64b3777631; Run set-copyright from admin.el8e1c56ae46; Add 2024 to copyright years # Conflicts: # doc/misc/modus-themes.org # doc/misc/texinfo.tex # etc/NEWS # etc/refcards/ru-refcard.tex # etc/themes/modus-operandi-theme.el # etc/themes/modus-themes.el # etc/themes/modus-vivendi-theme.el # lib/alloca.in.h # lib/binary-io.h # lib/c-ctype.h # lib/c-strcasecmp.c # lib/c-strncasecmp.c # lib/careadlinkat.c # lib/cloexec.c # lib/close-stream.c # lib/diffseq.h # lib/dup2.c # lib/filemode.h # lib/fpending.c # lib/fpending.h # lib/fsusage.c # lib/getgroups.c # lib/getloadavg.c # lib/gettext.h # lib/gettime.c # lib/gettimeofday.c # lib/group-member.c # lib/malloc.c # lib/md5-stream.c # lib/md5.c # lib/md5.h # lib/memmem.c # lib/memrchr.c # lib/nanosleep.c # lib/save-cwd.h # lib/sha1.c # lib/sig2str.c # lib/stdlib.in.h # lib/strtoimax.c # lib/strtol.c # lib/strtoll.c # lib/time_r.c # lib/xalloc-oversized.h # lisp/auth-source-pass.el # lisp/emacs-lisp/lisp-mnt.el # lisp/emacs-lisp/timer.el # lisp/info-look.el # lisp/jit-lock.el # lisp/loadhist.el # lisp/mail/rmail.el # lisp/net/ntlm.el # lisp/net/webjump.el # lisp/progmodes/asm-mode.el # lisp/progmodes/project.el # lisp/progmodes/sh-script.el # lisp/textmodes/flyspell.el # lisp/textmodes/reftex-toc.el # lisp/textmodes/reftex.el # lisp/textmodes/tex-mode.el # lisp/url/url-gw.el # m4/alloca.m4 # m4/clock_time.m4 # m4/d-type.m4 # m4/dirent_h.m4 # m4/dup2.m4 # m4/euidaccess.m4 # m4/fchmodat.m4 # m4/filemode.m4 # m4/fsusage.m4 # m4/getgroups.m4 # m4/getloadavg.m4 # m4/getrandom.m4 # m4/gettime.m4 # m4/gettimeofday.m4 # m4/gnulib-common.m4 # m4/group-member.m4 # m4/inttypes.m4 # m4/malloc.m4 # m4/manywarnings.m4 # m4/mempcpy.m4 # m4/memrchr.m4 # m4/mkostemp.m4 # m4/mktime.m4 # m4/nproc.m4 # m4/nstrftime.m4 # m4/pathmax.m4 # m4/pipe2.m4 # m4/pselect.m4 # m4/pthread_sigmask.m4 # m4/readlink.m4 # m4/realloc.m4 # m4/sig2str.m4 # m4/ssize_t.m4 # m4/stat-time.m4 # m4/stddef_h.m4 # m4/stdint.m4 # m4/stdio_h.m4 # m4/stdlib_h.m4 # m4/stpcpy.m4 # m4/strnlen.m4 # m4/strtoimax.m4 # m4/strtoll.m4 # m4/time_h.m4 # m4/timegm.m4 # m4/timer_time.m4 # m4/timespec.m4 # m4/unistd_h.m4 # m4/warnings.m4 # nt/configure.bat # nt/preprep.c # test/lisp/register-tests.el
331 lines
10 KiB
C
331 lines
10 KiB
C
/* Thread definitions
|
|
Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Emacs.
|
|
|
|
GNU Emacs is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
GNU Emacs is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef THREAD_H
|
|
#define THREAD_H
|
|
|
|
#include "regex-emacs.h"
|
|
|
|
#ifdef WINDOWSNT
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
#ifdef MSDOS
|
|
#include <time.h> /* struct rpl_timespec */
|
|
#include <signal.h> /* sigset_t */
|
|
#endif
|
|
|
|
#include "sysselect.h" /* FIXME */
|
|
#include "systhread.h"
|
|
|
|
/* Yield an address close enough to the top of the stack that the
|
|
garbage collector need not scan above it. Callers should be
|
|
declared NO_INLINE. */
|
|
#ifdef HAVE___BUILTIN_FRAME_ADDRESS
|
|
# define NEAR_STACK_TOP(addr) ((void) (addr), __builtin_frame_address (0))
|
|
#else
|
|
# define NEAR_STACK_TOP(addr) (addr)
|
|
#endif
|
|
|
|
INLINE_HEADER_BEGIN
|
|
|
|
/* Byte-code interpreter thread state. */
|
|
struct bc_thread_state {
|
|
struct bc_frame *fp; /* current frame pointer */
|
|
|
|
/* start and end of allocated bytecode stack */
|
|
char *stack;
|
|
char *stack_end;
|
|
};
|
|
|
|
struct thread_state
|
|
{
|
|
union vectorlike_header header;
|
|
|
|
/* The buffer in which the last search was performed, or
|
|
Qt if the last search was done in a string;
|
|
Qnil if no searching has been done yet. */
|
|
Lisp_Object m_last_thing_searched;
|
|
#define last_thing_searched (current_thread->m_last_thing_searched)
|
|
|
|
Lisp_Object m_saved_last_thing_searched;
|
|
#define saved_last_thing_searched (current_thread->m_saved_last_thing_searched)
|
|
|
|
/* The thread's name. */
|
|
Lisp_Object name;
|
|
|
|
/* The thread's function. */
|
|
Lisp_Object function;
|
|
|
|
/* The thread's result, if function has finished. */
|
|
Lisp_Object result;
|
|
|
|
/* If non-nil, this thread has been signaled. */
|
|
Lisp_Object error_symbol;
|
|
Lisp_Object error_data;
|
|
|
|
/* If we are waiting for some event, this holds the object we are
|
|
waiting on. */
|
|
Lisp_Object event_object;
|
|
/* event_object must be the last Lisp field. */
|
|
|
|
/* An address near the bottom of the stack.
|
|
Tells GC how to save a copy of the stack. */
|
|
char const *m_stack_bottom;
|
|
#define stack_bottom (current_thread->m_stack_bottom)
|
|
|
|
/* The address of an object near the C stack top, used to determine
|
|
which words need to be scanned by the garbage collector. This is
|
|
also used to detect heuristically whether segmentation violation
|
|
address indicates stack overflow, as opposed to some internal
|
|
error in Emacs. If the C function F calls G which calls H which
|
|
calls ... F, then at least one of the functions in the chain
|
|
should set this to the address of a local variable. */
|
|
void const *stack_top;
|
|
|
|
struct catchtag *m_catchlist;
|
|
#define catchlist (current_thread->m_catchlist)
|
|
|
|
/* Chain of condition handlers currently in effect.
|
|
The elements of this chain are contained in the stack frames
|
|
of Fcondition_case and internal_condition_case.
|
|
When an error is signaled (by calling Fsignal),
|
|
this chain is searched for an element that applies. */
|
|
struct handler *m_handlerlist;
|
|
#define handlerlist (current_thread->m_handlerlist)
|
|
|
|
struct handler *m_handlerlist_sentinel;
|
|
#define handlerlist_sentinel (current_thread->m_handlerlist_sentinel)
|
|
|
|
/* Pointer to beginning of specpdl. */
|
|
union specbinding *m_specpdl;
|
|
#define specpdl (current_thread->m_specpdl)
|
|
|
|
/* End of specpld (just beyond the last element). */
|
|
union specbinding *m_specpdl_end;
|
|
#define specpdl_end (current_thread->m_specpdl_end)
|
|
|
|
/* Pointer to first unused element in specpdl. */
|
|
union specbinding *m_specpdl_ptr;
|
|
#define specpdl_ptr (current_thread->m_specpdl_ptr)
|
|
|
|
/* Depth in Lisp evaluations and function calls. */
|
|
intmax_t m_lisp_eval_depth;
|
|
#define lisp_eval_depth (current_thread->m_lisp_eval_depth)
|
|
|
|
/* This points to the current buffer. */
|
|
struct buffer *m_current_buffer;
|
|
#define current_buffer (current_thread->m_current_buffer)
|
|
|
|
/* Every call to re_search, etc., must pass &search_regs as the regs
|
|
argument unless you can show it is unnecessary (i.e., if re_search
|
|
is certainly going to be called again before region-around-match
|
|
can be called).
|
|
|
|
Since the registers are now dynamically allocated, we need to make
|
|
sure not to refer to the Nth register before checking that it has
|
|
been allocated by checking search_regs.num_regs.
|
|
|
|
The regex code keeps track of whether it has allocated the search
|
|
buffer using bits in the re_pattern_buffer. This means that whenever
|
|
you compile a new pattern, it completely forgets whether it has
|
|
allocated any registers, and will allocate new registers the next
|
|
time you call a searching or matching function. Therefore, we need
|
|
to call re_set_registers after compiling a new pattern or after
|
|
setting the match registers, so that the regex functions will be
|
|
able to free or re-allocate it properly. */
|
|
struct re_registers m_search_regs;
|
|
#define search_regs (current_thread->m_search_regs)
|
|
|
|
struct re_registers m_saved_search_regs;
|
|
#define saved_search_regs (current_thread->m_saved_search_regs)
|
|
|
|
/* This member is different from waiting_for_input.
|
|
It is used to communicate to a lisp process-filter/sentinel (via the
|
|
function Fwaiting_for_user_input_p) whether Emacs was waiting
|
|
for user-input when that process-filter was called.
|
|
waiting_for_input cannot be used as that is by definition 0 when
|
|
lisp code is being evalled.
|
|
For that purpose, this must be 0
|
|
when not inside wait_reading_process_output. */
|
|
int m_waiting_for_user_input_p;
|
|
#define waiting_for_user_input_p (current_thread->m_waiting_for_user_input_p)
|
|
|
|
/* True while doing kbd input. */
|
|
bool m_waiting_for_input;
|
|
#define waiting_for_input (current_thread->m_waiting_for_input)
|
|
|
|
/* For longjmp to where kbd input is being done. This is per-thread
|
|
so that if more than one thread calls read_char, they don't
|
|
clobber each other's getcjmp, which will cause
|
|
quit_throw_to_read_char crash due to using a wrong stack. */
|
|
sys_jmp_buf m_getcjmp;
|
|
#define getcjmp (current_thread->m_getcjmp)
|
|
|
|
/* The OS identifier for this thread. */
|
|
sys_thread_t thread_id;
|
|
|
|
/* The condition variable for this thread. This is associated with
|
|
the global lock. This thread broadcasts to it when it exits. */
|
|
sys_cond_t thread_condvar;
|
|
|
|
/* This thread might be waiting for some condition. If so, this
|
|
points to the condition. If the thread is interrupted, the
|
|
interrupter should broadcast to this condition. */
|
|
sys_cond_t *wait_condvar;
|
|
|
|
/* Thread's name in the locale encoding. */
|
|
char *thread_name;
|
|
|
|
/* This thread might have released the global lock. If so, this is
|
|
non-zero. When a thread runs outside thread_select with this
|
|
flag non-zero, it means it has been interrupted by SIGINT while
|
|
in thread_select, and didn't have a chance of acquiring the lock.
|
|
It must do so ASAP. */
|
|
int not_holding_lock;
|
|
|
|
/* Threads are kept on a linked list. */
|
|
struct thread_state *next_thread;
|
|
|
|
struct bc_thread_state bc;
|
|
} GCALIGNED_STRUCT;
|
|
|
|
INLINE bool
|
|
THREADP (Lisp_Object a)
|
|
{
|
|
return PSEUDOVECTORP (a, PVEC_THREAD);
|
|
}
|
|
|
|
INLINE void
|
|
CHECK_THREAD (Lisp_Object x)
|
|
{
|
|
CHECK_TYPE (THREADP (x), Qthreadp, x);
|
|
}
|
|
|
|
INLINE struct thread_state *
|
|
XTHREAD (Lisp_Object a)
|
|
{
|
|
eassert (THREADP (a));
|
|
return XUNTAG (a, Lisp_Vectorlike, struct thread_state);
|
|
}
|
|
|
|
/* A mutex in lisp is represented by a system condition variable.
|
|
The system mutex associated with this condition variable is the
|
|
global lock.
|
|
|
|
Using a condition variable lets us implement interruptibility for
|
|
lisp mutexes. */
|
|
typedef struct
|
|
{
|
|
/* The owning thread, or NULL if unlocked. */
|
|
struct thread_state *owner;
|
|
/* The lock count. */
|
|
unsigned int count;
|
|
/* The underlying system condition variable. */
|
|
sys_cond_t condition;
|
|
} lisp_mutex_t;
|
|
|
|
/* A mutex as a lisp object. */
|
|
struct Lisp_Mutex
|
|
{
|
|
union vectorlike_header header;
|
|
|
|
/* The name of the mutex, or nil. */
|
|
Lisp_Object name;
|
|
|
|
/* The lower-level mutex object. */
|
|
lisp_mutex_t mutex;
|
|
} GCALIGNED_STRUCT;
|
|
|
|
INLINE bool
|
|
MUTEXP (Lisp_Object a)
|
|
{
|
|
return PSEUDOVECTORP (a, PVEC_MUTEX);
|
|
}
|
|
|
|
INLINE void
|
|
CHECK_MUTEX (Lisp_Object x)
|
|
{
|
|
CHECK_TYPE (MUTEXP (x), Qmutexp, x);
|
|
}
|
|
|
|
INLINE struct Lisp_Mutex *
|
|
XMUTEX (Lisp_Object a)
|
|
{
|
|
eassert (MUTEXP (a));
|
|
return XUNTAG (a, Lisp_Vectorlike, struct Lisp_Mutex);
|
|
}
|
|
|
|
/* A condition variable as a lisp object. */
|
|
struct Lisp_CondVar
|
|
{
|
|
union vectorlike_header header;
|
|
|
|
/* The associated mutex. */
|
|
Lisp_Object mutex;
|
|
|
|
/* The name of the condition variable, or nil. */
|
|
Lisp_Object name;
|
|
|
|
/* The lower-level condition variable object. */
|
|
sys_cond_t cond;
|
|
} GCALIGNED_STRUCT;
|
|
|
|
INLINE bool
|
|
CONDVARP (Lisp_Object a)
|
|
{
|
|
return PSEUDOVECTORP (a, PVEC_CONDVAR);
|
|
}
|
|
|
|
INLINE void
|
|
CHECK_CONDVAR (Lisp_Object x)
|
|
{
|
|
CHECK_TYPE (CONDVARP (x), Qcondition_variable_p, x);
|
|
}
|
|
|
|
INLINE struct Lisp_CondVar *
|
|
XCONDVAR (Lisp_Object a)
|
|
{
|
|
eassert (CONDVARP (a));
|
|
return XUNTAG (a, Lisp_Vectorlike, struct Lisp_CondVar);
|
|
}
|
|
|
|
extern struct thread_state *current_thread;
|
|
|
|
extern void finalize_one_thread (struct thread_state *state);
|
|
extern void finalize_one_mutex (struct Lisp_Mutex *);
|
|
extern void finalize_one_condvar (struct Lisp_CondVar *);
|
|
extern void maybe_reacquire_global_lock (void);
|
|
|
|
extern void init_threads (void);
|
|
extern void syms_of_threads (void);
|
|
extern bool main_thread_p (const void *);
|
|
extern bool in_current_thread (void);
|
|
|
|
typedef int select_func (int, fd_set *, fd_set *, fd_set *,
|
|
const struct timespec *, const sigset_t *);
|
|
|
|
int thread_select (select_func *func, int max_fds, fd_set *rfds,
|
|
fd_set *wfds, fd_set *efds, struct timespec *timeout,
|
|
sigset_t *sigmask);
|
|
|
|
bool thread_check_current_buffer (struct buffer *);
|
|
|
|
INLINE_HEADER_END
|
|
|
|
#endif /* THREAD_H */
|