diff options
| author | Eli Zaretskii | 2016-12-10 18:54:43 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2016-12-10 18:54:43 +0200 |
| commit | 2412a1fc05fe9f89b171d0781c2d530923f48adc (patch) | |
| tree | d42a5d2608e65a10b1cc23c6b4609d54bef25d49 /src/thread.h | |
| parent | fc0fd24c105bde4c001ebebe4b8b7e1f96cd2871 (diff) | |
| parent | 828b4560cd4a0d8cb9b7a7a3e20ff0c53ba86cfa (diff) | |
| download | emacs-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.h')
| -rw-r--r-- | src/thread.h | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 00000000000..a9de754d6b4 --- /dev/null +++ b/src/thread.h | |||
| @@ -0,0 +1,237 @@ | |||
| 1 | /* Thread definitions | ||
| 2 | Copyright (C) 2012, 2013 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | #ifndef THREAD_H | ||
| 20 | #define THREAD_H | ||
| 21 | |||
| 22 | #include <sys/types.h> /* for ssize_t used by regex.h */ | ||
| 23 | #include "regex.h" | ||
| 24 | |||
| 25 | #ifdef WINDOWSNT | ||
| 26 | #include <sys/socket.h> | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #include "sysselect.h" /* FIXME */ | ||
| 30 | #include "systime.h" /* FIXME */ | ||
| 31 | |||
| 32 | struct thread_state | ||
| 33 | { | ||
| 34 | struct vectorlike_header header; | ||
| 35 | |||
| 36 | /* The buffer in which the last search was performed, or | ||
| 37 | Qt if the last search was done in a string; | ||
| 38 | Qnil if no searching has been done yet. */ | ||
| 39 | Lisp_Object m_last_thing_searched; | ||
| 40 | #define last_thing_searched (current_thread->m_last_thing_searched) | ||
| 41 | |||
| 42 | Lisp_Object m_saved_last_thing_searched; | ||
| 43 | #define saved_last_thing_searched (current_thread->m_saved_last_thing_searched) | ||
| 44 | |||
| 45 | /* The thread's name. */ | ||
| 46 | Lisp_Object name; | ||
| 47 | |||
| 48 | /* The thread's function. */ | ||
| 49 | Lisp_Object function; | ||
| 50 | |||
| 51 | /* If non-nil, this thread has been signalled. */ | ||
| 52 | Lisp_Object error_symbol; | ||
| 53 | Lisp_Object error_data; | ||
| 54 | |||
| 55 | /* If we are waiting for some event, this holds the object we are | ||
| 56 | waiting on. */ | ||
| 57 | Lisp_Object event_object; | ||
| 58 | |||
| 59 | /* m_byte_stack_list must be the first non-lisp field. */ | ||
| 60 | /* A list of currently active byte-code execution value stacks. | ||
| 61 | Fbyte_code adds an entry to the head of this list before it starts | ||
| 62 | processing byte-code, and it removed the entry again when it is | ||
| 63 | done. Signalling an error truncates the list. */ | ||
| 64 | struct byte_stack *m_byte_stack_list; | ||
| 65 | #define byte_stack_list (current_thread->m_byte_stack_list) | ||
| 66 | |||
| 67 | /* An address near the bottom of the stack. | ||
| 68 | Tells GC how to save a copy of the stack. */ | ||
| 69 | char *m_stack_bottom; | ||
| 70 | #define stack_bottom (current_thread->m_stack_bottom) | ||
| 71 | |||
| 72 | /* An address near the top of the stack. */ | ||
| 73 | char *stack_top; | ||
| 74 | |||
| 75 | struct catchtag *m_catchlist; | ||
| 76 | #define catchlist (current_thread->m_catchlist) | ||
| 77 | |||
| 78 | /* Chain of condition handlers currently in effect. | ||
| 79 | The elements of this chain are contained in the stack frames | ||
| 80 | of Fcondition_case and internal_condition_case. | ||
| 81 | When an error is signaled (by calling Fsignal, below), | ||
| 82 | this chain is searched for an element that applies. */ | ||
| 83 | struct handler *m_handlerlist; | ||
| 84 | #define handlerlist (current_thread->m_handlerlist) | ||
| 85 | |||
| 86 | struct handler *m_handlerlist_sentinel; | ||
| 87 | #define handlerlist_sentinel (current_thread->m_handlerlist_sentinel) | ||
| 88 | |||
| 89 | /* Current number of specbindings allocated in specpdl. */ | ||
| 90 | ptrdiff_t m_specpdl_size; | ||
| 91 | #define specpdl_size (current_thread->m_specpdl_size) | ||
| 92 | |||
| 93 | /* Pointer to beginning of specpdl. */ | ||
| 94 | union specbinding *m_specpdl; | ||
| 95 | #define specpdl (current_thread->m_specpdl) | ||
| 96 | |||
| 97 | /* Pointer to first unused element in specpdl. */ | ||
| 98 | union specbinding *m_specpdl_ptr; | ||
| 99 | #define specpdl_ptr (current_thread->m_specpdl_ptr) | ||
| 100 | |||
| 101 | /* Depth in Lisp evaluations and function calls. */ | ||
| 102 | EMACS_INT m_lisp_eval_depth; | ||
| 103 | #define lisp_eval_depth (current_thread->m_lisp_eval_depth) | ||
| 104 | |||
| 105 | /* This points to the current buffer. */ | ||
| 106 | struct buffer *m_current_buffer; | ||
| 107 | #define current_buffer (current_thread->m_current_buffer) | ||
| 108 | |||
| 109 | /* Every call to re_match, etc., must pass &search_regs as the regs | ||
| 110 | argument unless you can show it is unnecessary (i.e., if re_match | ||
| 111 | is certainly going to be called again before region-around-match | ||
| 112 | can be called). | ||
| 113 | |||
| 114 | Since the registers are now dynamically allocated, we need to make | ||
| 115 | sure not to refer to the Nth register before checking that it has | ||
| 116 | been allocated by checking search_regs.num_regs. | ||
| 117 | |||
| 118 | The regex code keeps track of whether it has allocated the search | ||
| 119 | buffer using bits in the re_pattern_buffer. This means that whenever | ||
| 120 | you compile a new pattern, it completely forgets whether it has | ||
| 121 | allocated any registers, and will allocate new registers the next | ||
| 122 | time you call a searching or matching function. Therefore, we need | ||
| 123 | to call re_set_registers after compiling a new pattern or after | ||
| 124 | setting the match registers, so that the regex functions will be | ||
| 125 | able to free or re-allocate it properly. */ | ||
| 126 | struct re_registers m_search_regs; | ||
| 127 | #define search_regs (current_thread->m_search_regs) | ||
| 128 | |||
| 129 | /* If non-zero the match data have been saved in saved_search_regs | ||
| 130 | during the execution of a sentinel or filter. */ | ||
| 131 | bool m_search_regs_saved; | ||
| 132 | #define search_regs_saved (current_thread->m_search_regs_saved) | ||
| 133 | |||
| 134 | struct re_registers m_saved_search_regs; | ||
| 135 | #define saved_search_regs (current_thread->m_saved_search_regs) | ||
| 136 | |||
| 137 | /* This is the string or buffer in which we | ||
| 138 | are matching. It is used for looking up syntax properties. | ||
| 139 | |||
| 140 | If the value is a Lisp string object, we are matching text in that | ||
| 141 | string; if it's nil, we are matching text in the current buffer; if | ||
| 142 | it's t, we are matching text in a C string. */ | ||
| 143 | Lisp_Object m_re_match_object; | ||
| 144 | #define re_match_object (current_thread->m_re_match_object) | ||
| 145 | |||
| 146 | /* This variable is different from waiting_for_input in keyboard.c. | ||
| 147 | It is used to communicate to a lisp process-filter/sentinel (via the | ||
| 148 | function Fwaiting_for_user_input_p) whether Emacs was waiting | ||
| 149 | for user-input when that process-filter was called. | ||
| 150 | waiting_for_input cannot be used as that is by definition 0 when | ||
| 151 | lisp code is being evalled. | ||
| 152 | This is also used in record_asynch_buffer_change. | ||
| 153 | For that purpose, this must be 0 | ||
| 154 | when not inside wait_reading_process_output. */ | ||
| 155 | int m_waiting_for_user_input_p; | ||
| 156 | #define waiting_for_user_input_p (current_thread->m_waiting_for_user_input_p) | ||
| 157 | |||
| 158 | /* The OS identifier for this thread. */ | ||
| 159 | sys_thread_t thread_id; | ||
| 160 | |||
| 161 | /* The condition variable for this thread. This is associated with | ||
| 162 | the global lock. This thread broadcasts to it when it exits. */ | ||
| 163 | sys_cond_t thread_condvar; | ||
| 164 | |||
| 165 | /* This thread might be waiting for some condition. If so, this | ||
| 166 | points to the condition. If the thread is interrupted, the | ||
| 167 | interrupter should broadcast to this condition. */ | ||
| 168 | sys_cond_t *wait_condvar; | ||
| 169 | |||
| 170 | /* Threads are kept on a linked list. */ | ||
| 171 | struct thread_state *next_thread; | ||
| 172 | }; | ||
| 173 | |||
| 174 | /* A mutex in lisp is represented by a system condition variable. | ||
| 175 | The system mutex associated with this condition variable is the | ||
| 176 | global lock. | ||
| 177 | |||
| 178 | Using a condition variable lets us implement interruptibility for | ||
| 179 | lisp mutexes. */ | ||
| 180 | typedef struct | ||
| 181 | { | ||
| 182 | /* The owning thread, or NULL if unlocked. */ | ||
| 183 | struct thread_state *owner; | ||
| 184 | /* The lock count. */ | ||
| 185 | unsigned int count; | ||
| 186 | /* The underlying system condition variable. */ | ||
| 187 | sys_cond_t condition; | ||
| 188 | } lisp_mutex_t; | ||
| 189 | |||
| 190 | /* A mutex as a lisp object. */ | ||
| 191 | struct Lisp_Mutex | ||
| 192 | { | ||
| 193 | struct vectorlike_header header; | ||
| 194 | |||
| 195 | /* The name of the mutex, or nil. */ | ||
| 196 | Lisp_Object name; | ||
| 197 | |||
| 198 | /* The lower-level mutex object. */ | ||
| 199 | lisp_mutex_t mutex; | ||
| 200 | }; | ||
| 201 | |||
| 202 | /* A condition variable as a lisp object. */ | ||
| 203 | struct Lisp_CondVar | ||
| 204 | { | ||
| 205 | struct vectorlike_header header; | ||
| 206 | |||
| 207 | /* The associated mutex. */ | ||
| 208 | Lisp_Object mutex; | ||
| 209 | |||
| 210 | /* The name of the condition variable, or nil. */ | ||
| 211 | Lisp_Object name; | ||
| 212 | |||
| 213 | /* The lower-level condition variable object. */ | ||
| 214 | sys_cond_t cond; | ||
| 215 | }; | ||
| 216 | |||
| 217 | extern struct thread_state *current_thread; | ||
| 218 | |||
| 219 | extern void unmark_threads (void); | ||
| 220 | extern void finalize_one_thread (struct thread_state *state); | ||
| 221 | extern void finalize_one_mutex (struct Lisp_Mutex *); | ||
| 222 | extern void finalize_one_condvar (struct Lisp_CondVar *); | ||
| 223 | |||
| 224 | extern void init_threads_once (void); | ||
| 225 | extern void init_threads (void); | ||
| 226 | extern void syms_of_threads (void); | ||
| 227 | |||
| 228 | typedef int select_func (int, fd_set *, fd_set *, fd_set *, | ||
| 229 | const struct timespec *, const sigset_t *); | ||
| 230 | |||
| 231 | int thread_select (select_func *func, int max_fds, fd_set *rfds, | ||
| 232 | fd_set *wfds, fd_set *efds, struct timespec *timeout, | ||
| 233 | sigset_t *sigmask); | ||
| 234 | |||
| 235 | bool thread_check_current_buffer (struct buffer *); | ||
| 236 | |||
| 237 | #endif /* THREAD_H */ | ||