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 | |
| 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')
| -rw-r--r-- | src/.gdbinit | 15 | ||||
| -rw-r--r-- | src/Makefile.in | 1 | ||||
| -rw-r--r-- | src/alloc.c | 110 | ||||
| -rw-r--r-- | src/buffer.c | 5 | ||||
| -rw-r--r-- | src/buffer.h | 4 | ||||
| -rw-r--r-- | src/bytecode.c | 203 | ||||
| -rw-r--r-- | src/data.c | 39 | ||||
| -rw-r--r-- | src/emacs.c | 14 | ||||
| -rw-r--r-- | src/eval.c | 268 | ||||
| -rw-r--r-- | src/lisp.h | 162 | ||||
| -rw-r--r-- | src/print.c | 36 | ||||
| -rw-r--r-- | src/process.c | 547 | ||||
| -rw-r--r-- | src/process.h | 5 | ||||
| -rw-r--r-- | src/regex.c | 6 | ||||
| -rw-r--r-- | src/regex.h | 8 | ||||
| -rw-r--r-- | src/search.c | 22 | ||||
| -rw-r--r-- | src/sysdep.c | 9 | ||||
| -rw-r--r-- | src/systhread.c | 417 | ||||
| -rw-r--r-- | src/systhread.h | 112 | ||||
| -rw-r--r-- | src/thread.c | 970 | ||||
| -rw-r--r-- | src/thread.h | 237 | ||||
| -rw-r--r-- | src/w32.c | 2 | ||||
| -rw-r--r-- | src/w32proc.c | 8 | ||||
| -rw-r--r-- | src/window.c | 8 | ||||
| -rw-r--r-- | src/xgselect.c | 12 |
25 files changed, 2776 insertions, 444 deletions
diff --git a/src/.gdbinit b/src/.gdbinit index b0c0dfd7e90..9160ffa439e 100644 --- a/src/.gdbinit +++ b/src/.gdbinit | |||
| @@ -1215,6 +1215,21 @@ document xwhichsymbols | |||
| 1215 | maximum number of symbols referencing it to produce. | 1215 | maximum number of symbols referencing it to produce. |
| 1216 | end | 1216 | end |
| 1217 | 1217 | ||
| 1218 | define xbytecode | ||
| 1219 | set $bt = byte_stack_list | ||
| 1220 | while $bt | ||
| 1221 | xgetptr $bt->byte_string | ||
| 1222 | set $ptr = (struct Lisp_String *) $ptr | ||
| 1223 | xprintbytestr $ptr | ||
| 1224 | printf "\n0x%x => ", $bt->byte_string | ||
| 1225 | xwhichsymbols $bt->byte_string 5 | ||
| 1226 | set $bt = $bt->next | ||
| 1227 | end | ||
| 1228 | end | ||
| 1229 | document xbytecode | ||
| 1230 | Print a backtrace of the byte code stack. | ||
| 1231 | end | ||
| 1232 | |||
| 1218 | # Show Lisp backtrace after normal backtrace. | 1233 | # Show Lisp backtrace after normal backtrace. |
| 1219 | define hookpost-backtrace | 1234 | define hookpost-backtrace |
| 1220 | set $bt = backtrace_top () | 1235 | set $bt = backtrace_top () |
diff --git a/src/Makefile.in b/src/Makefile.in index 7ca147f1eb5..ffc741d48d3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -409,6 +409,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ | |||
| 409 | doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \ | 409 | doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \ |
| 410 | $(XWIDGETS_OBJ) \ | 410 | $(XWIDGETS_OBJ) \ |
| 411 | profiler.o decompress.o \ | 411 | profiler.o decompress.o \ |
| 412 | thread.o systhread.o \ | ||
| 412 | $(if $(HYBRID_MALLOC),sheap.o) \ | 413 | $(if $(HYBRID_MALLOC),sheap.o) \ |
| 413 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ | 414 | $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ |
| 414 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) | 415 | $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) |
diff --git a/src/alloc.c b/src/alloc.c index 6eced7bab18..f2b7682b05d 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -438,10 +438,6 @@ struct mem_node | |||
| 438 | enum mem_type type; | 438 | enum mem_type type; |
| 439 | }; | 439 | }; |
| 440 | 440 | ||
| 441 | /* Base address of stack. Set in main. */ | ||
| 442 | |||
| 443 | Lisp_Object *stack_base; | ||
| 444 | |||
| 445 | /* Root of the tree describing allocated Lisp memory. */ | 441 | /* Root of the tree describing allocated Lisp memory. */ |
| 446 | 442 | ||
| 447 | static struct mem_node *mem_root; | 443 | static struct mem_node *mem_root; |
| @@ -3190,8 +3186,7 @@ vector_nbytes (struct Lisp_Vector *v) | |||
| 3190 | } | 3186 | } |
| 3191 | 3187 | ||
| 3192 | /* Release extra resources still in use by VECTOR, which may be any | 3188 | /* Release extra resources still in use by VECTOR, which may be any |
| 3193 | vector-like object. For now, this is used just to free data in | 3189 | vector-like object. */ |
| 3194 | font objects. */ | ||
| 3195 | 3190 | ||
| 3196 | static void | 3191 | static void |
| 3197 | cleanup_vector (struct Lisp_Vector *vector) | 3192 | cleanup_vector (struct Lisp_Vector *vector) |
| @@ -3212,6 +3207,13 @@ cleanup_vector (struct Lisp_Vector *vector) | |||
| 3212 | drv->close ((struct font *) vector); | 3207 | drv->close ((struct font *) vector); |
| 3213 | } | 3208 | } |
| 3214 | } | 3209 | } |
| 3210 | |||
| 3211 | if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) | ||
| 3212 | finalize_one_thread ((struct thread_state *) vector); | ||
| 3213 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_MUTEX)) | ||
| 3214 | finalize_one_mutex ((struct Lisp_Mutex *) vector); | ||
| 3215 | else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_CONDVAR)) | ||
| 3216 | finalize_one_condvar ((struct Lisp_CondVar *) vector); | ||
| 3215 | } | 3217 | } |
| 3216 | 3218 | ||
| 3217 | /* Reclaim space used by unmarked vectors. */ | 3219 | /* Reclaim space used by unmarked vectors. */ |
| @@ -5047,14 +5049,13 @@ test_setjmp (void) | |||
| 5047 | would be necessary, each one starting with one byte more offset | 5049 | would be necessary, each one starting with one byte more offset |
| 5048 | from the stack start. */ | 5050 | from the stack start. */ |
| 5049 | 5051 | ||
| 5050 | static void | 5052 | void |
| 5051 | mark_stack (void *end) | 5053 | mark_stack (char *bottom, char *end) |
| 5052 | { | 5054 | { |
| 5053 | |||
| 5054 | /* This assumes that the stack is a contiguous region in memory. If | 5055 | /* This assumes that the stack is a contiguous region in memory. If |
| 5055 | that's not the case, something has to be done here to iterate | 5056 | that's not the case, something has to be done here to iterate |
| 5056 | over the stack segments. */ | 5057 | over the stack segments. */ |
| 5057 | mark_memory (stack_base, end); | 5058 | mark_memory (bottom, end); |
| 5058 | 5059 | ||
| 5059 | /* Allow for marking a secondary stack, like the register stack on the | 5060 | /* Allow for marking a secondary stack, like the register stack on the |
| 5060 | ia64. */ | 5061 | ia64. */ |
| @@ -5063,6 +5064,81 @@ mark_stack (void *end) | |||
| 5063 | #endif | 5064 | #endif |
| 5064 | } | 5065 | } |
| 5065 | 5066 | ||
| 5067 | /* This is a trampoline function that flushes registers to the stack, | ||
| 5068 | and then calls FUNC. ARG is passed through to FUNC verbatim. | ||
| 5069 | |||
| 5070 | This function must be called whenever Emacs is about to release the | ||
| 5071 | global interpreter lock. This lets the garbage collector easily | ||
| 5072 | find roots in registers on threads that are not actively running | ||
| 5073 | Lisp. | ||
| 5074 | |||
| 5075 | It is invalid to run any Lisp code or to allocate any GC memory | ||
| 5076 | from FUNC. */ | ||
| 5077 | |||
| 5078 | void | ||
| 5079 | flush_stack_call_func (void (*func) (void *arg), void *arg) | ||
| 5080 | { | ||
| 5081 | void *end; | ||
| 5082 | struct thread_state *self = current_thread; | ||
| 5083 | |||
| 5084 | #ifdef HAVE___BUILTIN_UNWIND_INIT | ||
| 5085 | /* Force callee-saved registers and register windows onto the stack. | ||
| 5086 | This is the preferred method if available, obviating the need for | ||
| 5087 | machine dependent methods. */ | ||
| 5088 | __builtin_unwind_init (); | ||
| 5089 | end = &end; | ||
| 5090 | #else /* not HAVE___BUILTIN_UNWIND_INIT */ | ||
| 5091 | #ifndef GC_SAVE_REGISTERS_ON_STACK | ||
| 5092 | /* jmp_buf may not be aligned enough on darwin-ppc64 */ | ||
| 5093 | union aligned_jmpbuf { | ||
| 5094 | Lisp_Object o; | ||
| 5095 | sys_jmp_buf j; | ||
| 5096 | } j; | ||
| 5097 | volatile bool stack_grows_down_p = (char *) &j > (char *) stack_bottom; | ||
| 5098 | #endif | ||
| 5099 | /* This trick flushes the register windows so that all the state of | ||
| 5100 | the process is contained in the stack. */ | ||
| 5101 | /* Fixme: Code in the Boehm GC suggests flushing (with `flushrs') is | ||
| 5102 | needed on ia64 too. See mach_dep.c, where it also says inline | ||
| 5103 | assembler doesn't work with relevant proprietary compilers. */ | ||
| 5104 | #ifdef __sparc__ | ||
| 5105 | #if defined (__sparc64__) && defined (__FreeBSD__) | ||
| 5106 | /* FreeBSD does not have a ta 3 handler. */ | ||
| 5107 | asm ("flushw"); | ||
| 5108 | #else | ||
| 5109 | asm ("ta 3"); | ||
| 5110 | #endif | ||
| 5111 | #endif | ||
| 5112 | |||
| 5113 | /* Save registers that we need to see on the stack. We need to see | ||
| 5114 | registers used to hold register variables and registers used to | ||
| 5115 | pass parameters. */ | ||
| 5116 | #ifdef GC_SAVE_REGISTERS_ON_STACK | ||
| 5117 | GC_SAVE_REGISTERS_ON_STACK (end); | ||
| 5118 | #else /* not GC_SAVE_REGISTERS_ON_STACK */ | ||
| 5119 | |||
| 5120 | #ifndef GC_SETJMP_WORKS /* If it hasn't been checked yet that | ||
| 5121 | setjmp will definitely work, test it | ||
| 5122 | and print a message with the result | ||
| 5123 | of the test. */ | ||
| 5124 | if (!setjmp_tested_p) | ||
| 5125 | { | ||
| 5126 | setjmp_tested_p = 1; | ||
| 5127 | test_setjmp (); | ||
| 5128 | } | ||
| 5129 | #endif /* GC_SETJMP_WORKS */ | ||
| 5130 | |||
| 5131 | sys_setjmp (j.j); | ||
| 5132 | end = stack_grows_down_p ? (char *) &j + sizeof j : (char *) &j; | ||
| 5133 | #endif /* not GC_SAVE_REGISTERS_ON_STACK */ | ||
| 5134 | #endif /* not HAVE___BUILTIN_UNWIND_INIT */ | ||
| 5135 | |||
| 5136 | self->stack_top = end; | ||
| 5137 | (*func) (arg); | ||
| 5138 | |||
| 5139 | eassert (current_thread == self); | ||
| 5140 | } | ||
| 5141 | |||
| 5066 | static bool | 5142 | static bool |
| 5067 | c_symbol_p (struct Lisp_Symbol *sym) | 5143 | c_symbol_p (struct Lisp_Symbol *sym) |
| 5068 | { | 5144 | { |
| @@ -5768,24 +5844,14 @@ garbage_collect_1 (void *end) | |||
| 5768 | mark_object (*staticvec[i]); | 5844 | mark_object (*staticvec[i]); |
| 5769 | 5845 | ||
| 5770 | mark_pinned_symbols (); | 5846 | mark_pinned_symbols (); |
| 5771 | mark_specpdl (); | ||
| 5772 | mark_terminals (); | 5847 | mark_terminals (); |
| 5773 | mark_kboards (); | 5848 | mark_kboards (); |
| 5849 | mark_threads (); | ||
| 5774 | 5850 | ||
| 5775 | #ifdef USE_GTK | 5851 | #ifdef USE_GTK |
| 5776 | xg_mark_data (); | 5852 | xg_mark_data (); |
| 5777 | #endif | 5853 | #endif |
| 5778 | 5854 | ||
| 5779 | mark_stack (end); | ||
| 5780 | |||
| 5781 | { | ||
| 5782 | struct handler *handler; | ||
| 5783 | for (handler = handlerlist; handler; handler = handler->next) | ||
| 5784 | { | ||
| 5785 | mark_object (handler->tag_or_ch); | ||
| 5786 | mark_object (handler->val); | ||
| 5787 | } | ||
| 5788 | } | ||
| 5789 | #ifdef HAVE_WINDOW_SYSTEM | 5855 | #ifdef HAVE_WINDOW_SYSTEM |
| 5790 | mark_fringe_data (); | 5856 | mark_fringe_data (); |
| 5791 | #endif | 5857 | #endif |
| @@ -5817,6 +5883,8 @@ garbage_collect_1 (void *end) | |||
| 5817 | 5883 | ||
| 5818 | gc_sweep (); | 5884 | gc_sweep (); |
| 5819 | 5885 | ||
| 5886 | unmark_threads (); | ||
| 5887 | |||
| 5820 | /* Clear the mark bits that we set in certain root slots. */ | 5888 | /* Clear the mark bits that we set in certain root slots. */ |
| 5821 | VECTOR_UNMARK (&buffer_defaults); | 5889 | VECTOR_UNMARK (&buffer_defaults); |
| 5822 | VECTOR_UNMARK (&buffer_local_symbols); | 5890 | VECTOR_UNMARK (&buffer_local_symbols); |
diff --git a/src/buffer.c b/src/buffer.c index 6815aa7f7ed..cea1ddb5ab3 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -48,8 +48,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 48 | #include "w32heap.h" /* for mmap_* */ | 48 | #include "w32heap.h" /* for mmap_* */ |
| 49 | #endif | 49 | #endif |
| 50 | 50 | ||
| 51 | struct buffer *current_buffer; /* The current buffer. */ | ||
| 52 | |||
| 53 | /* First buffer in chain of all buffers (in reverse order of creation). | 51 | /* First buffer in chain of all buffers (in reverse order of creation). |
| 54 | Threaded through ->header.next.buffer. */ | 52 | Threaded through ->header.next.buffer. */ |
| 55 | 53 | ||
| @@ -1654,6 +1652,9 @@ cleaning up all windows currently displaying the buffer to be killed. */) | |||
| 1654 | if (!BUFFER_LIVE_P (b)) | 1652 | if (!BUFFER_LIVE_P (b)) |
| 1655 | return Qnil; | 1653 | return Qnil; |
| 1656 | 1654 | ||
| 1655 | if (thread_check_current_buffer (b)) | ||
| 1656 | return Qnil; | ||
| 1657 | |||
| 1657 | /* Run hooks with the buffer to be killed the current buffer. */ | 1658 | /* Run hooks with the buffer to be killed the current buffer. */ |
| 1658 | { | 1659 | { |
| 1659 | ptrdiff_t count = SPECPDL_INDEX (); | 1660 | ptrdiff_t count = SPECPDL_INDEX (); |
diff --git a/src/buffer.h b/src/buffer.h index 6ac161c1c91..21ad5e3bc0f 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
| @@ -1040,10 +1040,6 @@ extern struct buffer *all_buffers; | |||
| 1040 | #define FOR_EACH_BUFFER(b) \ | 1040 | #define FOR_EACH_BUFFER(b) \ |
| 1041 | for ((b) = all_buffers; (b); (b) = (b)->next) | 1041 | for ((b) = all_buffers; (b); (b) = (b)->next) |
| 1042 | 1042 | ||
| 1043 | /* This points to the current buffer. */ | ||
| 1044 | |||
| 1045 | extern struct buffer *current_buffer; | ||
| 1046 | |||
| 1047 | /* This structure holds the default values of the buffer-local variables | 1043 | /* This structure holds the default values of the buffer-local variables |
| 1048 | that have special slots in each buffer. | 1044 | that have special slots in each buffer. |
| 1049 | The default value occupies the same slot in this structure | 1045 | The default value occupies the same slot in this structure |
diff --git a/src/bytecode.c b/src/bytecode.c index 71ecdbf2cc0..c581ed6d982 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -280,10 +280,68 @@ enum byte_code_op | |||
| 280 | Bset_mark = 0163, /* this loser is no longer generated as of v18 */ | 280 | Bset_mark = 0163, /* this loser is no longer generated as of v18 */ |
| 281 | #endif | 281 | #endif |
| 282 | }; | 282 | }; |
| 283 | |||
| 284 | /* Whether to maintain a `top' and `bottom' field in the stack frame. */ | ||
| 285 | #define BYTE_MAINTAIN_TOP BYTE_CODE_SAFE | ||
| 283 | 286 | ||
| 284 | /* Fetch the next byte from the bytecode stream. */ | 287 | /* Structure describing a value stack used during byte-code execution |
| 288 | in Fbyte_code. */ | ||
| 289 | |||
| 290 | struct byte_stack | ||
| 291 | { | ||
| 292 | /* Program counter. This points into the byte_string below | ||
| 293 | and is relocated when that string is relocated. */ | ||
| 294 | const unsigned char *pc; | ||
| 295 | |||
| 296 | /* Top and bottom of stack. The bottom points to an area of memory | ||
| 297 | allocated with alloca in Fbyte_code. */ | ||
| 298 | #if BYTE_MAINTAIN_TOP | ||
| 299 | Lisp_Object *top, *bottom; | ||
| 300 | #endif | ||
| 301 | |||
| 302 | /* The string containing the byte-code, and its current address. | ||
| 303 | Storing this here protects it from GC because mark_byte_stack | ||
| 304 | marks it. */ | ||
| 305 | Lisp_Object byte_string; | ||
| 306 | const unsigned char *byte_string_start; | ||
| 307 | |||
| 308 | /* Next entry in byte_stack_list. */ | ||
| 309 | struct byte_stack *next; | ||
| 310 | }; | ||
| 311 | |||
| 312 | /* A list of currently active byte-code execution value stacks. | ||
| 313 | Fbyte_code adds an entry to the head of this list before it starts | ||
| 314 | processing byte-code, and it removes the entry again when it is | ||
| 315 | done. Signaling an error truncates the list. | ||
| 316 | |||
| 317 | byte_stack_list is a macro defined in thread.h. */ | ||
| 318 | /* struct byte_stack *byte_stack_list; */ | ||
| 319 | |||
| 320 | |||
| 321 | /* Relocate program counters in the stacks on byte_stack_list. Called | ||
| 322 | when GC has completed. */ | ||
| 323 | |||
| 324 | void | ||
| 325 | relocate_byte_stack (struct byte_stack *stack) | ||
| 326 | { | ||
| 327 | for (; stack; stack = stack->next) | ||
| 328 | { | ||
| 329 | if (stack->byte_string_start != SDATA (stack->byte_string)) | ||
| 330 | { | ||
| 331 | ptrdiff_t offset = stack->pc - stack->byte_string_start; | ||
| 332 | stack->byte_string_start = SDATA (stack->byte_string); | ||
| 333 | stack->pc = stack->byte_string_start + offset; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | } | ||
| 285 | 337 | ||
| 286 | #define FETCH (*pc++) | 338 | |
| 339 | /* Fetch the next byte from the bytecode stream. */ | ||
| 340 | #ifdef BYTE_CODE_SAFE | ||
| 341 | #define FETCH (eassert (stack.byte_string_start == SDATA (stack.byte_string)), *stack.pc++) | ||
| 342 | #else | ||
| 343 | #define FETCH *stack.pc++ | ||
| 344 | #endif | ||
| 287 | 345 | ||
| 288 | /* Fetch two bytes from the bytecode stream and make a 16-bit number | 346 | /* Fetch two bytes from the bytecode stream and make a 16-bit number |
| 289 | out of them. */ | 347 | out of them. */ |
| @@ -308,6 +366,29 @@ enum byte_code_op | |||
| 308 | 366 | ||
| 309 | #define TOP (*top) | 367 | #define TOP (*top) |
| 310 | 368 | ||
| 369 | #define CHECK_RANGE(ARG) \ | ||
| 370 | (BYTE_CODE_SAFE && bytestr_length <= (ARG) ? emacs_abort () : (void) 0) | ||
| 371 | |||
| 372 | /* A version of the QUIT macro which makes sure that the stack top is | ||
| 373 | set before signaling `quit'. */ | ||
| 374 | #define BYTE_CODE_QUIT \ | ||
| 375 | do { \ | ||
| 376 | if (quitcounter++) \ | ||
| 377 | break; \ | ||
| 378 | maybe_gc (); \ | ||
| 379 | if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ | ||
| 380 | { \ | ||
| 381 | Lisp_Object flag = Vquit_flag; \ | ||
| 382 | Vquit_flag = Qnil; \ | ||
| 383 | if (EQ (Vthrow_on_input, flag)) \ | ||
| 384 | Fthrow (Vthrow_on_input, Qt); \ | ||
| 385 | quit (); \ | ||
| 386 | } \ | ||
| 387 | else if (pending_signals) \ | ||
| 388 | process_pending_signals (); \ | ||
| 389 | } while (0) | ||
| 390 | |||
| 391 | |||
| 311 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, | 392 | DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0, |
| 312 | doc: /* Function used internally in byte-compiled code. | 393 | doc: /* Function used internally in byte-compiled code. |
| 313 | The first argument, BYTESTR, is a string of byte code; | 394 | The first argument, BYTESTR, is a string of byte code; |
| @@ -357,18 +438,19 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 357 | 438 | ||
| 358 | ptrdiff_t bytestr_length = SBYTES (bytestr); | 439 | ptrdiff_t bytestr_length = SBYTES (bytestr); |
| 359 | Lisp_Object *vectorp = XVECTOR (vector)->contents; | 440 | Lisp_Object *vectorp = XVECTOR (vector)->contents; |
| 441 | struct byte_stack stack; | ||
| 360 | 442 | ||
| 361 | unsigned char quitcounter = 1; | 443 | stack.byte_string = bytestr; |
| 444 | stack.pc = stack.byte_string_start = SDATA (bytestr); | ||
| 445 | unsigned char quitcounter = 0; | ||
| 362 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; | 446 | EMACS_INT stack_items = XFASTINT (maxdepth) + 1; |
| 363 | USE_SAFE_ALLOCA; | 447 | USE_SAFE_ALLOCA; |
| 364 | Lisp_Object *stack_base; | 448 | Lisp_Object *stack_base; |
| 365 | SAFE_ALLOCA_LISP_EXTRA (stack_base, stack_items, bytestr_length); | 449 | SAFE_ALLOCA_LISP (stack_base, stack_items); |
| 366 | Lisp_Object *stack_lim = stack_base + stack_items; | 450 | Lisp_Object *stack_lim = stack_base + stack_items; |
| 367 | Lisp_Object *top = stack_base; | 451 | Lisp_Object *top = stack_base; |
| 368 | memcpy (stack_lim, SDATA (bytestr), bytestr_length); | 452 | stack.next = byte_stack_list; |
| 369 | void *void_stack_lim = stack_lim; | 453 | byte_stack_list = &stack; |
| 370 | unsigned char const *bytestr_data = void_stack_lim; | ||
| 371 | unsigned char const *pc = bytestr_data; | ||
| 372 | ptrdiff_t count = SPECPDL_INDEX (); | 454 | ptrdiff_t count = SPECPDL_INDEX (); |
| 373 | 455 | ||
| 374 | if (!NILP (args_template)) | 456 | if (!NILP (args_template)) |
| @@ -508,10 +590,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 508 | 590 | ||
| 509 | CASE (Bgotoifnil): | 591 | CASE (Bgotoifnil): |
| 510 | { | 592 | { |
| 511 | Lisp_Object v1 = POP; | 593 | Lisp_Object v1; |
| 512 | op = FETCH2; | 594 | op = FETCH2; |
| 595 | v1 = POP; | ||
| 513 | if (NILP (v1)) | 596 | if (NILP (v1)) |
| 514 | goto op_branch; | 597 | { |
| 598 | BYTE_CODE_QUIT; | ||
| 599 | CHECK_RANGE (op); | ||
| 600 | stack.pc = stack.byte_string_start + op; | ||
| 601 | } | ||
| 515 | NEXT; | 602 | NEXT; |
| 516 | } | 603 | } |
| 517 | 604 | ||
| @@ -569,7 +656,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 569 | if (SYMBOLP (sym) | 656 | if (SYMBOLP (sym) |
| 570 | && !EQ (val, Qunbound) | 657 | && !EQ (val, Qunbound) |
| 571 | && !XSYMBOL (sym)->redirect | 658 | && !XSYMBOL (sym)->redirect |
| 572 | && !SYMBOL_TRAPPED_WRITE_P (sym)) | 659 | && !SYMBOL_TRAPPED_WRITE_P (sym)) |
| 573 | SET_SYMBOL_VAL (XSYMBOL (sym), val); | 660 | SET_SYMBOL_VAL (XSYMBOL (sym), val); |
| 574 | else | 661 | else |
| 575 | set_internal (sym, val, Qnil, SET_INTERNAL_SET); | 662 | set_internal (sym, val, Qnil, SET_INTERNAL_SET); |
| @@ -666,72 +753,86 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 666 | NEXT; | 753 | NEXT; |
| 667 | 754 | ||
| 668 | CASE (Bgoto): | 755 | CASE (Bgoto): |
| 669 | op = FETCH2; | 756 | BYTE_CODE_QUIT; |
| 670 | op_branch: | 757 | op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */ |
| 671 | op -= pc - bytestr_data; | 758 | CHECK_RANGE (op); |
| 672 | op_relative_branch: | 759 | stack.pc = stack.byte_string_start + op; |
| 673 | if (BYTE_CODE_SAFE | ||
| 674 | && ! (bytestr_data - pc <= op | ||
| 675 | && op < bytestr_data + bytestr_length - pc)) | ||
| 676 | emacs_abort (); | ||
| 677 | quitcounter += op < 0; | ||
| 678 | if (!quitcounter) | ||
| 679 | { | ||
| 680 | quitcounter = 1; | ||
| 681 | maybe_gc (); | ||
| 682 | QUIT; | ||
| 683 | } | ||
| 684 | pc += op; | ||
| 685 | NEXT; | 760 | NEXT; |
| 686 | 761 | ||
| 687 | CASE (Bgotoifnonnil): | 762 | CASE (Bgotoifnonnil): |
| 688 | op = FETCH2; | 763 | op = FETCH2; |
| 689 | if (!NILP (POP)) | 764 | Lisp_Object v1 = POP; |
| 690 | goto op_branch; | 765 | if (!NILP (v1)) |
| 766 | { | ||
| 767 | BYTE_CODE_QUIT; | ||
| 768 | CHECK_RANGE (op); | ||
| 769 | stack.pc = stack.byte_string_start + op; | ||
| 770 | } | ||
| 691 | NEXT; | 771 | NEXT; |
| 692 | 772 | ||
| 693 | CASE (Bgotoifnilelsepop): | 773 | CASE (Bgotoifnilelsepop): |
| 694 | op = FETCH2; | 774 | op = FETCH2; |
| 695 | if (NILP (TOP)) | 775 | if (NILP (TOP)) |
| 696 | goto op_branch; | 776 | { |
| 697 | DISCARD (1); | 777 | BYTE_CODE_QUIT; |
| 778 | CHECK_RANGE (op); | ||
| 779 | stack.pc = stack.byte_string_start + op; | ||
| 780 | } | ||
| 781 | else DISCARD (1); | ||
| 698 | NEXT; | 782 | NEXT; |
| 699 | 783 | ||
| 700 | CASE (Bgotoifnonnilelsepop): | 784 | CASE (Bgotoifnonnilelsepop): |
| 701 | op = FETCH2; | 785 | op = FETCH2; |
| 702 | if (!NILP (TOP)) | 786 | if (!NILP (TOP)) |
| 703 | goto op_branch; | 787 | { |
| 704 | DISCARD (1); | 788 | BYTE_CODE_QUIT; |
| 789 | CHECK_RANGE (op); | ||
| 790 | stack.pc = stack.byte_string_start + op; | ||
| 791 | } | ||
| 792 | else DISCARD (1); | ||
| 705 | NEXT; | 793 | NEXT; |
| 706 | 794 | ||
| 707 | CASE (BRgoto): | 795 | CASE (BRgoto): |
| 708 | op = FETCH - 128; | 796 | BYTE_CODE_QUIT; |
| 709 | goto op_relative_branch; | 797 | stack.pc += (int) *stack.pc - 127; |
| 798 | NEXT; | ||
| 710 | 799 | ||
| 711 | CASE (BRgotoifnil): | 800 | CASE (BRgotoifnil): |
| 712 | op = FETCH - 128; | ||
| 713 | if (NILP (POP)) | 801 | if (NILP (POP)) |
| 714 | goto op_relative_branch; | 802 | { |
| 803 | BYTE_CODE_QUIT; | ||
| 804 | stack.pc += (int) *stack.pc - 128; | ||
| 805 | } | ||
| 806 | stack.pc++; | ||
| 715 | NEXT; | 807 | NEXT; |
| 716 | 808 | ||
| 717 | CASE (BRgotoifnonnil): | 809 | CASE (BRgotoifnonnil): |
| 718 | op = FETCH - 128; | ||
| 719 | if (!NILP (POP)) | 810 | if (!NILP (POP)) |
| 720 | goto op_relative_branch; | 811 | { |
| 812 | BYTE_CODE_QUIT; | ||
| 813 | stack.pc += (int) *stack.pc - 128; | ||
| 814 | } | ||
| 815 | stack.pc++; | ||
| 721 | NEXT; | 816 | NEXT; |
| 722 | 817 | ||
| 723 | CASE (BRgotoifnilelsepop): | 818 | CASE (BRgotoifnilelsepop): |
| 724 | op = FETCH - 128; | 819 | op = *stack.pc++; |
| 725 | if (NILP (TOP)) | 820 | if (NILP (TOP)) |
| 726 | goto op_relative_branch; | 821 | { |
| 727 | DISCARD (1); | 822 | BYTE_CODE_QUIT; |
| 823 | stack.pc += op - 128; | ||
| 824 | } | ||
| 825 | else DISCARD (1); | ||
| 728 | NEXT; | 826 | NEXT; |
| 729 | 827 | ||
| 730 | CASE (BRgotoifnonnilelsepop): | 828 | CASE (BRgotoifnonnilelsepop): |
| 731 | op = FETCH - 128; | 829 | op = *stack.pc++; |
| 732 | if (!NILP (TOP)) | 830 | if (!NILP (TOP)) |
| 733 | goto op_relative_branch; | 831 | { |
| 734 | DISCARD (1); | 832 | BYTE_CODE_QUIT; |
| 833 | stack.pc += op - 128; | ||
| 834 | } | ||
| 835 | else DISCARD (1); | ||
| 735 | NEXT; | 836 | NEXT; |
| 736 | 837 | ||
| 737 | CASE (Breturn): | 838 | CASE (Breturn): |
| @@ -791,11 +892,15 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 791 | if (sys_setjmp (c->jmp)) | 892 | if (sys_setjmp (c->jmp)) |
| 792 | { | 893 | { |
| 793 | struct handler *c = handlerlist; | 894 | struct handler *c = handlerlist; |
| 895 | int dest; | ||
| 794 | top = c->bytecode_top; | 896 | top = c->bytecode_top; |
| 795 | op = c->bytecode_dest; | 897 | dest = c->bytecode_dest; |
| 796 | handlerlist = c->next; | 898 | handlerlist = c->next; |
| 797 | PUSH (c->val); | 899 | PUSH (c->val); |
| 798 | goto op_branch; | 900 | CHECK_RANGE (dest); |
| 901 | /* Might have been re-set by longjmp! */ | ||
| 902 | stack.byte_string_start = SDATA (stack.byte_string); | ||
| 903 | stack.pc = stack.byte_string_start + dest; | ||
| 799 | } | 904 | } |
| 800 | 905 | ||
| 801 | NEXT; | 906 | NEXT; |
| @@ -1363,7 +1468,7 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1363 | call3 (Qerror, | 1468 | call3 (Qerror, |
| 1364 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), | 1469 | build_string ("Invalid byte opcode: op=%s, ptr=%d"), |
| 1365 | make_number (op), | 1470 | make_number (op), |
| 1366 | make_number (pc - 1 - bytestr_data)); | 1471 | make_number (stack.pc - 1 - stack.byte_string_start)); |
| 1367 | 1472 | ||
| 1368 | /* Handy byte-codes for lexical binding. */ | 1473 | /* Handy byte-codes for lexical binding. */ |
| 1369 | CASE (Bstack_ref1): | 1474 | CASE (Bstack_ref1): |
| @@ -1423,6 +1528,8 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1423 | 1528 | ||
| 1424 | exit: | 1529 | exit: |
| 1425 | 1530 | ||
| 1531 | byte_stack_list = byte_stack_list->next; | ||
| 1532 | |||
| 1426 | /* Binds and unbinds are supposed to be compiled balanced. */ | 1533 | /* Binds and unbinds are supposed to be compiled balanced. */ |
| 1427 | if (SPECPDL_INDEX () != count) | 1534 | if (SPECPDL_INDEX () != count) |
| 1428 | { | 1535 | { |
diff --git a/src/data.c b/src/data.c index 64cd8b23b46..09d94f57a8e 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -258,6 +258,12 @@ for example, (type-of 1) returns `integer'. */) | |||
| 258 | return Qfont_entity; | 258 | return Qfont_entity; |
| 259 | if (FONT_OBJECT_P (object)) | 259 | if (FONT_OBJECT_P (object)) |
| 260 | return Qfont_object; | 260 | return Qfont_object; |
| 261 | if (THREADP (object)) | ||
| 262 | return Qthread; | ||
| 263 | if (MUTEXP (object)) | ||
| 264 | return Qmutex; | ||
| 265 | if (CONDVARP (object)) | ||
| 266 | return Qcondition_variable; | ||
| 261 | return Qvector; | 267 | return Qvector; |
| 262 | 268 | ||
| 263 | case Lisp_Float: | 269 | case Lisp_Float: |
| @@ -528,6 +534,33 @@ DEFUN ("floatp", Ffloatp, Sfloatp, 1, 1, 0, | |||
| 528 | return Qnil; | 534 | return Qnil; |
| 529 | } | 535 | } |
| 530 | 536 | ||
| 537 | DEFUN ("threadp", Fthreadp, Sthreadp, 1, 1, 0, | ||
| 538 | doc: /* Return t if OBJECT is a thread. */) | ||
| 539 | (Lisp_Object object) | ||
| 540 | { | ||
| 541 | if (THREADP (object)) | ||
| 542 | return Qt; | ||
| 543 | return Qnil; | ||
| 544 | } | ||
| 545 | |||
| 546 | DEFUN ("mutexp", Fmutexp, Smutexp, 1, 1, 0, | ||
| 547 | doc: /* Return t if OBJECT is a mutex. */) | ||
| 548 | (Lisp_Object object) | ||
| 549 | { | ||
| 550 | if (MUTEXP (object)) | ||
| 551 | return Qt; | ||
| 552 | return Qnil; | ||
| 553 | } | ||
| 554 | |||
| 555 | DEFUN ("condition-variable-p", Fcondition_variable_p, Scondition_variable_p, | ||
| 556 | 1, 1, 0, | ||
| 557 | doc: /* Return t if OBJECT is a condition variable. */) | ||
| 558 | (Lisp_Object object) | ||
| 559 | { | ||
| 560 | if (CONDVARP (object)) | ||
| 561 | return Qt; | ||
| 562 | return Qnil; | ||
| 563 | } | ||
| 531 | 564 | ||
| 532 | /* Extract and set components of lists. */ | 565 | /* Extract and set components of lists. */ |
| 533 | 566 | ||
| @@ -3756,6 +3789,9 @@ syms_of_data (void) | |||
| 3756 | DEFSYM (Qchar_table, "char-table"); | 3789 | DEFSYM (Qchar_table, "char-table"); |
| 3757 | DEFSYM (Qbool_vector, "bool-vector"); | 3790 | DEFSYM (Qbool_vector, "bool-vector"); |
| 3758 | DEFSYM (Qhash_table, "hash-table"); | 3791 | DEFSYM (Qhash_table, "hash-table"); |
| 3792 | DEFSYM (Qthread, "thread"); | ||
| 3793 | DEFSYM (Qmutex, "mutex"); | ||
| 3794 | DEFSYM (Qcondition_variable, "condition-variable"); | ||
| 3759 | 3795 | ||
| 3760 | DEFSYM (Qdefun, "defun"); | 3796 | DEFSYM (Qdefun, "defun"); |
| 3761 | 3797 | ||
| @@ -3796,6 +3832,9 @@ syms_of_data (void) | |||
| 3796 | defsubr (&Ssubrp); | 3832 | defsubr (&Ssubrp); |
| 3797 | defsubr (&Sbyte_code_function_p); | 3833 | defsubr (&Sbyte_code_function_p); |
| 3798 | defsubr (&Schar_or_string_p); | 3834 | defsubr (&Schar_or_string_p); |
| 3835 | defsubr (&Sthreadp); | ||
| 3836 | defsubr (&Smutexp); | ||
| 3837 | defsubr (&Scondition_variable_p); | ||
| 3799 | defsubr (&Scar); | 3838 | defsubr (&Scar); |
| 3800 | defsubr (&Scdr); | 3839 | defsubr (&Scdr); |
| 3801 | defsubr (&Scar_safe); | 3840 | defsubr (&Scar_safe); |
diff --git a/src/emacs.c b/src/emacs.c index 75b2d6ed607..424ee05a42c 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -155,10 +155,6 @@ bool running_asynch_code; | |||
| 155 | bool display_arg; | 155 | bool display_arg; |
| 156 | #endif | 156 | #endif |
| 157 | 157 | ||
| 158 | /* An address near the bottom of the stack. | ||
| 159 | Tells GC how to save a copy of the stack. */ | ||
| 160 | char *stack_bottom; | ||
| 161 | |||
| 162 | #if defined GNU_LINUX && !defined CANNOT_DUMP | 158 | #if defined GNU_LINUX && !defined CANNOT_DUMP |
| 163 | /* The gap between BSS end and heap start as far as we can tell. */ | 159 | /* The gap between BSS end and heap start as far as we can tell. */ |
| 164 | static uprintmax_t heap_bss_diff; | 160 | static uprintmax_t heap_bss_diff; |
| @@ -670,7 +666,6 @@ close_output_streams (void) | |||
| 670 | int | 666 | int |
| 671 | main (int argc, char **argv) | 667 | main (int argc, char **argv) |
| 672 | { | 668 | { |
| 673 | Lisp_Object dummy; | ||
| 674 | char stack_bottom_variable; | 669 | char stack_bottom_variable; |
| 675 | bool do_initial_setlocale; | 670 | bool do_initial_setlocale; |
| 676 | bool dumping; | 671 | bool dumping; |
| @@ -686,7 +681,8 @@ main (int argc, char **argv) | |||
| 686 | /* If we use --chdir, this records the original directory. */ | 681 | /* If we use --chdir, this records the original directory. */ |
| 687 | char *original_pwd = 0; | 682 | char *original_pwd = 0; |
| 688 | 683 | ||
| 689 | stack_base = &dummy; | 684 | /* Record (approximately) where the stack begins. */ |
| 685 | stack_bottom = &stack_bottom_variable; | ||
| 690 | 686 | ||
| 691 | dumping = !initialized && (strcmp (argv[argc - 1], "dump") == 0 | 687 | dumping = !initialized && (strcmp (argv[argc - 1], "dump") == 0 |
| 692 | || strcmp (argv[argc - 1], "bootstrap") == 0); | 688 | || strcmp (argv[argc - 1], "bootstrap") == 0); |
| @@ -881,9 +877,6 @@ main (int argc, char **argv) | |||
| 881 | } | 877 | } |
| 882 | #endif /* HAVE_SETRLIMIT and RLIMIT_STACK and not CYGWIN */ | 878 | #endif /* HAVE_SETRLIMIT and RLIMIT_STACK and not CYGWIN */ |
| 883 | 879 | ||
| 884 | /* Record (approximately) where the stack begins. */ | ||
| 885 | stack_bottom = &stack_bottom_variable; | ||
| 886 | |||
| 887 | clearerr (stdin); | 880 | clearerr (stdin); |
| 888 | 881 | ||
| 889 | emacs_backtrace (-1); | 882 | emacs_backtrace (-1); |
| @@ -1197,6 +1190,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1197 | if (!initialized) | 1190 | if (!initialized) |
| 1198 | { | 1191 | { |
| 1199 | init_alloc_once (); | 1192 | init_alloc_once (); |
| 1193 | init_threads_once (); | ||
| 1200 | init_obarray (); | 1194 | init_obarray (); |
| 1201 | init_eval_once (); | 1195 | init_eval_once (); |
| 1202 | init_charset_once (); | 1196 | init_charset_once (); |
| @@ -1243,6 +1237,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1243 | } | 1237 | } |
| 1244 | 1238 | ||
| 1245 | init_alloc (); | 1239 | init_alloc (); |
| 1240 | init_threads (); | ||
| 1246 | 1241 | ||
| 1247 | if (do_initial_setlocale) | 1242 | if (do_initial_setlocale) |
| 1248 | { | 1243 | { |
| @@ -1585,6 +1580,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1585 | #endif /* HAVE_W32NOTIFY */ | 1580 | #endif /* HAVE_W32NOTIFY */ |
| 1586 | #endif /* WINDOWSNT */ | 1581 | #endif /* WINDOWSNT */ |
| 1587 | 1582 | ||
| 1583 | syms_of_threads (); | ||
| 1588 | syms_of_profiler (); | 1584 | syms_of_profiler (); |
| 1589 | 1585 | ||
| 1590 | keys_of_casefiddle (); | 1586 | keys_of_casefiddle (); |
diff --git a/src/eval.c b/src/eval.c index 8ad06dded80..f1e0ae7d586 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -32,7 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 32 | 32 | ||
| 33 | /* Chain of condition and catch handlers currently in effect. */ | 33 | /* Chain of condition and catch handlers currently in effect. */ |
| 34 | 34 | ||
| 35 | struct handler *handlerlist; | 35 | /* struct handler *handlerlist; */ |
| 36 | 36 | ||
| 37 | /* Non-nil means record all fset's and provide's, to be undone | 37 | /* Non-nil means record all fset's and provide's, to be undone |
| 38 | if the file being autoloaded is not fully loaded. | 38 | if the file being autoloaded is not fully loaded. |
| @@ -46,23 +46,25 @@ Lisp_Object Vautoload_queue; | |||
| 46 | is shutting down. */ | 46 | is shutting down. */ |
| 47 | Lisp_Object Vrun_hooks; | 47 | Lisp_Object Vrun_hooks; |
| 48 | 48 | ||
| 49 | /* The commented-out variables below are macros defined in thread.h. */ | ||
| 50 | |||
| 49 | /* Current number of specbindings allocated in specpdl, not counting | 51 | /* Current number of specbindings allocated in specpdl, not counting |
| 50 | the dummy entry specpdl[-1]. */ | 52 | the dummy entry specpdl[-1]. */ |
| 51 | 53 | ||
| 52 | ptrdiff_t specpdl_size; | 54 | /* ptrdiff_t specpdl_size; */ |
| 53 | 55 | ||
| 54 | /* Pointer to beginning of specpdl. A dummy entry specpdl[-1] exists | 56 | /* Pointer to beginning of specpdl. A dummy entry specpdl[-1] exists |
| 55 | only so that its address can be taken. */ | 57 | only so that its address can be taken. */ |
| 56 | 58 | ||
| 57 | union specbinding *specpdl; | 59 | /* union specbinding *specpdl; */ |
| 58 | 60 | ||
| 59 | /* Pointer to first unused element in specpdl. */ | 61 | /* Pointer to first unused element in specpdl. */ |
| 60 | 62 | ||
| 61 | union specbinding *specpdl_ptr; | 63 | /* union specbinding *specpdl_ptr; */ |
| 62 | 64 | ||
| 63 | /* Depth in Lisp evaluations and function calls. */ | 65 | /* Depth in Lisp evaluations and function calls. */ |
| 64 | 66 | ||
| 65 | static EMACS_INT lisp_eval_depth; | 67 | /* static EMACS_INT lisp_eval_depth; */ |
| 66 | 68 | ||
| 67 | /* The value of num_nonmacro_input_events as of the last time we | 69 | /* The value of num_nonmacro_input_events as of the last time we |
| 68 | started to enter the debugger. If we decide to enter the debugger | 70 | started to enter the debugger. If we decide to enter the debugger |
| @@ -100,6 +102,13 @@ specpdl_symbol (union specbinding *pdl) | |||
| 100 | return pdl->let.symbol; | 102 | return pdl->let.symbol; |
| 101 | } | 103 | } |
| 102 | 104 | ||
| 105 | static enum specbind_tag | ||
| 106 | specpdl_kind (union specbinding *pdl) | ||
| 107 | { | ||
| 108 | eassert (pdl->kind >= SPECPDL_LET); | ||
| 109 | return pdl->let.kind; | ||
| 110 | } | ||
| 111 | |||
| 103 | static Lisp_Object | 112 | static Lisp_Object |
| 104 | specpdl_old_value (union specbinding *pdl) | 113 | specpdl_old_value (union specbinding *pdl) |
| 105 | { | 114 | { |
| @@ -122,6 +131,13 @@ specpdl_where (union specbinding *pdl) | |||
| 122 | } | 131 | } |
| 123 | 132 | ||
| 124 | static Lisp_Object | 133 | static Lisp_Object |
| 134 | specpdl_saved_value (union specbinding *pdl) | ||
| 135 | { | ||
| 136 | eassert (pdl->kind >= SPECPDL_LET); | ||
| 137 | return pdl->let.saved_value; | ||
| 138 | } | ||
| 139 | |||
| 140 | static Lisp_Object | ||
| 125 | specpdl_arg (union specbinding *pdl) | 141 | specpdl_arg (union specbinding *pdl) |
| 126 | { | 142 | { |
| 127 | eassert (pdl->kind == SPECPDL_UNWIND); | 143 | eassert (pdl->kind == SPECPDL_UNWIND); |
| @@ -218,20 +234,22 @@ init_eval_once (void) | |||
| 218 | Vrun_hooks = Qnil; | 234 | Vrun_hooks = Qnil; |
| 219 | } | 235 | } |
| 220 | 236 | ||
| 221 | static struct handler handlerlist_sentinel; | 237 | /* static struct handler handlerlist_sentinel; */ |
| 222 | 238 | ||
| 223 | void | 239 | void |
| 224 | init_eval (void) | 240 | init_eval (void) |
| 225 | { | 241 | { |
| 242 | byte_stack_list = 0; | ||
| 226 | specpdl_ptr = specpdl; | 243 | specpdl_ptr = specpdl; |
| 227 | { /* Put a dummy catcher at top-level so that handlerlist is never NULL. | 244 | { /* Put a dummy catcher at top-level so that handlerlist is never NULL. |
| 228 | This is important since handlerlist->nextfree holds the freelist | 245 | This is important since handlerlist->nextfree holds the freelist |
| 229 | which would otherwise leak every time we unwind back to top-level. */ | 246 | which would otherwise leak every time we unwind back to top-level. */ |
| 230 | handlerlist = handlerlist_sentinel.nextfree = &handlerlist_sentinel; | 247 | handlerlist_sentinel = xzalloc (sizeof (struct handler)); |
| 248 | handlerlist = handlerlist_sentinel->nextfree = handlerlist_sentinel; | ||
| 231 | struct handler *c = push_handler (Qunbound, CATCHER); | 249 | struct handler *c = push_handler (Qunbound, CATCHER); |
| 232 | eassert (c == &handlerlist_sentinel); | 250 | eassert (c == handlerlist_sentinel); |
| 233 | handlerlist_sentinel.nextfree = NULL; | 251 | handlerlist_sentinel->nextfree = NULL; |
| 234 | handlerlist_sentinel.next = NULL; | 252 | handlerlist_sentinel->next = NULL; |
| 235 | } | 253 | } |
| 236 | Vquit_flag = Qnil; | 254 | Vquit_flag = Qnil; |
| 237 | debug_on_next_call = 0; | 255 | debug_on_next_call = 0; |
| @@ -1138,7 +1156,8 @@ unwind_to_catch (struct handler *catch, Lisp_Object value) | |||
| 1138 | 1156 | ||
| 1139 | eassert (handlerlist == catch); | 1157 | eassert (handlerlist == catch); |
| 1140 | 1158 | ||
| 1141 | lisp_eval_depth = catch->lisp_eval_depth; | 1159 | byte_stack_list = catch->byte_stack; |
| 1160 | lisp_eval_depth = catch->f_lisp_eval_depth; | ||
| 1142 | 1161 | ||
| 1143 | sys_longjmp (catch->jmp, 1); | 1162 | sys_longjmp (catch->jmp, 1); |
| 1144 | } | 1163 | } |
| @@ -1428,10 +1447,11 @@ push_handler_nosignal (Lisp_Object tag_ch_val, enum handlertype handlertype) | |||
| 1428 | c->tag_or_ch = tag_ch_val; | 1447 | c->tag_or_ch = tag_ch_val; |
| 1429 | c->val = Qnil; | 1448 | c->val = Qnil; |
| 1430 | c->next = handlerlist; | 1449 | c->next = handlerlist; |
| 1431 | c->lisp_eval_depth = lisp_eval_depth; | 1450 | c->f_lisp_eval_depth = lisp_eval_depth; |
| 1432 | c->pdlcount = SPECPDL_INDEX (); | 1451 | c->pdlcount = SPECPDL_INDEX (); |
| 1433 | c->poll_suppress_count = poll_suppress_count; | 1452 | c->poll_suppress_count = poll_suppress_count; |
| 1434 | c->interrupt_input_blocked = interrupt_input_blocked; | 1453 | c->interrupt_input_blocked = interrupt_input_blocked; |
| 1454 | c->byte_stack = byte_stack_list; | ||
| 1435 | handlerlist = c; | 1455 | handlerlist = c; |
| 1436 | return c; | 1456 | return c; |
| 1437 | } | 1457 | } |
| @@ -1581,7 +1601,7 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit) | |||
| 1581 | } | 1601 | } |
| 1582 | else | 1602 | else |
| 1583 | { | 1603 | { |
| 1584 | if (handlerlist != &handlerlist_sentinel) | 1604 | if (handlerlist != handlerlist_sentinel) |
| 1585 | /* FIXME: This will come right back here if there's no `top-level' | 1605 | /* FIXME: This will come right back here if there's no `top-level' |
| 1586 | catcher. A better solution would be to abort here, and instead | 1606 | catcher. A better solution would be to abort here, and instead |
| 1587 | add a catch-all condition handler so we never come here. */ | 1607 | add a catch-all condition handler so we never come here. */ |
| @@ -3175,6 +3195,36 @@ let_shadows_global_binding_p (Lisp_Object symbol) | |||
| 3175 | return 0; | 3195 | return 0; |
| 3176 | } | 3196 | } |
| 3177 | 3197 | ||
| 3198 | static void | ||
| 3199 | do_specbind (struct Lisp_Symbol *sym, union specbinding *bind, | ||
| 3200 | Lisp_Object value) | ||
| 3201 | { | ||
| 3202 | switch (sym->redirect) | ||
| 3203 | { | ||
| 3204 | case SYMBOL_PLAINVAL: | ||
| 3205 | if (!sym->trapped_write) | ||
| 3206 | SET_SYMBOL_VAL (sym, value); | ||
| 3207 | else | ||
| 3208 | set_internal (specpdl_symbol (bind), value, Qnil, SET_INTERNAL_BIND); | ||
| 3209 | break; | ||
| 3210 | |||
| 3211 | case SYMBOL_FORWARDED: | ||
| 3212 | if (BUFFER_OBJFWDP (SYMBOL_FWD (sym)) | ||
| 3213 | && specpdl_kind (bind) == SPECPDL_LET_DEFAULT) | ||
| 3214 | { | ||
| 3215 | Fset_default (specpdl_symbol (bind), value); | ||
| 3216 | return; | ||
| 3217 | } | ||
| 3218 | /* FALLTHROUGH */ | ||
| 3219 | case SYMBOL_LOCALIZED: | ||
| 3220 | set_internal (specpdl_symbol (bind), value, Qnil, SET_INTERNAL_BIND); | ||
| 3221 | break; | ||
| 3222 | |||
| 3223 | default: | ||
| 3224 | emacs_abort (); | ||
| 3225 | } | ||
| 3226 | } | ||
| 3227 | |||
| 3178 | /* `specpdl_ptr' describes which variable is | 3228 | /* `specpdl_ptr' describes which variable is |
| 3179 | let-bound, so it can be properly undone when we unbind_to. | 3229 | let-bound, so it can be properly undone when we unbind_to. |
| 3180 | It can be either a plain SPECPDL_LET or a SPECPDL_LET_LOCAL/DEFAULT. | 3230 | It can be either a plain SPECPDL_LET or a SPECPDL_LET_LOCAL/DEFAULT. |
| @@ -3206,11 +3256,9 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3206 | specpdl_ptr->let.kind = SPECPDL_LET; | 3256 | specpdl_ptr->let.kind = SPECPDL_LET; |
| 3207 | specpdl_ptr->let.symbol = symbol; | 3257 | specpdl_ptr->let.symbol = symbol; |
| 3208 | specpdl_ptr->let.old_value = SYMBOL_VAL (sym); | 3258 | specpdl_ptr->let.old_value = SYMBOL_VAL (sym); |
| 3259 | specpdl_ptr->let.saved_value = Qnil; | ||
| 3209 | grow_specpdl (); | 3260 | grow_specpdl (); |
| 3210 | if (!sym->trapped_write) | 3261 | do_specbind (sym, specpdl_ptr - 1, value); |
| 3211 | SET_SYMBOL_VAL (sym, value); | ||
| 3212 | else | ||
| 3213 | set_internal (symbol, value, Qnil, SET_INTERNAL_BIND); | ||
| 3214 | break; | 3262 | break; |
| 3215 | case SYMBOL_LOCALIZED: | 3263 | case SYMBOL_LOCALIZED: |
| 3216 | if (SYMBOL_BLV (sym)->frame_local) | 3264 | if (SYMBOL_BLV (sym)->frame_local) |
| @@ -3222,6 +3270,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3222 | specpdl_ptr->let.symbol = symbol; | 3270 | specpdl_ptr->let.symbol = symbol; |
| 3223 | specpdl_ptr->let.old_value = ovalue; | 3271 | specpdl_ptr->let.old_value = ovalue; |
| 3224 | specpdl_ptr->let.where = Fcurrent_buffer (); | 3272 | specpdl_ptr->let.where = Fcurrent_buffer (); |
| 3273 | specpdl_ptr->let.saved_value = Qnil; | ||
| 3225 | 3274 | ||
| 3226 | eassert (sym->redirect != SYMBOL_LOCALIZED | 3275 | eassert (sym->redirect != SYMBOL_LOCALIZED |
| 3227 | || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ()))); | 3276 | || (EQ (SYMBOL_BLV (sym)->where, Fcurrent_buffer ()))); |
| @@ -3242,7 +3291,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3242 | { | 3291 | { |
| 3243 | specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT; | 3292 | specpdl_ptr->let.kind = SPECPDL_LET_DEFAULT; |
| 3244 | grow_specpdl (); | 3293 | grow_specpdl (); |
| 3245 | Fset_default (symbol, value); | 3294 | do_specbind (sym, specpdl_ptr - 1, value); |
| 3246 | return; | 3295 | return; |
| 3247 | } | 3296 | } |
| 3248 | } | 3297 | } |
| @@ -3250,7 +3299,7 @@ specbind (Lisp_Object symbol, Lisp_Object value) | |||
| 3250 | specpdl_ptr->let.kind = SPECPDL_LET; | 3299 | specpdl_ptr->let.kind = SPECPDL_LET; |
| 3251 | 3300 | ||
| 3252 | grow_specpdl (); | 3301 | grow_specpdl (); |
| 3253 | set_internal (symbol, value, Qnil, SET_INTERNAL_BIND); | 3302 | do_specbind (sym, specpdl_ptr - 1, value); |
| 3254 | break; | 3303 | break; |
| 3255 | } | 3304 | } |
| 3256 | default: emacs_abort (); | 3305 | default: emacs_abort (); |
| @@ -3294,6 +3343,91 @@ record_unwind_protect_void (void (*function) (void)) | |||
| 3294 | grow_specpdl (); | 3343 | grow_specpdl (); |
| 3295 | } | 3344 | } |
| 3296 | 3345 | ||
| 3346 | void | ||
| 3347 | rebind_for_thread_switch (void) | ||
| 3348 | { | ||
| 3349 | union specbinding *bind; | ||
| 3350 | |||
| 3351 | for (bind = specpdl; bind != specpdl_ptr; ++bind) | ||
| 3352 | { | ||
| 3353 | if (bind->kind >= SPECPDL_LET) | ||
| 3354 | { | ||
| 3355 | Lisp_Object value = specpdl_saved_value (bind); | ||
| 3356 | Lisp_Object sym = specpdl_symbol (bind); | ||
| 3357 | bool was_trapped = | ||
| 3358 | SYMBOLP (sym) | ||
| 3359 | && XSYMBOL (sym)->trapped_write == SYMBOL_TRAPPED_WRITE; | ||
| 3360 | /* FIXME: This is not clean, and if do_specbind signals an | ||
| 3361 | error, the symbol will be left untrapped. */ | ||
| 3362 | if (was_trapped) | ||
| 3363 | XSYMBOL (sym)->trapped_write = SYMBOL_UNTRAPPED_WRITE; | ||
| 3364 | bind->let.saved_value = Qnil; | ||
| 3365 | do_specbind (XSYMBOL (sym), bind, value); | ||
| 3366 | if (was_trapped) | ||
| 3367 | XSYMBOL (sym)->trapped_write = SYMBOL_TRAPPED_WRITE; | ||
| 3368 | } | ||
| 3369 | } | ||
| 3370 | } | ||
| 3371 | |||
| 3372 | static void | ||
| 3373 | do_one_unbind (union specbinding *this_binding, bool unwinding) | ||
| 3374 | { | ||
| 3375 | eassert (unwinding || this_binding->kind >= SPECPDL_LET); | ||
| 3376 | switch (this_binding->kind) | ||
| 3377 | { | ||
| 3378 | case SPECPDL_UNWIND: | ||
| 3379 | this_binding->unwind.func (this_binding->unwind.arg); | ||
| 3380 | break; | ||
| 3381 | case SPECPDL_UNWIND_PTR: | ||
| 3382 | this_binding->unwind_ptr.func (this_binding->unwind_ptr.arg); | ||
| 3383 | break; | ||
| 3384 | case SPECPDL_UNWIND_INT: | ||
| 3385 | this_binding->unwind_int.func (this_binding->unwind_int.arg); | ||
| 3386 | break; | ||
| 3387 | case SPECPDL_UNWIND_VOID: | ||
| 3388 | this_binding->unwind_void.func (); | ||
| 3389 | break; | ||
| 3390 | case SPECPDL_BACKTRACE: | ||
| 3391 | break; | ||
| 3392 | case SPECPDL_LET: | ||
| 3393 | { /* If variable has a trivial value (no forwarding), and isn't | ||
| 3394 | trapped, we can just set it. */ | ||
| 3395 | Lisp_Object sym = specpdl_symbol (this_binding); | ||
| 3396 | if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL) | ||
| 3397 | { | ||
| 3398 | if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE) | ||
| 3399 | SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (this_binding)); | ||
| 3400 | else | ||
| 3401 | set_internal (sym, specpdl_old_value (this_binding), | ||
| 3402 | Qnil, SET_INTERNAL_UNBIND); | ||
| 3403 | break; | ||
| 3404 | } | ||
| 3405 | else | ||
| 3406 | { /* FALLTHROUGH!! | ||
| 3407 | NOTE: we only ever come here if make_local_foo was used for | ||
| 3408 | the first time on this var within this let. */ | ||
| 3409 | } | ||
| 3410 | } | ||
| 3411 | case SPECPDL_LET_DEFAULT: | ||
| 3412 | Fset_default (specpdl_symbol (this_binding), | ||
| 3413 | specpdl_old_value (this_binding)); | ||
| 3414 | break; | ||
| 3415 | case SPECPDL_LET_LOCAL: | ||
| 3416 | { | ||
| 3417 | Lisp_Object symbol = specpdl_symbol (this_binding); | ||
| 3418 | Lisp_Object where = specpdl_where (this_binding); | ||
| 3419 | Lisp_Object old_value = specpdl_old_value (this_binding); | ||
| 3420 | eassert (BUFFERP (where)); | ||
| 3421 | |||
| 3422 | /* If this was a local binding, reset the value in the appropriate | ||
| 3423 | buffer, but only if that buffer's binding still exists. */ | ||
| 3424 | if (!NILP (Flocal_variable_p (symbol, where))) | ||
| 3425 | set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND); | ||
| 3426 | } | ||
| 3427 | break; | ||
| 3428 | } | ||
| 3429 | } | ||
| 3430 | |||
| 3297 | static void | 3431 | static void |
| 3298 | do_nothing (void) | 3432 | do_nothing (void) |
| 3299 | {} | 3433 | {} |
| @@ -3353,66 +3487,16 @@ unbind_to (ptrdiff_t count, Lisp_Object value) | |||
| 3353 | 3487 | ||
| 3354 | while (specpdl_ptr != specpdl + count) | 3488 | while (specpdl_ptr != specpdl + count) |
| 3355 | { | 3489 | { |
| 3356 | /* Decrement specpdl_ptr before we do the work to unbind it, so | 3490 | /* Copy the binding, and decrement specpdl_ptr, before we do |
| 3357 | that an error in unbinding won't try to unbind the same entry | 3491 | the work to unbind it. We decrement first |
| 3358 | again. Take care to copy any parts of the binding needed | 3492 | so that an error in unbinding won't try to unbind |
| 3359 | before invoking any code that can make more bindings. */ | 3493 | the same entry again, and we copy the binding first |
| 3494 | in case more bindings are made during some of the code we run. */ | ||
| 3360 | 3495 | ||
| 3361 | specpdl_ptr--; | 3496 | union specbinding this_binding; |
| 3362 | 3497 | this_binding = *--specpdl_ptr; | |
| 3363 | switch (specpdl_ptr->kind) | ||
| 3364 | { | ||
| 3365 | case SPECPDL_UNWIND: | ||
| 3366 | specpdl_ptr->unwind.func (specpdl_ptr->unwind.arg); | ||
| 3367 | break; | ||
| 3368 | case SPECPDL_UNWIND_PTR: | ||
| 3369 | specpdl_ptr->unwind_ptr.func (specpdl_ptr->unwind_ptr.arg); | ||
| 3370 | break; | ||
| 3371 | case SPECPDL_UNWIND_INT: | ||
| 3372 | specpdl_ptr->unwind_int.func (specpdl_ptr->unwind_int.arg); | ||
| 3373 | break; | ||
| 3374 | case SPECPDL_UNWIND_VOID: | ||
| 3375 | specpdl_ptr->unwind_void.func (); | ||
| 3376 | break; | ||
| 3377 | case SPECPDL_BACKTRACE: | ||
| 3378 | break; | ||
| 3379 | case SPECPDL_LET: | ||
| 3380 | { /* If variable has a trivial value (no forwarding), and | ||
| 3381 | isn't trapped, we can just set it. */ | ||
| 3382 | Lisp_Object sym = specpdl_symbol (specpdl_ptr); | ||
| 3383 | if (SYMBOLP (sym) && XSYMBOL (sym)->redirect == SYMBOL_PLAINVAL) | ||
| 3384 | { | ||
| 3385 | if (XSYMBOL (sym)->trapped_write == SYMBOL_UNTRAPPED_WRITE) | ||
| 3386 | SET_SYMBOL_VAL (XSYMBOL (sym), specpdl_old_value (specpdl_ptr)); | ||
| 3387 | else | ||
| 3388 | set_internal (sym, specpdl_old_value (specpdl_ptr), | ||
| 3389 | Qnil, SET_INTERNAL_UNBIND); | ||
| 3390 | break; | ||
| 3391 | } | ||
| 3392 | else | ||
| 3393 | { /* FALLTHROUGH!! | ||
| 3394 | NOTE: we only ever come here if make_local_foo was used for | ||
| 3395 | the first time on this var within this let. */ | ||
| 3396 | } | ||
| 3397 | } | ||
| 3398 | case SPECPDL_LET_DEFAULT: | ||
| 3399 | Fset_default (specpdl_symbol (specpdl_ptr), | ||
| 3400 | specpdl_old_value (specpdl_ptr)); | ||
| 3401 | break; | ||
| 3402 | case SPECPDL_LET_LOCAL: | ||
| 3403 | { | ||
| 3404 | Lisp_Object symbol = specpdl_symbol (specpdl_ptr); | ||
| 3405 | Lisp_Object where = specpdl_where (specpdl_ptr); | ||
| 3406 | Lisp_Object old_value = specpdl_old_value (specpdl_ptr); | ||
| 3407 | eassert (BUFFERP (where)); | ||
| 3408 | 3498 | ||
| 3409 | /* If this was a local binding, reset the value in the appropriate | 3499 | do_one_unbind (&this_binding, true); |
| 3410 | buffer, but only if that buffer's binding still exists. */ | ||
| 3411 | if (!NILP (Flocal_variable_p (symbol, where))) | ||
| 3412 | set_internal (symbol, old_value, where, SET_INTERNAL_UNBIND); | ||
| 3413 | } | ||
| 3414 | break; | ||
| 3415 | } | ||
| 3416 | } | 3500 | } |
| 3417 | 3501 | ||
| 3418 | if (NILP (Vquit_flag) && !NILP (quitf)) | 3502 | if (NILP (Vquit_flag) && !NILP (quitf)) |
| @@ -3421,6 +3505,31 @@ unbind_to (ptrdiff_t count, Lisp_Object value) | |||
| 3421 | return value; | 3505 | return value; |
| 3422 | } | 3506 | } |
| 3423 | 3507 | ||
| 3508 | void | ||
| 3509 | unbind_for_thread_switch (struct thread_state *thr) | ||
| 3510 | { | ||
| 3511 | union specbinding *bind; | ||
| 3512 | |||
| 3513 | for (bind = thr->m_specpdl_ptr; bind > thr->m_specpdl;) | ||
| 3514 | { | ||
| 3515 | if ((--bind)->kind >= SPECPDL_LET) | ||
| 3516 | { | ||
| 3517 | Lisp_Object sym = specpdl_symbol (bind); | ||
| 3518 | bool was_trapped = | ||
| 3519 | SYMBOLP (sym) | ||
| 3520 | && XSYMBOL (sym)->trapped_write == SYMBOL_TRAPPED_WRITE; | ||
| 3521 | bind->let.saved_value = find_symbol_value (sym); | ||
| 3522 | /* FIXME: This is not clean, and if do_one_unbind signals an | ||
| 3523 | error, the symbol will be left untrapped. */ | ||
| 3524 | if (was_trapped) | ||
| 3525 | XSYMBOL (sym)->trapped_write = SYMBOL_UNTRAPPED_WRITE; | ||
| 3526 | do_one_unbind (bind, false); | ||
| 3527 | if (was_trapped) | ||
| 3528 | XSYMBOL (sym)->trapped_write = SYMBOL_TRAPPED_WRITE; | ||
| 3529 | } | ||
| 3530 | } | ||
| 3531 | } | ||
| 3532 | |||
| 3424 | DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0, | 3533 | DEFUN ("special-variable-p", Fspecial_variable_p, Sspecial_variable_p, 1, 1, 0, |
| 3425 | doc: /* Return non-nil if SYMBOL's global binding has been declared special. | 3534 | doc: /* Return non-nil if SYMBOL's global binding has been declared special. |
| 3426 | A special variable is one that will be bound dynamically, even in a | 3535 | A special variable is one that will be bound dynamically, even in a |
| @@ -3743,10 +3852,10 @@ NFRAMES and BASE specify the activation frame to use, as in `backtrace-frame'. | |||
| 3743 | 3852 | ||
| 3744 | 3853 | ||
| 3745 | void | 3854 | void |
| 3746 | mark_specpdl (void) | 3855 | mark_specpdl (union specbinding *first, union specbinding *ptr) |
| 3747 | { | 3856 | { |
| 3748 | union specbinding *pdl; | 3857 | union specbinding *pdl; |
| 3749 | for (pdl = specpdl; pdl != specpdl_ptr; pdl++) | 3858 | for (pdl = first; pdl != ptr; pdl++) |
| 3750 | { | 3859 | { |
| 3751 | switch (pdl->kind) | 3860 | switch (pdl->kind) |
| 3752 | { | 3861 | { |
| @@ -3772,6 +3881,7 @@ mark_specpdl (void) | |||
| 3772 | case SPECPDL_LET: | 3881 | case SPECPDL_LET: |
| 3773 | mark_object (specpdl_symbol (pdl)); | 3882 | mark_object (specpdl_symbol (pdl)); |
| 3774 | mark_object (specpdl_old_value (pdl)); | 3883 | mark_object (specpdl_old_value (pdl)); |
| 3884 | mark_object (specpdl_saved_value (pdl)); | ||
| 3775 | break; | 3885 | break; |
| 3776 | 3886 | ||
| 3777 | case SPECPDL_UNWIND_PTR: | 3887 | case SPECPDL_UNWIND_PTR: |
diff --git a/src/lisp.h b/src/lisp.h index 11e49b6ee7e..252707c3495 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -34,6 +34,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 34 | #include <intprops.h> | 34 | #include <intprops.h> |
| 35 | #include <verify.h> | 35 | #include <verify.h> |
| 36 | 36 | ||
| 37 | #include "systhread.h" | ||
| 38 | |||
| 37 | INLINE_HEADER_BEGIN | 39 | INLINE_HEADER_BEGIN |
| 38 | 40 | ||
| 39 | /* Define a TYPE constant ID as an externally visible name. Use like this: | 41 | /* Define a TYPE constant ID as an externally visible name. Use like this: |
| @@ -588,6 +590,9 @@ INLINE bool (SYMBOLP) (Lisp_Object); | |||
| 588 | INLINE bool (VECTORLIKEP) (Lisp_Object); | 590 | INLINE bool (VECTORLIKEP) (Lisp_Object); |
| 589 | INLINE bool WINDOWP (Lisp_Object); | 591 | INLINE bool WINDOWP (Lisp_Object); |
| 590 | INLINE bool TERMINALP (Lisp_Object); | 592 | INLINE bool TERMINALP (Lisp_Object); |
| 593 | INLINE bool THREADP (Lisp_Object); | ||
| 594 | INLINE bool MUTEXP (Lisp_Object); | ||
| 595 | INLINE bool CONDVARP (Lisp_Object); | ||
| 591 | INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object); | 596 | INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object); |
| 592 | INLINE struct Lisp_Finalizer *XFINALIZER (Lisp_Object); | 597 | INLINE struct Lisp_Finalizer *XFINALIZER (Lisp_Object); |
| 593 | INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object); | 598 | INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object); |
| @@ -756,6 +761,39 @@ struct Lisp_Symbol | |||
| 756 | 761 | ||
| 757 | #include "globals.h" | 762 | #include "globals.h" |
| 758 | 763 | ||
| 764 | /* Header of vector-like objects. This documents the layout constraints on | ||
| 765 | vectors and pseudovectors (objects of PVEC_xxx subtype). It also prevents | ||
| 766 | compilers from being fooled by Emacs's type punning: XSETPSEUDOVECTOR | ||
| 767 | and PSEUDOVECTORP cast their pointers to struct vectorlike_header *, | ||
| 768 | because when two such pointers potentially alias, a compiler won't | ||
| 769 | incorrectly reorder loads and stores to their size fields. See | ||
| 770 | Bug#8546. */ | ||
| 771 | struct vectorlike_header | ||
| 772 | { | ||
| 773 | /* The only field contains various pieces of information: | ||
| 774 | - The MSB (ARRAY_MARK_FLAG) holds the gcmarkbit. | ||
| 775 | - The next bit (PSEUDOVECTOR_FLAG) indicates whether this is a plain | ||
| 776 | vector (0) or a pseudovector (1). | ||
| 777 | - If PSEUDOVECTOR_FLAG is 0, the rest holds the size (number | ||
| 778 | of slots) of the vector. | ||
| 779 | - If PSEUDOVECTOR_FLAG is 1, the rest is subdivided into three fields: | ||
| 780 | - a) pseudovector subtype held in PVEC_TYPE_MASK field; | ||
| 781 | - b) number of Lisp_Objects slots at the beginning of the object | ||
| 782 | held in PSEUDOVECTOR_SIZE_MASK field. These objects are always | ||
| 783 | traced by the GC; | ||
| 784 | - c) size of the rest fields held in PSEUDOVECTOR_REST_MASK and | ||
| 785 | measured in word_size units. Rest fields may also include | ||
| 786 | Lisp_Objects, but these objects usually needs some special treatment | ||
| 787 | during GC. | ||
| 788 | There are some exceptions. For PVEC_FREE, b) is always zero. For | ||
| 789 | PVEC_BOOL_VECTOR and PVEC_SUBR, both b) and c) are always zero. | ||
| 790 | Current layout limits the pseudovectors to 63 PVEC_xxx subtypes, | ||
| 791 | 4095 Lisp_Objects in GC-ed area and 4095 word-sized other slots. */ | ||
| 792 | ptrdiff_t size; | ||
| 793 | }; | ||
| 794 | |||
| 795 | #include "thread.h" | ||
| 796 | |||
| 759 | /* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa. | 797 | /* Convert a Lisp_Object to the corresponding EMACS_INT and vice versa. |
| 760 | At the machine level, these operations are no-ops. */ | 798 | At the machine level, these operations are no-ops. */ |
| 761 | 799 | ||
| @@ -802,6 +840,9 @@ enum pvec_type | |||
| 802 | PVEC_OTHER, | 840 | PVEC_OTHER, |
| 803 | PVEC_XWIDGET, | 841 | PVEC_XWIDGET, |
| 804 | PVEC_XWIDGET_VIEW, | 842 | PVEC_XWIDGET_VIEW, |
| 843 | PVEC_THREAD, | ||
| 844 | PVEC_MUTEX, | ||
| 845 | PVEC_CONDVAR, | ||
| 805 | 846 | ||
| 806 | /* These should be last, check internal_equal to see why. */ | 847 | /* These should be last, check internal_equal to see why. */ |
| 807 | PVEC_COMPILED, | 848 | PVEC_COMPILED, |
| @@ -1105,6 +1146,27 @@ XBOOL_VECTOR (Lisp_Object a) | |||
| 1105 | return XUNTAG (a, Lisp_Vectorlike); | 1146 | return XUNTAG (a, Lisp_Vectorlike); |
| 1106 | } | 1147 | } |
| 1107 | 1148 | ||
| 1149 | INLINE struct thread_state * | ||
| 1150 | XTHREAD (Lisp_Object a) | ||
| 1151 | { | ||
| 1152 | eassert (THREADP (a)); | ||
| 1153 | return XUNTAG (a, Lisp_Vectorlike); | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | INLINE struct Lisp_Mutex * | ||
| 1157 | XMUTEX (Lisp_Object a) | ||
| 1158 | { | ||
| 1159 | eassert (MUTEXP (a)); | ||
| 1160 | return XUNTAG (a, Lisp_Vectorlike); | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | INLINE struct Lisp_CondVar * | ||
| 1164 | XCONDVAR (Lisp_Object a) | ||
| 1165 | { | ||
| 1166 | eassert (CONDVARP (a)); | ||
| 1167 | return XUNTAG (a, Lisp_Vectorlike); | ||
| 1168 | } | ||
| 1169 | |||
| 1108 | /* Construct a Lisp_Object from a value or address. */ | 1170 | /* Construct a Lisp_Object from a value or address. */ |
| 1109 | 1171 | ||
| 1110 | INLINE Lisp_Object | 1172 | INLINE Lisp_Object |
| @@ -1171,6 +1233,9 @@ builtin_lisp_symbol (int index) | |||
| 1171 | #define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE)) | 1233 | #define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE)) |
| 1172 | #define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR)) | 1234 | #define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR)) |
| 1173 | #define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE)) | 1235 | #define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE)) |
| 1236 | #define XSETTHREAD(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_THREAD)) | ||
| 1237 | #define XSETMUTEX(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_MUTEX)) | ||
| 1238 | #define XSETCONDVAR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CONDVAR)) | ||
| 1174 | 1239 | ||
| 1175 | /* Efficiently convert a pointer to a Lisp object and back. The | 1240 | /* Efficiently convert a pointer to a Lisp object and back. The |
| 1176 | pointer is represented as a Lisp integer, so the garbage collector | 1241 | pointer is represented as a Lisp integer, so the garbage collector |
| @@ -1402,37 +1467,6 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize) | |||
| 1402 | XSTRING (string)->size = newsize; | 1467 | XSTRING (string)->size = newsize; |
| 1403 | } | 1468 | } |
| 1404 | 1469 | ||
| 1405 | /* Header of vector-like objects. This documents the layout constraints on | ||
| 1406 | vectors and pseudovectors (objects of PVEC_xxx subtype). It also prevents | ||
| 1407 | compilers from being fooled by Emacs's type punning: XSETPSEUDOVECTOR | ||
| 1408 | and PSEUDOVECTORP cast their pointers to struct vectorlike_header *, | ||
| 1409 | because when two such pointers potentially alias, a compiler won't | ||
| 1410 | incorrectly reorder loads and stores to their size fields. See | ||
| 1411 | Bug#8546. */ | ||
| 1412 | struct vectorlike_header | ||
| 1413 | { | ||
| 1414 | /* The only field contains various pieces of information: | ||
| 1415 | - The MSB (ARRAY_MARK_FLAG) holds the gcmarkbit. | ||
| 1416 | - The next bit (PSEUDOVECTOR_FLAG) indicates whether this is a plain | ||
| 1417 | vector (0) or a pseudovector (1). | ||
| 1418 | - If PSEUDOVECTOR_FLAG is 0, the rest holds the size (number | ||
| 1419 | of slots) of the vector. | ||
| 1420 | - If PSEUDOVECTOR_FLAG is 1, the rest is subdivided into three fields: | ||
| 1421 | - a) pseudovector subtype held in PVEC_TYPE_MASK field; | ||
| 1422 | - b) number of Lisp_Objects slots at the beginning of the object | ||
| 1423 | held in PSEUDOVECTOR_SIZE_MASK field. These objects are always | ||
| 1424 | traced by the GC; | ||
| 1425 | - c) size of the rest fields held in PSEUDOVECTOR_REST_MASK and | ||
| 1426 | measured in word_size units. Rest fields may also include | ||
| 1427 | Lisp_Objects, but these objects usually needs some special treatment | ||
| 1428 | during GC. | ||
| 1429 | There are some exceptions. For PVEC_FREE, b) is always zero. For | ||
| 1430 | PVEC_BOOL_VECTOR and PVEC_SUBR, both b) and c) are always zero. | ||
| 1431 | Current layout limits the pseudovectors to 63 PVEC_xxx subtypes, | ||
| 1432 | 4095 Lisp_Objects in GC-ed area and 4095 word-sized other slots. */ | ||
| 1433 | ptrdiff_t size; | ||
| 1434 | }; | ||
| 1435 | |||
| 1436 | /* A regular vector is just a header plus an array of Lisp_Objects. */ | 1470 | /* A regular vector is just a header plus an array of Lisp_Objects. */ |
| 1437 | 1471 | ||
| 1438 | struct Lisp_Vector | 1472 | struct Lisp_Vector |
| @@ -2782,6 +2816,24 @@ FRAMEP (Lisp_Object a) | |||
| 2782 | return PSEUDOVECTORP (a, PVEC_FRAME); | 2816 | return PSEUDOVECTORP (a, PVEC_FRAME); |
| 2783 | } | 2817 | } |
| 2784 | 2818 | ||
| 2819 | INLINE bool | ||
| 2820 | THREADP (Lisp_Object a) | ||
| 2821 | { | ||
| 2822 | return PSEUDOVECTORP (a, PVEC_THREAD); | ||
| 2823 | } | ||
| 2824 | |||
| 2825 | INLINE bool | ||
| 2826 | MUTEXP (Lisp_Object a) | ||
| 2827 | { | ||
| 2828 | return PSEUDOVECTORP (a, PVEC_MUTEX); | ||
| 2829 | } | ||
| 2830 | |||
| 2831 | INLINE bool | ||
| 2832 | CONDVARP (Lisp_Object a) | ||
| 2833 | { | ||
| 2834 | return PSEUDOVECTORP (a, PVEC_CONDVAR); | ||
| 2835 | } | ||
| 2836 | |||
| 2785 | /* Test for image (image . spec) */ | 2837 | /* Test for image (image . spec) */ |
| 2786 | INLINE bool | 2838 | INLINE bool |
| 2787 | IMAGEP (Lisp_Object x) | 2839 | IMAGEP (Lisp_Object x) |
| @@ -2930,6 +2982,25 @@ CHECK_NUMBER_OR_FLOAT (Lisp_Object x) | |||
| 2930 | CHECK_TYPE (NUMBERP (x), Qnumber_or_marker_p, x); \ | 2982 | CHECK_TYPE (NUMBERP (x), Qnumber_or_marker_p, x); \ |
| 2931 | } while (false) | 2983 | } while (false) |
| 2932 | 2984 | ||
| 2985 | |||
| 2986 | INLINE void | ||
| 2987 | CHECK_THREAD (Lisp_Object x) | ||
| 2988 | { | ||
| 2989 | CHECK_TYPE (THREADP (x), Qthreadp, x); | ||
| 2990 | } | ||
| 2991 | |||
| 2992 | INLINE void | ||
| 2993 | CHECK_MUTEX (Lisp_Object x) | ||
| 2994 | { | ||
| 2995 | CHECK_TYPE (MUTEXP (x), Qmutexp, x); | ||
| 2996 | } | ||
| 2997 | |||
| 2998 | INLINE void | ||
| 2999 | CHECK_CONDVAR (Lisp_Object x) | ||
| 3000 | { | ||
| 3001 | CHECK_TYPE (CONDVARP (x), Qcondition_variable_p, x); | ||
| 3002 | } | ||
| 3003 | |||
| 2933 | /* Since we can't assign directly to the CAR or CDR fields of a cons | 3004 | /* Since we can't assign directly to the CAR or CDR fields of a cons |
| 2934 | cell, use these when checking that those fields contain numbers. */ | 3005 | cell, use these when checking that those fields contain numbers. */ |
| 2935 | INLINE void | 3006 | INLINE void |
| @@ -3141,6 +3212,9 @@ union specbinding | |||
| 3141 | ENUM_BF (specbind_tag) kind : CHAR_BIT; | 3212 | ENUM_BF (specbind_tag) kind : CHAR_BIT; |
| 3142 | /* `where' is not used in the case of SPECPDL_LET. */ | 3213 | /* `where' is not used in the case of SPECPDL_LET. */ |
| 3143 | Lisp_Object symbol, old_value, where; | 3214 | Lisp_Object symbol, old_value, where; |
| 3215 | /* Normally this is unused; but it is set to the symbol's | ||
| 3216 | current value when a thread is swapped out. */ | ||
| 3217 | Lisp_Object saved_value; | ||
| 3144 | } let; | 3218 | } let; |
| 3145 | struct { | 3219 | struct { |
| 3146 | ENUM_BF (specbind_tag) kind : CHAR_BIT; | 3220 | ENUM_BF (specbind_tag) kind : CHAR_BIT; |
| @@ -3151,9 +3225,10 @@ union specbinding | |||
| 3151 | } bt; | 3225 | } bt; |
| 3152 | }; | 3226 | }; |
| 3153 | 3227 | ||
| 3154 | extern union specbinding *specpdl; | 3228 | /* These 3 are defined as macros in thread.h. */ |
| 3155 | extern union specbinding *specpdl_ptr; | 3229 | /* extern union specbinding *specpdl; */ |
| 3156 | extern ptrdiff_t specpdl_size; | 3230 | /* extern union specbinding *specpdl_ptr; */ |
| 3231 | /* extern ptrdiff_t specpdl_size; */ | ||
| 3157 | 3232 | ||
| 3158 | INLINE ptrdiff_t | 3233 | INLINE ptrdiff_t |
| 3159 | SPECPDL_INDEX (void) | 3234 | SPECPDL_INDEX (void) |
| @@ -3204,18 +3279,15 @@ struct handler | |||
| 3204 | /* Most global vars are reset to their value via the specpdl mechanism, | 3279 | /* Most global vars are reset to their value via the specpdl mechanism, |
| 3205 | but a few others are handled by storing their value here. */ | 3280 | but a few others are handled by storing their value here. */ |
| 3206 | sys_jmp_buf jmp; | 3281 | sys_jmp_buf jmp; |
| 3207 | EMACS_INT lisp_eval_depth; | 3282 | EMACS_INT f_lisp_eval_depth; |
| 3208 | ptrdiff_t pdlcount; | 3283 | ptrdiff_t pdlcount; |
| 3209 | int poll_suppress_count; | 3284 | int poll_suppress_count; |
| 3210 | int interrupt_input_blocked; | 3285 | int interrupt_input_blocked; |
| 3286 | struct byte_stack *byte_stack; | ||
| 3211 | }; | 3287 | }; |
| 3212 | 3288 | ||
| 3213 | extern Lisp_Object memory_signal_data; | 3289 | extern Lisp_Object memory_signal_data; |
| 3214 | 3290 | ||
| 3215 | /* An address near the bottom of the stack. | ||
| 3216 | Tells GC how to save a copy of the stack. */ | ||
| 3217 | extern char *stack_bottom; | ||
| 3218 | |||
| 3219 | /* Check quit-flag and quit if it is non-nil. | 3291 | /* Check quit-flag and quit if it is non-nil. |
| 3220 | Typing C-g does not directly cause a quit; it only sets Vquit_flag. | 3292 | Typing C-g does not directly cause a quit; it only sets Vquit_flag. |
| 3221 | So the program needs to do QUIT at times when it is safe to quit. | 3293 | So the program needs to do QUIT at times when it is safe to quit. |
| @@ -3617,9 +3689,10 @@ extern void refill_memory_reserve (void); | |||
| 3617 | #endif | 3689 | #endif |
| 3618 | extern void alloc_unexec_pre (void); | 3690 | extern void alloc_unexec_pre (void); |
| 3619 | extern void alloc_unexec_post (void); | 3691 | extern void alloc_unexec_post (void); |
| 3692 | extern void mark_stack (char *, char *); | ||
| 3693 | extern void flush_stack_call_func (void (*func) (void *arg), void *arg); | ||
| 3620 | extern const char *pending_malloc_warning; | 3694 | extern const char *pending_malloc_warning; |
| 3621 | extern Lisp_Object zero_vector; | 3695 | extern Lisp_Object zero_vector; |
| 3622 | extern Lisp_Object *stack_base; | ||
| 3623 | extern EMACS_INT consing_since_gc; | 3696 | extern EMACS_INT consing_since_gc; |
| 3624 | extern EMACS_INT gc_relative_threshold; | 3697 | extern EMACS_INT gc_relative_threshold; |
| 3625 | extern EMACS_INT memory_full_cons_threshold; | 3698 | extern EMACS_INT memory_full_cons_threshold; |
| @@ -3881,7 +3954,6 @@ extern Lisp_Object Vautoload_queue; | |||
| 3881 | extern Lisp_Object Vrun_hooks; | 3954 | extern Lisp_Object Vrun_hooks; |
| 3882 | extern Lisp_Object Vsignaling_function; | 3955 | extern Lisp_Object Vsignaling_function; |
| 3883 | extern Lisp_Object inhibit_lisp_code; | 3956 | extern Lisp_Object inhibit_lisp_code; |
| 3884 | extern struct handler *handlerlist; | ||
| 3885 | 3957 | ||
| 3886 | /* To run a normal hook, use the appropriate function from the list below. | 3958 | /* To run a normal hook, use the appropriate function from the list below. |
| 3887 | The calling convention: | 3959 | The calling convention: |
| @@ -3939,6 +4011,8 @@ extern void clear_unwind_protect (ptrdiff_t); | |||
| 3939 | extern void set_unwind_protect (ptrdiff_t, void (*) (Lisp_Object), Lisp_Object); | 4011 | extern void set_unwind_protect (ptrdiff_t, void (*) (Lisp_Object), Lisp_Object); |
| 3940 | extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *); | 4012 | extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *); |
| 3941 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); | 4013 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); |
| 4014 | extern void rebind_for_thread_switch (void); | ||
| 4015 | extern void unbind_for_thread_switch (struct thread_state *); | ||
| 3942 | extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); | 4016 | extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); |
| 3943 | extern _Noreturn void verror (const char *, va_list) | 4017 | extern _Noreturn void verror (const char *, va_list) |
| 3944 | ATTRIBUTE_FORMAT_PRINTF (1, 0); | 4018 | ATTRIBUTE_FORMAT_PRINTF (1, 0); |
| @@ -3955,7 +4029,7 @@ extern void init_eval (void); | |||
| 3955 | extern void syms_of_eval (void); | 4029 | extern void syms_of_eval (void); |
| 3956 | extern void unwind_body (Lisp_Object); | 4030 | extern void unwind_body (Lisp_Object); |
| 3957 | extern ptrdiff_t record_in_backtrace (Lisp_Object, Lisp_Object *, ptrdiff_t); | 4031 | extern ptrdiff_t record_in_backtrace (Lisp_Object, Lisp_Object *, ptrdiff_t); |
| 3958 | extern void mark_specpdl (void); | 4032 | extern void mark_specpdl (union specbinding *first, union specbinding *ptr); |
| 3959 | extern void get_backtrace (Lisp_Object array); | 4033 | extern void get_backtrace (Lisp_Object array); |
| 3960 | Lisp_Object backtrace_top_function (void); | 4034 | Lisp_Object backtrace_top_function (void); |
| 3961 | extern bool let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol); | 4035 | extern bool let_shadows_buffer_binding_p (struct Lisp_Symbol *symbol); |
| @@ -3970,6 +4044,9 @@ extern void module_init (void); | |||
| 3970 | extern void syms_of_module (void); | 4044 | extern void syms_of_module (void); |
| 3971 | #endif | 4045 | #endif |
| 3972 | 4046 | ||
| 4047 | /* Defined in thread.c. */ | ||
| 4048 | extern void mark_threads (void); | ||
| 4049 | |||
| 3973 | /* Defined in editfns.c. */ | 4050 | /* Defined in editfns.c. */ |
| 3974 | extern void insert1 (Lisp_Object); | 4051 | extern void insert1 (Lisp_Object); |
| 3975 | extern Lisp_Object save_excursion_save (void); | 4052 | extern Lisp_Object save_excursion_save (void); |
| @@ -4250,6 +4327,7 @@ extern int read_bytecode_char (bool); | |||
| 4250 | 4327 | ||
| 4251 | /* Defined in bytecode.c. */ | 4328 | /* Defined in bytecode.c. */ |
| 4252 | extern void syms_of_bytecode (void); | 4329 | extern void syms_of_bytecode (void); |
| 4330 | extern void relocate_byte_stack (struct byte_stack *); | ||
| 4253 | extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object, | 4331 | extern Lisp_Object exec_byte_code (Lisp_Object, Lisp_Object, Lisp_Object, |
| 4254 | Lisp_Object, ptrdiff_t, Lisp_Object *); | 4332 | Lisp_Object, ptrdiff_t, Lisp_Object *); |
| 4255 | extern Lisp_Object get_byte_code_arity (Lisp_Object); | 4333 | extern Lisp_Object get_byte_code_arity (Lisp_Object); |
diff --git a/src/print.c b/src/print.c index f3db6748d03..6c350fc86aa 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -1911,6 +1911,42 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 1911 | } | 1911 | } |
| 1912 | printchar ('>', printcharfun); | 1912 | printchar ('>', printcharfun); |
| 1913 | } | 1913 | } |
| 1914 | else if (THREADP (obj)) | ||
| 1915 | { | ||
| 1916 | print_c_string ("#<thread ", printcharfun); | ||
| 1917 | if (STRINGP (XTHREAD (obj)->name)) | ||
| 1918 | print_string (XTHREAD (obj)->name, printcharfun); | ||
| 1919 | else | ||
| 1920 | { | ||
| 1921 | int len = sprintf (buf, "%p", XTHREAD (obj)); | ||
| 1922 | strout (buf, len, len, printcharfun); | ||
| 1923 | } | ||
| 1924 | printchar ('>', printcharfun); | ||
| 1925 | } | ||
| 1926 | else if (MUTEXP (obj)) | ||
| 1927 | { | ||
| 1928 | print_c_string ("#<mutex ", printcharfun); | ||
| 1929 | if (STRINGP (XMUTEX (obj)->name)) | ||
| 1930 | print_string (XMUTEX (obj)->name, printcharfun); | ||
| 1931 | else | ||
| 1932 | { | ||
| 1933 | int len = sprintf (buf, "%p", XMUTEX (obj)); | ||
| 1934 | strout (buf, len, len, printcharfun); | ||
| 1935 | } | ||
| 1936 | printchar ('>', printcharfun); | ||
| 1937 | } | ||
| 1938 | else if (CONDVARP (obj)) | ||
| 1939 | { | ||
| 1940 | print_c_string ("#<condvar ", printcharfun); | ||
| 1941 | if (STRINGP (XCONDVAR (obj)->name)) | ||
| 1942 | print_string (XCONDVAR (obj)->name, printcharfun); | ||
| 1943 | else | ||
| 1944 | { | ||
| 1945 | int len = sprintf (buf, "%p", XCONDVAR (obj)); | ||
| 1946 | strout (buf, len, len, printcharfun); | ||
| 1947 | } | ||
| 1948 | printchar ('>', printcharfun); | ||
| 1949 | } | ||
| 1914 | else | 1950 | else |
| 1915 | { | 1951 | { |
| 1916 | ptrdiff_t size = ASIZE (obj); | 1952 | ptrdiff_t size = ASIZE (obj); |
diff --git a/src/process.c b/src/process.c index 8ab73bd9ae6..31c9d74a3f2 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -138,7 +138,7 @@ static struct rlimit nofile_limit; | |||
| 138 | 138 | ||
| 139 | #ifdef WINDOWSNT | 139 | #ifdef WINDOWSNT |
| 140 | extern int sys_select (int, fd_set *, fd_set *, fd_set *, | 140 | extern int sys_select (int, fd_set *, fd_set *, fd_set *, |
| 141 | struct timespec *, void *); | 141 | const struct timespec *, const sigset_t *); |
| 142 | #endif | 142 | #endif |
| 143 | 143 | ||
| 144 | /* Work around GCC 4.3.0 bug with strict overflow checking; see | 144 | /* Work around GCC 4.3.0 bug with strict overflow checking; see |
| @@ -260,36 +260,11 @@ static int read_process_output (Lisp_Object, int); | |||
| 260 | static void create_pty (Lisp_Object); | 260 | static void create_pty (Lisp_Object); |
| 261 | static void exec_sentinel (Lisp_Object, Lisp_Object); | 261 | static void exec_sentinel (Lisp_Object, Lisp_Object); |
| 262 | 262 | ||
| 263 | /* Mask of bits indicating the descriptors that we wait for input on. */ | ||
| 264 | |||
| 265 | static fd_set input_wait_mask; | ||
| 266 | |||
| 267 | /* Mask that excludes keyboard input descriptor(s). */ | ||
| 268 | |||
| 269 | static fd_set non_keyboard_wait_mask; | ||
| 270 | |||
| 271 | /* Mask that excludes process input descriptor(s). */ | ||
| 272 | |||
| 273 | static fd_set non_process_wait_mask; | ||
| 274 | |||
| 275 | /* Mask for selecting for write. */ | ||
| 276 | |||
| 277 | static fd_set write_mask; | ||
| 278 | |||
| 279 | /* Mask of bits indicating the descriptors that we wait for connect to | ||
| 280 | complete on. Once they complete, they are removed from this mask | ||
| 281 | and added to the input_wait_mask and non_keyboard_wait_mask. */ | ||
| 282 | |||
| 283 | static fd_set connect_wait_mask; | ||
| 284 | |||
| 285 | /* Number of bits set in connect_wait_mask. */ | 263 | /* Number of bits set in connect_wait_mask. */ |
| 286 | static int num_pending_connects; | 264 | static int num_pending_connects; |
| 287 | 265 | ||
| 288 | /* The largest descriptor currently in use for a process object; -1 if none. */ | 266 | /* The largest descriptor currently in use; -1 if none. */ |
| 289 | static int max_process_desc; | 267 | static int max_desc; |
| 290 | |||
| 291 | /* The largest descriptor currently in use for input; -1 if none. */ | ||
| 292 | static int max_input_desc; | ||
| 293 | 268 | ||
| 294 | /* Set the external socket descriptor for Emacs to use when | 269 | /* Set the external socket descriptor for Emacs to use when |
| 295 | `make-network-process' is called with a non-nil | 270 | `make-network-process' is called with a non-nil |
| @@ -384,6 +359,11 @@ pset_mark (struct Lisp_Process *p, Lisp_Object val) | |||
| 384 | p->mark = val; | 359 | p->mark = val; |
| 385 | } | 360 | } |
| 386 | static void | 361 | static void |
| 362 | pset_thread (struct Lisp_Process *p, Lisp_Object val) | ||
| 363 | { | ||
| 364 | p->thread = val; | ||
| 365 | } | ||
| 366 | static void | ||
| 387 | pset_name (struct Lisp_Process *p, Lisp_Object val) | 367 | pset_name (struct Lisp_Process *p, Lisp_Object val) |
| 388 | { | 368 | { |
| 389 | p->name = val; | 369 | p->name = val; |
| @@ -426,13 +406,34 @@ make_lisp_proc (struct Lisp_Process *p) | |||
| 426 | return make_lisp_ptr (p, Lisp_Vectorlike); | 406 | return make_lisp_ptr (p, Lisp_Vectorlike); |
| 427 | } | 407 | } |
| 428 | 408 | ||
| 409 | enum fd_bits | ||
| 410 | { | ||
| 411 | /* Read from file descriptor. */ | ||
| 412 | FOR_READ = 1, | ||
| 413 | /* Write to file descriptor. */ | ||
| 414 | FOR_WRITE = 2, | ||
| 415 | /* This descriptor refers to a keyboard. Only valid if FOR_READ is | ||
| 416 | set. */ | ||
| 417 | KEYBOARD_FD = 4, | ||
| 418 | /* This descriptor refers to a process. */ | ||
| 419 | PROCESS_FD = 8, | ||
| 420 | /* A non-blocking connect. Only valid if FOR_WRITE is set. */ | ||
| 421 | NON_BLOCKING_CONNECT_FD = 16 | ||
| 422 | }; | ||
| 423 | |||
| 429 | static struct fd_callback_data | 424 | static struct fd_callback_data |
| 430 | { | 425 | { |
| 431 | fd_callback func; | 426 | fd_callback func; |
| 432 | void *data; | 427 | void *data; |
| 433 | #define FOR_READ 1 | 428 | /* Flags from enum fd_bits. */ |
| 434 | #define FOR_WRITE 2 | 429 | int flags; |
| 435 | int condition; /* Mask of the defines above. */ | 430 | /* If this fd is locked to a certain thread, this points to it. |
| 431 | Otherwise, this is NULL. If an fd is locked to a thread, then | ||
| 432 | only that thread is permitted to wait on it. */ | ||
| 433 | struct thread_state *thread; | ||
| 434 | /* If this fd is currently being selected on by a thread, this | ||
| 435 | points to the thread. Otherwise it is NULL. */ | ||
| 436 | struct thread_state *waiting_thread; | ||
| 436 | } fd_callback_info[FD_SETSIZE]; | 437 | } fd_callback_info[FD_SETSIZE]; |
| 437 | 438 | ||
| 438 | 439 | ||
| @@ -446,7 +447,25 @@ add_read_fd (int fd, fd_callback func, void *data) | |||
| 446 | 447 | ||
| 447 | fd_callback_info[fd].func = func; | 448 | fd_callback_info[fd].func = func; |
| 448 | fd_callback_info[fd].data = data; | 449 | fd_callback_info[fd].data = data; |
| 449 | fd_callback_info[fd].condition |= FOR_READ; | 450 | } |
| 451 | |||
| 452 | static void | ||
| 453 | add_non_keyboard_read_fd (int fd) | ||
| 454 | { | ||
| 455 | eassert (fd >= 0 && fd < FD_SETSIZE); | ||
| 456 | eassert (fd_callback_info[fd].func == NULL); | ||
| 457 | |||
| 458 | fd_callback_info[fd].flags &= ~KEYBOARD_FD; | ||
| 459 | fd_callback_info[fd].flags |= FOR_READ; | ||
| 460 | if (fd > max_desc) | ||
| 461 | max_desc = fd; | ||
| 462 | } | ||
| 463 | |||
| 464 | static void | ||
| 465 | add_process_read_fd (int fd) | ||
| 466 | { | ||
| 467 | add_non_keyboard_read_fd (fd); | ||
| 468 | fd_callback_info[fd].flags |= PROCESS_FD; | ||
| 450 | } | 469 | } |
| 451 | 470 | ||
| 452 | /* Stop monitoring file descriptor FD for when read is possible. */ | 471 | /* Stop monitoring file descriptor FD for when read is possible. */ |
| @@ -456,8 +475,7 @@ delete_read_fd (int fd) | |||
| 456 | { | 475 | { |
| 457 | delete_keyboard_wait_descriptor (fd); | 476 | delete_keyboard_wait_descriptor (fd); |
| 458 | 477 | ||
| 459 | fd_callback_info[fd].condition &= ~FOR_READ; | 478 | if (fd_callback_info[fd].flags == 0) |
| 460 | if (fd_callback_info[fd].condition == 0) | ||
| 461 | { | 479 | { |
| 462 | fd_callback_info[fd].func = 0; | 480 | fd_callback_info[fd].func = 0; |
| 463 | fd_callback_info[fd].data = 0; | 481 | fd_callback_info[fd].data = 0; |
| @@ -470,28 +488,39 @@ delete_read_fd (int fd) | |||
| 470 | void | 488 | void |
| 471 | add_write_fd (int fd, fd_callback func, void *data) | 489 | add_write_fd (int fd, fd_callback func, void *data) |
| 472 | { | 490 | { |
| 473 | FD_SET (fd, &write_mask); | 491 | eassert (fd >= 0 && fd < FD_SETSIZE); |
| 474 | if (fd > max_input_desc) | ||
| 475 | max_input_desc = fd; | ||
| 476 | 492 | ||
| 477 | fd_callback_info[fd].func = func; | 493 | fd_callback_info[fd].func = func; |
| 478 | fd_callback_info[fd].data = data; | 494 | fd_callback_info[fd].data = data; |
| 479 | fd_callback_info[fd].condition |= FOR_WRITE; | 495 | fd_callback_info[fd].flags |= FOR_WRITE; |
| 496 | if (fd > max_desc) | ||
| 497 | max_desc = fd; | ||
| 480 | } | 498 | } |
| 481 | 499 | ||
| 482 | /* FD is no longer an input descriptor; update max_input_desc accordingly. */ | 500 | static void |
| 501 | add_non_blocking_write_fd (int fd) | ||
| 502 | { | ||
| 503 | eassert (fd >= 0 && fd < FD_SETSIZE); | ||
| 504 | eassert (fd_callback_info[fd].func == NULL); | ||
| 505 | |||
| 506 | fd_callback_info[fd].flags |= FOR_WRITE | NON_BLOCKING_CONNECT_FD; | ||
| 507 | if (fd > max_desc) | ||
| 508 | max_desc = fd; | ||
| 509 | ++num_pending_connects; | ||
| 510 | } | ||
| 483 | 511 | ||
| 484 | static void | 512 | static void |
| 485 | delete_input_desc (int fd) | 513 | recompute_max_desc (void) |
| 486 | { | 514 | { |
| 487 | if (fd == max_input_desc) | 515 | int fd; |
| 488 | { | ||
| 489 | do | ||
| 490 | fd--; | ||
| 491 | while (0 <= fd && ! (FD_ISSET (fd, &input_wait_mask) | ||
| 492 | || FD_ISSET (fd, &write_mask))); | ||
| 493 | 516 | ||
| 494 | max_input_desc = fd; | 517 | for (fd = max_desc; fd >= 0; --fd) |
| 518 | { | ||
| 519 | if (fd_callback_info[fd].flags != 0) | ||
| 520 | { | ||
| 521 | max_desc = fd; | ||
| 522 | break; | ||
| 523 | } | ||
| 495 | } | 524 | } |
| 496 | } | 525 | } |
| 497 | 526 | ||
| @@ -500,13 +529,121 @@ delete_input_desc (int fd) | |||
| 500 | void | 529 | void |
| 501 | delete_write_fd (int fd) | 530 | delete_write_fd (int fd) |
| 502 | { | 531 | { |
| 503 | FD_CLR (fd, &write_mask); | 532 | if ((fd_callback_info[fd].flags & NON_BLOCKING_CONNECT_FD) != 0) |
| 504 | fd_callback_info[fd].condition &= ~FOR_WRITE; | 533 | { |
| 505 | if (fd_callback_info[fd].condition == 0) | 534 | if (--num_pending_connects < 0) |
| 535 | emacs_abort (); | ||
| 536 | } | ||
| 537 | fd_callback_info[fd].flags &= ~(FOR_WRITE | NON_BLOCKING_CONNECT_FD); | ||
| 538 | if (fd_callback_info[fd].flags == 0) | ||
| 506 | { | 539 | { |
| 507 | fd_callback_info[fd].func = 0; | 540 | fd_callback_info[fd].func = 0; |
| 508 | fd_callback_info[fd].data = 0; | 541 | fd_callback_info[fd].data = 0; |
| 509 | delete_input_desc (fd); | 542 | |
| 543 | if (fd == max_desc) | ||
| 544 | recompute_max_desc (); | ||
| 545 | } | ||
| 546 | } | ||
| 547 | |||
| 548 | static void | ||
| 549 | compute_input_wait_mask (fd_set *mask) | ||
| 550 | { | ||
| 551 | int fd; | ||
| 552 | |||
| 553 | FD_ZERO (mask); | ||
| 554 | for (fd = 0; fd <= max_desc; ++fd) | ||
| 555 | { | ||
| 556 | if (fd_callback_info[fd].thread != NULL | ||
| 557 | && fd_callback_info[fd].thread != current_thread) | ||
| 558 | continue; | ||
| 559 | if (fd_callback_info[fd].waiting_thread != NULL | ||
| 560 | && fd_callback_info[fd].waiting_thread != current_thread) | ||
| 561 | continue; | ||
| 562 | if ((fd_callback_info[fd].flags & FOR_READ) != 0) | ||
| 563 | { | ||
| 564 | FD_SET (fd, mask); | ||
| 565 | fd_callback_info[fd].waiting_thread = current_thread; | ||
| 566 | } | ||
| 567 | } | ||
| 568 | } | ||
| 569 | |||
| 570 | static void | ||
| 571 | compute_non_process_wait_mask (fd_set *mask) | ||
| 572 | { | ||
| 573 | int fd; | ||
| 574 | |||
| 575 | FD_ZERO (mask); | ||
| 576 | for (fd = 0; fd <= max_desc; ++fd) | ||
| 577 | { | ||
| 578 | if (fd_callback_info[fd].thread != NULL | ||
| 579 | && fd_callback_info[fd].thread != current_thread) | ||
| 580 | continue; | ||
| 581 | if (fd_callback_info[fd].waiting_thread != NULL | ||
| 582 | && fd_callback_info[fd].waiting_thread != current_thread) | ||
| 583 | continue; | ||
| 584 | if ((fd_callback_info[fd].flags & FOR_READ) != 0 | ||
| 585 | && (fd_callback_info[fd].flags & PROCESS_FD) == 0) | ||
| 586 | { | ||
| 587 | FD_SET (fd, mask); | ||
| 588 | fd_callback_info[fd].waiting_thread = current_thread; | ||
| 589 | } | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | static void | ||
| 594 | compute_non_keyboard_wait_mask (fd_set *mask) | ||
| 595 | { | ||
| 596 | int fd; | ||
| 597 | |||
| 598 | FD_ZERO (mask); | ||
| 599 | for (fd = 0; fd <= max_desc; ++fd) | ||
| 600 | { | ||
| 601 | if (fd_callback_info[fd].thread != NULL | ||
| 602 | && fd_callback_info[fd].thread != current_thread) | ||
| 603 | continue; | ||
| 604 | if (fd_callback_info[fd].waiting_thread != NULL | ||
| 605 | && fd_callback_info[fd].waiting_thread != current_thread) | ||
| 606 | continue; | ||
| 607 | if ((fd_callback_info[fd].flags & FOR_READ) != 0 | ||
| 608 | && (fd_callback_info[fd].flags & KEYBOARD_FD) == 0) | ||
| 609 | { | ||
| 610 | FD_SET (fd, mask); | ||
| 611 | fd_callback_info[fd].waiting_thread = current_thread; | ||
| 612 | } | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | static void | ||
| 617 | compute_write_mask (fd_set *mask) | ||
| 618 | { | ||
| 619 | int fd; | ||
| 620 | |||
| 621 | FD_ZERO (mask); | ||
| 622 | for (fd = 0; fd <= max_desc; ++fd) | ||
| 623 | { | ||
| 624 | if (fd_callback_info[fd].thread != NULL | ||
| 625 | && fd_callback_info[fd].thread != current_thread) | ||
| 626 | continue; | ||
| 627 | if (fd_callback_info[fd].waiting_thread != NULL | ||
| 628 | && fd_callback_info[fd].waiting_thread != current_thread) | ||
| 629 | continue; | ||
| 630 | if ((fd_callback_info[fd].flags & FOR_WRITE) != 0) | ||
| 631 | { | ||
| 632 | FD_SET (fd, mask); | ||
| 633 | fd_callback_info[fd].waiting_thread = current_thread; | ||
| 634 | } | ||
| 635 | } | ||
| 636 | } | ||
| 637 | |||
| 638 | static void | ||
| 639 | clear_waiting_thread_info (void) | ||
| 640 | { | ||
| 641 | int fd; | ||
| 642 | |||
| 643 | for (fd = 0; fd <= max_desc; ++fd) | ||
| 644 | { | ||
| 645 | if (fd_callback_info[fd].waiting_thread == current_thread) | ||
| 646 | fd_callback_info[fd].waiting_thread = NULL; | ||
| 510 | } | 647 | } |
| 511 | } | 648 | } |
| 512 | 649 | ||
| @@ -716,6 +853,7 @@ make_process (Lisp_Object name) | |||
| 716 | Lisp data to nil, so do it only for slots which should not be nil. */ | 853 | Lisp data to nil, so do it only for slots which should not be nil. */ |
| 717 | pset_status (p, Qrun); | 854 | pset_status (p, Qrun); |
| 718 | pset_mark (p, Fmake_marker ()); | 855 | pset_mark (p, Fmake_marker ()); |
| 856 | pset_thread (p, Fcurrent_thread ()); | ||
| 719 | 857 | ||
| 720 | /* Initialize non-Lisp data. Note that allocate_process zeroes out all | 858 | /* Initialize non-Lisp data. Note that allocate_process zeroes out all |
| 721 | non-Lisp data, so do it only for slots which should not be zero. */ | 859 | non-Lisp data, so do it only for slots which should not be zero. */ |
| @@ -764,6 +902,27 @@ remove_process (register Lisp_Object proc) | |||
| 764 | deactivate_process (proc); | 902 | deactivate_process (proc); |
| 765 | } | 903 | } |
| 766 | 904 | ||
| 905 | void | ||
| 906 | update_processes_for_thread_death (Lisp_Object dying_thread) | ||
| 907 | { | ||
| 908 | Lisp_Object pair; | ||
| 909 | |||
| 910 | for (pair = Vprocess_alist; !NILP (pair); pair = XCDR (pair)) | ||
| 911 | { | ||
| 912 | Lisp_Object process = XCDR (XCAR (pair)); | ||
| 913 | if (EQ (XPROCESS (process)->thread, dying_thread)) | ||
| 914 | { | ||
| 915 | struct Lisp_Process *proc = XPROCESS (process); | ||
| 916 | |||
| 917 | pset_thread (proc, Qnil); | ||
| 918 | if (proc->infd >= 0) | ||
| 919 | fd_callback_info[proc->infd].thread = NULL; | ||
| 920 | if (proc->outfd >= 0) | ||
| 921 | fd_callback_info[proc->outfd].thread = NULL; | ||
| 922 | } | ||
| 923 | } | ||
| 924 | } | ||
| 925 | |||
| 767 | #ifdef HAVE_GETADDRINFO_A | 926 | #ifdef HAVE_GETADDRINFO_A |
| 768 | static void | 927 | static void |
| 769 | free_dns_request (Lisp_Object proc) | 928 | free_dns_request (Lisp_Object proc) |
| @@ -1066,17 +1225,11 @@ static void | |||
| 1066 | set_process_filter_masks (struct Lisp_Process *p) | 1225 | set_process_filter_masks (struct Lisp_Process *p) |
| 1067 | { | 1226 | { |
| 1068 | if (EQ (p->filter, Qt) && !EQ (p->status, Qlisten)) | 1227 | if (EQ (p->filter, Qt) && !EQ (p->status, Qlisten)) |
| 1069 | { | 1228 | delete_read_fd (p->infd); |
| 1070 | FD_CLR (p->infd, &input_wait_mask); | ||
| 1071 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 1072 | } | ||
| 1073 | else if (EQ (p->filter, Qt) | 1229 | else if (EQ (p->filter, Qt) |
| 1074 | /* Network or serial process not stopped: */ | 1230 | /* Network or serial process not stopped: */ |
| 1075 | && !EQ (p->command, Qt)) | 1231 | && !EQ (p->command, Qt)) |
| 1076 | { | 1232 | add_process_read_fd (p->infd); |
| 1077 | FD_SET (p->infd, &input_wait_mask); | ||
| 1078 | FD_SET (p->infd, &non_keyboard_wait_mask); | ||
| 1079 | } | ||
| 1080 | } | 1233 | } |
| 1081 | 1234 | ||
| 1082 | DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, | 1235 | DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter, |
| @@ -1163,6 +1316,44 @@ See `set-process-sentinel' for more info on sentinels. */) | |||
| 1163 | return XPROCESS (process)->sentinel; | 1316 | return XPROCESS (process)->sentinel; |
| 1164 | } | 1317 | } |
| 1165 | 1318 | ||
| 1319 | DEFUN ("set-process-thread", Fset_process_thread, Sset_process_thread, | ||
| 1320 | 2, 2, 0, | ||
| 1321 | doc: /* Set the locking thread of PROCESS to be THREAD. | ||
| 1322 | If THREAD is nil, the process is unlocked. */) | ||
| 1323 | (Lisp_Object process, Lisp_Object thread) | ||
| 1324 | { | ||
| 1325 | struct Lisp_Process *proc; | ||
| 1326 | struct thread_state *tstate; | ||
| 1327 | |||
| 1328 | CHECK_PROCESS (process); | ||
| 1329 | if (NILP (thread)) | ||
| 1330 | tstate = NULL; | ||
| 1331 | else | ||
| 1332 | { | ||
| 1333 | CHECK_THREAD (thread); | ||
| 1334 | tstate = XTHREAD (thread); | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | proc = XPROCESS (process); | ||
| 1338 | pset_thread (proc, thread); | ||
| 1339 | if (proc->infd >= 0) | ||
| 1340 | fd_callback_info[proc->infd].thread = tstate; | ||
| 1341 | if (proc->outfd >= 0) | ||
| 1342 | fd_callback_info[proc->outfd].thread = tstate; | ||
| 1343 | |||
| 1344 | return thread; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | DEFUN ("process-thread", Fprocess_thread, Sprocess_thread, | ||
| 1348 | 1, 1, 0, | ||
| 1349 | doc: /* Ret the locking thread of PROCESS. | ||
| 1350 | If PROCESS is unlocked, this function returns nil. */) | ||
| 1351 | (Lisp_Object process) | ||
| 1352 | { | ||
| 1353 | CHECK_PROCESS (process); | ||
| 1354 | return XPROCESS (process)->thread; | ||
| 1355 | } | ||
| 1356 | |||
| 1166 | DEFUN ("set-process-window-size", Fset_process_window_size, | 1357 | DEFUN ("set-process-window-size", Fset_process_window_size, |
| 1167 | Sset_process_window_size, 3, 3, 0, | 1358 | Sset_process_window_size, 3, 3, 0, |
| 1168 | doc: /* Tell PROCESS that it has logical window size WIDTH by HEIGHT. | 1359 | doc: /* Tell PROCESS that it has logical window size WIDTH by HEIGHT. |
| @@ -1840,13 +2031,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1840 | pset_status (p, Qrun); | 2031 | pset_status (p, Qrun); |
| 1841 | 2032 | ||
| 1842 | if (!EQ (p->command, Qt)) | 2033 | if (!EQ (p->command, Qt)) |
| 1843 | { | 2034 | add_process_read_fd (inchannel); |
| 1844 | FD_SET (inchannel, &input_wait_mask); | ||
| 1845 | FD_SET (inchannel, &non_keyboard_wait_mask); | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | if (inchannel > max_process_desc) | ||
| 1849 | max_process_desc = inchannel; | ||
| 1850 | 2035 | ||
| 1851 | /* This may signal an error. */ | 2036 | /* This may signal an error. */ |
| 1852 | setup_process_coding_systems (process); | 2037 | setup_process_coding_systems (process); |
| @@ -2079,10 +2264,7 @@ create_pty (Lisp_Object process) | |||
| 2079 | pset_status (p, Qrun); | 2264 | pset_status (p, Qrun); |
| 2080 | setup_process_coding_systems (process); | 2265 | setup_process_coding_systems (process); |
| 2081 | 2266 | ||
| 2082 | FD_SET (pty_fd, &input_wait_mask); | 2267 | add_process_read_fd (pty_fd); |
| 2083 | FD_SET (pty_fd, &non_keyboard_wait_mask); | ||
| 2084 | if (pty_fd > max_process_desc) | ||
| 2085 | max_process_desc = pty_fd; | ||
| 2086 | 2268 | ||
| 2087 | pset_tty_name (p, build_string (pty_name)); | 2269 | pset_tty_name (p, build_string (pty_name)); |
| 2088 | } | 2270 | } |
| @@ -2166,8 +2348,8 @@ usage: (make-pipe-process &rest ARGS) */) | |||
| 2166 | p->infd = inchannel; | 2348 | p->infd = inchannel; |
| 2167 | p->outfd = outchannel; | 2349 | p->outfd = outchannel; |
| 2168 | 2350 | ||
| 2169 | if (inchannel > max_process_desc) | 2351 | if (inchannel > max_desc) |
| 2170 | max_process_desc = inchannel; | 2352 | max_desc = inchannel; |
| 2171 | 2353 | ||
| 2172 | buffer = Fplist_get (contact, QCbuffer); | 2354 | buffer = Fplist_get (contact, QCbuffer); |
| 2173 | if (NILP (buffer)) | 2355 | if (NILP (buffer)) |
| @@ -2188,10 +2370,7 @@ usage: (make-pipe-process &rest ARGS) */) | |||
| 2188 | eassert (! p->pty_flag); | 2370 | eassert (! p->pty_flag); |
| 2189 | 2371 | ||
| 2190 | if (!EQ (p->command, Qt)) | 2372 | if (!EQ (p->command, Qt)) |
| 2191 | { | 2373 | add_process_read_fd (inchannel); |
| 2192 | FD_SET (inchannel, &input_wait_mask); | ||
| 2193 | FD_SET (inchannel, &non_keyboard_wait_mask); | ||
| 2194 | } | ||
| 2195 | p->adaptive_read_buffering | 2374 | p->adaptive_read_buffering |
| 2196 | = (NILP (Vprocess_adaptive_read_buffering) ? 0 | 2375 | = (NILP (Vprocess_adaptive_read_buffering) ? 0 |
| 2197 | : EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2); | 2376 | : EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2); |
| @@ -2904,8 +3083,8 @@ usage: (make-serial-process &rest ARGS) */) | |||
| 2904 | p->open_fd[SUBPROCESS_STDIN] = fd; | 3083 | p->open_fd[SUBPROCESS_STDIN] = fd; |
| 2905 | p->infd = fd; | 3084 | p->infd = fd; |
| 2906 | p->outfd = fd; | 3085 | p->outfd = fd; |
| 2907 | if (fd > max_process_desc) | 3086 | if (fd > max_desc) |
| 2908 | max_process_desc = fd; | 3087 | max_desc = fd; |
| 2909 | chan_process[fd] = proc; | 3088 | chan_process[fd] = proc; |
| 2910 | 3089 | ||
| 2911 | buffer = Fplist_get (contact, QCbuffer); | 3090 | buffer = Fplist_get (contact, QCbuffer); |
| @@ -2927,10 +3106,7 @@ usage: (make-serial-process &rest ARGS) */) | |||
| 2927 | eassert (! p->pty_flag); | 3106 | eassert (! p->pty_flag); |
| 2928 | 3107 | ||
| 2929 | if (!EQ (p->command, Qt)) | 3108 | if (!EQ (p->command, Qt)) |
| 2930 | { | 3109 | add_process_read_fd (fd); |
| 2931 | FD_SET (fd, &input_wait_mask); | ||
| 2932 | FD_SET (fd, &non_keyboard_wait_mask); | ||
| 2933 | } | ||
| 2934 | 3110 | ||
| 2935 | if (BUFFERP (buffer)) | 3111 | if (BUFFERP (buffer)) |
| 2936 | { | 3112 | { |
| @@ -3102,7 +3278,7 @@ finish_after_tls_connection (Lisp_Object proc) | |||
| 3102 | pset_status (p, Qfailed); | 3278 | pset_status (p, Qfailed); |
| 3103 | deactivate_process (proc); | 3279 | deactivate_process (proc); |
| 3104 | } | 3280 | } |
| 3105 | else if (! FD_ISSET (p->outfd, &connect_wait_mask)) | 3281 | else if ((fd_callback_info[p->outfd].flags & NON_BLOCKING_CONNECT_FD) == 0) |
| 3106 | { | 3282 | { |
| 3107 | /* If we cleared the connection wait mask before we did the TLS | 3283 | /* If we cleared the connection wait mask before we did the TLS |
| 3108 | setup, then we have to say that the process is finally "open" | 3284 | setup, then we have to say that the process is finally "open" |
| @@ -3412,25 +3588,18 @@ connect_network_socket (Lisp_Object proc, Lisp_Object addrinfos, | |||
| 3412 | if (! (connecting_status (p->status) | 3588 | if (! (connecting_status (p->status) |
| 3413 | && EQ (XCDR (p->status), addrinfos))) | 3589 | && EQ (XCDR (p->status), addrinfos))) |
| 3414 | pset_status (p, Fcons (Qconnect, addrinfos)); | 3590 | pset_status (p, Fcons (Qconnect, addrinfos)); |
| 3415 | if (!FD_ISSET (inch, &connect_wait_mask)) | 3591 | if ((fd_callback_info[inch].flags & NON_BLOCKING_CONNECT_FD) == 0) |
| 3416 | { | 3592 | add_non_blocking_write_fd (inch); |
| 3417 | FD_SET (inch, &connect_wait_mask); | ||
| 3418 | FD_SET (inch, &write_mask); | ||
| 3419 | num_pending_connects++; | ||
| 3420 | } | ||
| 3421 | } | 3593 | } |
| 3422 | else | 3594 | else |
| 3423 | /* A server may have a client filter setting of Qt, but it must | 3595 | /* A server may have a client filter setting of Qt, but it must |
| 3424 | still listen for incoming connects unless it is stopped. */ | 3596 | still listen for incoming connects unless it is stopped. */ |
| 3425 | if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt)) | 3597 | if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt)) |
| 3426 | || (EQ (p->status, Qlisten) && NILP (p->command))) | 3598 | || (EQ (p->status, Qlisten) && NILP (p->command))) |
| 3427 | { | 3599 | add_process_read_fd (inch); |
| 3428 | FD_SET (inch, &input_wait_mask); | ||
| 3429 | FD_SET (inch, &non_keyboard_wait_mask); | ||
| 3430 | } | ||
| 3431 | 3600 | ||
| 3432 | if (inch > max_process_desc) | 3601 | if (inch > max_desc) |
| 3433 | max_process_desc = inch; | 3602 | max_desc = inch; |
| 3434 | 3603 | ||
| 3435 | /* Set up the masks based on the process filter. */ | 3604 | /* Set up the masks based on the process filter. */ |
| 3436 | set_process_filter_masks (p); | 3605 | set_process_filter_masks (p); |
| @@ -4361,26 +4530,11 @@ deactivate_process (Lisp_Object proc) | |||
| 4361 | } | 4530 | } |
| 4362 | #endif | 4531 | #endif |
| 4363 | chan_process[inchannel] = Qnil; | 4532 | chan_process[inchannel] = Qnil; |
| 4364 | FD_CLR (inchannel, &input_wait_mask); | 4533 | delete_read_fd (inchannel); |
| 4365 | FD_CLR (inchannel, &non_keyboard_wait_mask); | 4534 | if ((fd_callback_info[inchannel].flags & NON_BLOCKING_CONNECT_FD) != 0) |
| 4366 | if (FD_ISSET (inchannel, &connect_wait_mask)) | 4535 | delete_write_fd (inchannel); |
| 4367 | { | 4536 | if (inchannel == max_desc) |
| 4368 | FD_CLR (inchannel, &connect_wait_mask); | 4537 | recompute_max_desc (); |
| 4369 | FD_CLR (inchannel, &write_mask); | ||
| 4370 | if (--num_pending_connects < 0) | ||
| 4371 | emacs_abort (); | ||
| 4372 | } | ||
| 4373 | if (inchannel == max_process_desc) | ||
| 4374 | { | ||
| 4375 | /* We just closed the highest-numbered process input descriptor, | ||
| 4376 | so recompute the highest-numbered one now. */ | ||
| 4377 | int i = inchannel; | ||
| 4378 | do | ||
| 4379 | i--; | ||
| 4380 | while (0 <= i && NILP (chan_process[i])); | ||
| 4381 | |||
| 4382 | max_process_desc = i; | ||
| 4383 | } | ||
| 4384 | } | 4538 | } |
| 4385 | } | 4539 | } |
| 4386 | 4540 | ||
| @@ -4409,7 +4563,18 @@ is nil, from any process) before the timeout expired. */) | |||
| 4409 | int nsecs; | 4563 | int nsecs; |
| 4410 | 4564 | ||
| 4411 | if (! NILP (process)) | 4565 | if (! NILP (process)) |
| 4412 | CHECK_PROCESS (process); | 4566 | { |
| 4567 | struct Lisp_Process *procp; | ||
| 4568 | |||
| 4569 | CHECK_PROCESS (process); | ||
| 4570 | procp = XPROCESS (process); | ||
| 4571 | |||
| 4572 | /* Can't wait for a process that is dedicated to a different | ||
| 4573 | thread. */ | ||
| 4574 | if (!EQ (procp->thread, Qnil) && !EQ (procp->thread, Fcurrent_thread ())) | ||
| 4575 | error ("Attempt to accept output from process %s locked to thread %s", | ||
| 4576 | SDATA (procp->name), SDATA (XTHREAD (procp->thread)->name)); | ||
| 4577 | } | ||
| 4413 | else | 4578 | else |
| 4414 | just_this_one = Qnil; | 4579 | just_this_one = Qnil; |
| 4415 | 4580 | ||
| @@ -4627,13 +4792,9 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 4627 | 4792 | ||
| 4628 | /* Client processes for accepted connections are not stopped initially. */ | 4793 | /* Client processes for accepted connections are not stopped initially. */ |
| 4629 | if (!EQ (p->filter, Qt)) | 4794 | if (!EQ (p->filter, Qt)) |
| 4630 | { | 4795 | add_process_read_fd (s); |
| 4631 | FD_SET (s, &input_wait_mask); | 4796 | if (s > max_desc) |
| 4632 | FD_SET (s, &non_keyboard_wait_mask); | 4797 | max_desc = s; |
| 4633 | } | ||
| 4634 | |||
| 4635 | if (s > max_process_desc) | ||
| 4636 | max_process_desc = s; | ||
| 4637 | 4798 | ||
| 4638 | /* Setup coding system for new process based on server process. | 4799 | /* Setup coding system for new process based on server process. |
| 4639 | This seems to be the proper thing to do, as the coding system | 4800 | This seems to be the proper thing to do, as the coding system |
| @@ -4746,20 +4907,10 @@ wait_for_tls_negotiation (Lisp_Object process) | |||
| 4746 | #endif | 4907 | #endif |
| 4747 | } | 4908 | } |
| 4748 | 4909 | ||
| 4749 | /* This variable is different from waiting_for_input in keyboard.c. | ||
| 4750 | It is used to communicate to a lisp process-filter/sentinel (via the | ||
| 4751 | function Fwaiting_for_user_input_p below) whether Emacs was waiting | ||
| 4752 | for user-input when that process-filter was called. | ||
| 4753 | waiting_for_input cannot be used as that is by definition 0 when | ||
| 4754 | lisp code is being evalled. | ||
| 4755 | This is also used in record_asynch_buffer_change. | ||
| 4756 | For that purpose, this must be 0 | ||
| 4757 | when not inside wait_reading_process_output. */ | ||
| 4758 | static int waiting_for_user_input_p; | ||
| 4759 | |||
| 4760 | static void | 4910 | static void |
| 4761 | wait_reading_process_output_unwind (int data) | 4911 | wait_reading_process_output_unwind (int data) |
| 4762 | { | 4912 | { |
| 4913 | clear_waiting_thread_info (); | ||
| 4763 | waiting_for_user_input_p = data; | 4914 | waiting_for_user_input_p = data; |
| 4764 | } | 4915 | } |
| 4765 | 4916 | ||
| @@ -4832,6 +4983,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 4832 | /* Close to the current time if known, an invalid timespec otherwise. */ | 4983 | /* Close to the current time if known, an invalid timespec otherwise. */ |
| 4833 | struct timespec now = invalid_timespec (); | 4984 | struct timespec now = invalid_timespec (); |
| 4834 | 4985 | ||
| 4986 | eassert (wait_proc == NULL | ||
| 4987 | || EQ (wait_proc->thread, Qnil) | ||
| 4988 | || XTHREAD (wait_proc->thread) == current_thread); | ||
| 4989 | |||
| 4835 | FD_ZERO (&Available); | 4990 | FD_ZERO (&Available); |
| 4836 | FD_ZERO (&Writeok); | 4991 | FD_ZERO (&Writeok); |
| 4837 | 4992 | ||
| @@ -5004,14 +5159,14 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5004 | if (kbd_on_hold_p ()) | 5159 | if (kbd_on_hold_p ()) |
| 5005 | FD_ZERO (&Atemp); | 5160 | FD_ZERO (&Atemp); |
| 5006 | else | 5161 | else |
| 5007 | Atemp = input_wait_mask; | 5162 | compute_input_wait_mask (&Atemp); |
| 5008 | Ctemp = write_mask; | 5163 | compute_write_mask (&Ctemp); |
| 5009 | 5164 | ||
| 5010 | timeout = make_timespec (0, 0); | 5165 | timeout = make_timespec (0, 0); |
| 5011 | if ((pselect (max (max_process_desc, max_input_desc) + 1, | 5166 | if ((thread_select (pselect, max_desc + 1, |
| 5012 | &Atemp, | 5167 | &Atemp, |
| 5013 | (num_pending_connects > 0 ? &Ctemp : NULL), | 5168 | (num_pending_connects > 0 ? &Ctemp : NULL), |
| 5014 | NULL, &timeout, NULL) | 5169 | NULL, &timeout, NULL) |
| 5015 | <= 0)) | 5170 | <= 0)) |
| 5016 | { | 5171 | { |
| 5017 | /* It's okay for us to do this and then continue with | 5172 | /* It's okay for us to do this and then continue with |
| @@ -5076,17 +5231,17 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5076 | } | 5231 | } |
| 5077 | else if (!NILP (wait_for_cell)) | 5232 | else if (!NILP (wait_for_cell)) |
| 5078 | { | 5233 | { |
| 5079 | Available = non_process_wait_mask; | 5234 | compute_non_process_wait_mask (&Available); |
| 5080 | check_delay = 0; | 5235 | check_delay = 0; |
| 5081 | check_write = 0; | 5236 | check_write = 0; |
| 5082 | } | 5237 | } |
| 5083 | else | 5238 | else |
| 5084 | { | 5239 | { |
| 5085 | if (! read_kbd) | 5240 | if (! read_kbd) |
| 5086 | Available = non_keyboard_wait_mask; | 5241 | compute_non_keyboard_wait_mask (&Available); |
| 5087 | else | 5242 | else |
| 5088 | Available = input_wait_mask; | 5243 | compute_input_wait_mask (&Available); |
| 5089 | Writeok = write_mask; | 5244 | compute_write_mask (&Writeok); |
| 5090 | check_delay = wait_proc ? 0 : process_output_delay_count; | 5245 | check_delay = wait_proc ? 0 : process_output_delay_count; |
| 5091 | check_write = true; | 5246 | check_write = true; |
| 5092 | } | 5247 | } |
| @@ -5128,7 +5283,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5128 | int adaptive_nsecs = timeout.tv_nsec; | 5283 | int adaptive_nsecs = timeout.tv_nsec; |
| 5129 | if (timeout.tv_sec > 0 || adaptive_nsecs > READ_OUTPUT_DELAY_MAX) | 5284 | if (timeout.tv_sec > 0 || adaptive_nsecs > READ_OUTPUT_DELAY_MAX) |
| 5130 | adaptive_nsecs = READ_OUTPUT_DELAY_MAX; | 5285 | adaptive_nsecs = READ_OUTPUT_DELAY_MAX; |
| 5131 | for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++) | 5286 | for (channel = 0; check_delay > 0 && channel <= max_desc; channel++) |
| 5132 | { | 5287 | { |
| 5133 | proc = chan_process[channel]; | 5288 | proc = chan_process[channel]; |
| 5134 | if (NILP (proc)) | 5289 | if (NILP (proc)) |
| @@ -5187,17 +5342,18 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5187 | } | 5342 | } |
| 5188 | #endif | 5343 | #endif |
| 5189 | 5344 | ||
| 5345 | nfds = thread_select ( | ||
| 5190 | #if defined (HAVE_NS) | 5346 | #if defined (HAVE_NS) |
| 5191 | nfds = ns_select | 5347 | ns_select |
| 5192 | #elif defined (HAVE_GLIB) | 5348 | #elif defined (HAVE_GLIB) |
| 5193 | nfds = xg_select | 5349 | xg_select |
| 5194 | #else | 5350 | #else |
| 5195 | nfds = pselect | 5351 | pselect |
| 5196 | #endif | 5352 | #endif |
| 5197 | (max (max_process_desc, max_input_desc) + 1, | 5353 | , max_desc + 1, |
| 5198 | &Available, | 5354 | &Available, |
| 5199 | (check_write ? &Writeok : 0), | 5355 | (check_write ? &Writeok : 0), |
| 5200 | NULL, &timeout, NULL); | 5356 | NULL, &timeout, NULL); |
| 5201 | 5357 | ||
| 5202 | #ifdef HAVE_GNUTLS | 5358 | #ifdef HAVE_GNUTLS |
| 5203 | /* GnuTLS buffers data internally. In lowat mode it leaves | 5359 | /* GnuTLS buffers data internally. In lowat mode it leaves |
| @@ -5381,22 +5537,22 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5381 | if (no_avail || nfds == 0) | 5537 | if (no_avail || nfds == 0) |
| 5382 | continue; | 5538 | continue; |
| 5383 | 5539 | ||
| 5384 | for (channel = 0; channel <= max_input_desc; ++channel) | 5540 | for (channel = 0; channel <= max_desc; ++channel) |
| 5385 | { | 5541 | { |
| 5386 | struct fd_callback_data *d = &fd_callback_info[channel]; | 5542 | struct fd_callback_data *d = &fd_callback_info[channel]; |
| 5387 | if (d->func | 5543 | if (d->func |
| 5388 | && ((d->condition & FOR_READ | 5544 | && ((d->flags & FOR_READ |
| 5389 | && FD_ISSET (channel, &Available)) | 5545 | && FD_ISSET (channel, &Available)) |
| 5390 | || (d->condition & FOR_WRITE | 5546 | || ((d->flags & FOR_WRITE) |
| 5391 | && FD_ISSET (channel, &write_mask)))) | 5547 | && FD_ISSET (channel, &Writeok)))) |
| 5392 | d->func (channel, d->data); | 5548 | d->func (channel, d->data); |
| 5393 | } | 5549 | } |
| 5394 | 5550 | ||
| 5395 | for (channel = 0; channel <= max_process_desc; channel++) | 5551 | for (channel = 0; channel <= max_desc; channel++) |
| 5396 | { | 5552 | { |
| 5397 | if (FD_ISSET (channel, &Available) | 5553 | if (FD_ISSET (channel, &Available) |
| 5398 | && FD_ISSET (channel, &non_keyboard_wait_mask) | 5554 | && ((fd_callback_info[channel].flags & (KEYBOARD_FD | PROCESS_FD)) |
| 5399 | && !FD_ISSET (channel, &non_process_wait_mask)) | 5555 | == PROCESS_FD)) |
| 5400 | { | 5556 | { |
| 5401 | int nread; | 5557 | int nread; |
| 5402 | 5558 | ||
| @@ -5461,8 +5617,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5461 | 5617 | ||
| 5462 | /* Clear the descriptor now, so we only raise the | 5618 | /* Clear the descriptor now, so we only raise the |
| 5463 | signal once. */ | 5619 | signal once. */ |
| 5464 | FD_CLR (channel, &input_wait_mask); | 5620 | delete_read_fd (channel); |
| 5465 | FD_CLR (channel, &non_keyboard_wait_mask); | ||
| 5466 | 5621 | ||
| 5467 | if (p->pid == -2) | 5622 | if (p->pid == -2) |
| 5468 | { | 5623 | { |
| @@ -5501,14 +5656,12 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5501 | } | 5656 | } |
| 5502 | } | 5657 | } |
| 5503 | if (FD_ISSET (channel, &Writeok) | 5658 | if (FD_ISSET (channel, &Writeok) |
| 5504 | && FD_ISSET (channel, &connect_wait_mask)) | 5659 | && (fd_callback_info[channel].flags |
| 5660 | & NON_BLOCKING_CONNECT_FD) != 0) | ||
| 5505 | { | 5661 | { |
| 5506 | struct Lisp_Process *p; | 5662 | struct Lisp_Process *p; |
| 5507 | 5663 | ||
| 5508 | FD_CLR (channel, &connect_wait_mask); | 5664 | delete_write_fd (channel); |
| 5509 | FD_CLR (channel, &write_mask); | ||
| 5510 | if (--num_pending_connects < 0) | ||
| 5511 | emacs_abort (); | ||
| 5512 | 5665 | ||
| 5513 | proc = chan_process[channel]; | 5666 | proc = chan_process[channel]; |
| 5514 | if (NILP (proc)) | 5667 | if (NILP (proc)) |
| @@ -5576,10 +5729,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 5576 | 5729 | ||
| 5577 | if (0 <= p->infd && !EQ (p->filter, Qt) | 5730 | if (0 <= p->infd && !EQ (p->filter, Qt) |
| 5578 | && !EQ (p->command, Qt)) | 5731 | && !EQ (p->command, Qt)) |
| 5579 | { | 5732 | add_process_read_fd (p->infd); |
| 5580 | FD_SET (p->infd, &input_wait_mask); | ||
| 5581 | FD_SET (p->infd, &non_keyboard_wait_mask); | ||
| 5582 | } | ||
| 5583 | } | 5733 | } |
| 5584 | } | 5734 | } |
| 5585 | } /* End for each file descriptor. */ | 5735 | } /* End for each file descriptor. */ |
| @@ -6550,10 +6700,7 @@ of incoming traffic. */) | |||
| 6550 | p = XPROCESS (process); | 6700 | p = XPROCESS (process); |
| 6551 | if (NILP (p->command) | 6701 | if (NILP (p->command) |
| 6552 | && p->infd >= 0) | 6702 | && p->infd >= 0) |
| 6553 | { | 6703 | delete_read_fd (p->infd); |
| 6554 | FD_CLR (p->infd, &input_wait_mask); | ||
| 6555 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 6556 | } | ||
| 6557 | pset_command (p, Qt); | 6704 | pset_command (p, Qt); |
| 6558 | return process; | 6705 | return process; |
| 6559 | } | 6706 | } |
| @@ -6582,8 +6729,7 @@ traffic. */) | |||
| 6582 | && p->infd >= 0 | 6729 | && p->infd >= 0 |
| 6583 | && (!EQ (p->filter, Qt) || EQ (p->status, Qlisten))) | 6730 | && (!EQ (p->filter, Qt) || EQ (p->status, Qlisten))) |
| 6584 | { | 6731 | { |
| 6585 | FD_SET (p->infd, &input_wait_mask); | 6732 | add_process_read_fd (p->infd); |
| 6586 | FD_SET (p->infd, &non_keyboard_wait_mask); | ||
| 6587 | #ifdef WINDOWSNT | 6733 | #ifdef WINDOWSNT |
| 6588 | if (fd_info[ p->infd ].flags & FILE_SERIAL) | 6734 | if (fd_info[ p->infd ].flags & FILE_SERIAL) |
| 6589 | PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR); | 6735 | PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR); |
| @@ -6890,10 +7036,7 @@ handle_child_signal (int sig) | |||
| 6890 | 7036 | ||
| 6891 | /* clear_desc_flag avoids a compiler bug in Microsoft C. */ | 7037 | /* clear_desc_flag avoids a compiler bug in Microsoft C. */ |
| 6892 | if (clear_desc_flag) | 7038 | if (clear_desc_flag) |
| 6893 | { | 7039 | delete_read_fd (p->infd); |
| 6894 | FD_CLR (p->infd, &input_wait_mask); | ||
| 6895 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 6896 | } | ||
| 6897 | } | 7040 | } |
| 6898 | } | 7041 | } |
| 6899 | } | 7042 | } |
| @@ -7253,9 +7396,10 @@ keyboard_bit_set (fd_set *mask) | |||
| 7253 | { | 7396 | { |
| 7254 | int fd; | 7397 | int fd; |
| 7255 | 7398 | ||
| 7256 | for (fd = 0; fd <= max_input_desc; fd++) | 7399 | for (fd = 0; fd <= max_desc; fd++) |
| 7257 | if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask) | 7400 | if (FD_ISSET (fd, mask) |
| 7258 | && !FD_ISSET (fd, &non_keyboard_wait_mask)) | 7401 | && ((fd_callback_info[fd].flags & (FOR_READ | KEYBOARD_FD)) |
| 7402 | == (FOR_READ | KEYBOARD_FD))) | ||
| 7259 | return 1; | 7403 | return 1; |
| 7260 | 7404 | ||
| 7261 | return 0; | 7405 | return 0; |
| @@ -7492,14 +7636,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 7492 | void | 7636 | void |
| 7493 | add_timer_wait_descriptor (int fd) | 7637 | add_timer_wait_descriptor (int fd) |
| 7494 | { | 7638 | { |
| 7495 | FD_SET (fd, &input_wait_mask); | 7639 | add_read_fd (fd, timerfd_callback, NULL); |
| 7496 | FD_SET (fd, &non_keyboard_wait_mask); | 7640 | fd_callback_info[fd].flags &= ~KEYBOARD_FD; |
| 7497 | FD_SET (fd, &non_process_wait_mask); | ||
| 7498 | fd_callback_info[fd].func = timerfd_callback; | ||
| 7499 | fd_callback_info[fd].data = NULL; | ||
| 7500 | fd_callback_info[fd].condition |= FOR_READ; | ||
| 7501 | if (fd > max_input_desc) | ||
| 7502 | max_input_desc = fd; | ||
| 7503 | } | 7641 | } |
| 7504 | 7642 | ||
| 7505 | #endif /* HAVE_TIMERFD */ | 7643 | #endif /* HAVE_TIMERFD */ |
| @@ -7523,10 +7661,11 @@ void | |||
| 7523 | add_keyboard_wait_descriptor (int desc) | 7661 | add_keyboard_wait_descriptor (int desc) |
| 7524 | { | 7662 | { |
| 7525 | #ifdef subprocesses /* Actually means "not MSDOS". */ | 7663 | #ifdef subprocesses /* Actually means "not MSDOS". */ |
| 7526 | FD_SET (desc, &input_wait_mask); | 7664 | eassert (desc >= 0 && desc < FD_SETSIZE); |
| 7527 | FD_SET (desc, &non_process_wait_mask); | 7665 | fd_callback_info[desc].flags &= ~PROCESS_FD; |
| 7528 | if (desc > max_input_desc) | 7666 | fd_callback_info[desc].flags |= (FOR_READ | KEYBOARD_FD); |
| 7529 | max_input_desc = desc; | 7667 | if (desc > max_desc) |
| 7668 | max_desc = desc; | ||
| 7530 | #endif | 7669 | #endif |
| 7531 | } | 7670 | } |
| 7532 | 7671 | ||
| @@ -7536,9 +7675,12 @@ void | |||
| 7536 | delete_keyboard_wait_descriptor (int desc) | 7675 | delete_keyboard_wait_descriptor (int desc) |
| 7537 | { | 7676 | { |
| 7538 | #ifdef subprocesses | 7677 | #ifdef subprocesses |
| 7539 | FD_CLR (desc, &input_wait_mask); | 7678 | eassert (desc >= 0 && desc < FD_SETSIZE); |
| 7540 | FD_CLR (desc, &non_process_wait_mask); | 7679 | |
| 7541 | delete_input_desc (desc); | 7680 | fd_callback_info[desc].flags &= ~(FOR_READ | KEYBOARD_FD | PROCESS_FD); |
| 7681 | |||
| 7682 | if (desc == max_desc) | ||
| 7683 | recompute_max_desc (); | ||
| 7542 | #endif | 7684 | #endif |
| 7543 | } | 7685 | } |
| 7544 | 7686 | ||
| @@ -7819,15 +7961,10 @@ init_process_emacs (int sockfd) | |||
| 7819 | } | 7961 | } |
| 7820 | #endif | 7962 | #endif |
| 7821 | 7963 | ||
| 7822 | FD_ZERO (&input_wait_mask); | ||
| 7823 | FD_ZERO (&non_keyboard_wait_mask); | ||
| 7824 | FD_ZERO (&non_process_wait_mask); | ||
| 7825 | FD_ZERO (&write_mask); | ||
| 7826 | max_process_desc = max_input_desc = -1; | ||
| 7827 | external_sock_fd = sockfd; | 7964 | external_sock_fd = sockfd; |
| 7965 | max_desc = -1; | ||
| 7828 | memset (fd_callback_info, 0, sizeof (fd_callback_info)); | 7966 | memset (fd_callback_info, 0, sizeof (fd_callback_info)); |
| 7829 | 7967 | ||
| 7830 | FD_ZERO (&connect_wait_mask); | ||
| 7831 | num_pending_connects = 0; | 7968 | num_pending_connects = 0; |
| 7832 | 7969 | ||
| 7833 | process_output_delay_count = 0; | 7970 | process_output_delay_count = 0; |
| @@ -8027,6 +8164,8 @@ The variable takes effect when `start-process' is called. */); | |||
| 8027 | defsubr (&Sprocess_filter); | 8164 | defsubr (&Sprocess_filter); |
| 8028 | defsubr (&Sset_process_sentinel); | 8165 | defsubr (&Sset_process_sentinel); |
| 8029 | defsubr (&Sprocess_sentinel); | 8166 | defsubr (&Sprocess_sentinel); |
| 8167 | defsubr (&Sset_process_thread); | ||
| 8168 | defsubr (&Sprocess_thread); | ||
| 8030 | defsubr (&Sset_process_window_size); | 8169 | defsubr (&Sset_process_window_size); |
| 8031 | defsubr (&Sset_process_inherit_coding_system_flag); | 8170 | defsubr (&Sset_process_inherit_coding_system_flag); |
| 8032 | defsubr (&Sset_process_query_on_exit_flag); | 8171 | defsubr (&Sset_process_query_on_exit_flag); |
diff --git a/src/process.h b/src/process.h index 24c628231a0..e497ebc539f 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -115,6 +115,9 @@ struct Lisp_Process | |||
| 115 | /* Pipe process attached to the standard error of this process. */ | 115 | /* Pipe process attached to the standard error of this process. */ |
| 116 | Lisp_Object stderrproc; | 116 | Lisp_Object stderrproc; |
| 117 | 117 | ||
| 118 | /* The thread a process is linked to, or nil for any thread. */ | ||
| 119 | Lisp_Object thread; | ||
| 120 | |||
| 118 | /* After this point, there are no Lisp_Objects any more. */ | 121 | /* After this point, there are no Lisp_Objects any more. */ |
| 119 | /* alloc.c assumes that `pid' is the first such non-Lisp slot. */ | 122 | /* alloc.c assumes that `pid' is the first such non-Lisp slot. */ |
| 120 | 123 | ||
| @@ -274,6 +277,8 @@ extern Lisp_Object network_interface_info (Lisp_Object); | |||
| 274 | 277 | ||
| 275 | extern Lisp_Object remove_slash_colon (Lisp_Object); | 278 | extern Lisp_Object remove_slash_colon (Lisp_Object); |
| 276 | 279 | ||
| 280 | extern void update_processes_for_thread_death (Lisp_Object); | ||
| 281 | |||
| 277 | INLINE_HEADER_END | 282 | INLINE_HEADER_END |
| 278 | 283 | ||
| 279 | #endif /* EMACS_PROCESS_H */ | 284 | #endif /* EMACS_PROCESS_H */ |
diff --git a/src/regex.c b/src/regex.c index afd0d180316..f1686cf700c 100644 --- a/src/regex.c +++ b/src/regex.c | |||
| @@ -4885,12 +4885,6 @@ re_match (struct re_pattern_buffer *bufp, const char *string, | |||
| 4885 | WEAK_ALIAS (__re_match, re_match) | 4885 | WEAK_ALIAS (__re_match, re_match) |
| 4886 | #endif /* not emacs */ | 4886 | #endif /* not emacs */ |
| 4887 | 4887 | ||
| 4888 | #ifdef emacs | ||
| 4889 | /* In Emacs, this is the string or buffer in which we are matching. | ||
| 4890 | See the declaration in regex.h for details. */ | ||
| 4891 | Lisp_Object re_match_object; | ||
| 4892 | #endif | ||
| 4893 | |||
| 4894 | /* re_match_2 matches the compiled pattern in BUFP against the | 4888 | /* re_match_2 matches the compiled pattern in BUFP against the |
| 4895 | the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 | 4889 | the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 |
| 4896 | and SIZE2, respectively). We start matching at POS, and stop | 4890 | and SIZE2, respectively). We start matching at POS, and stop |
diff --git a/src/regex.h b/src/regex.h index 4922440e472..2d720e68f22 100644 --- a/src/regex.h +++ b/src/regex.h | |||
| @@ -171,7 +171,7 @@ typedef unsigned long reg_syntax_t; | |||
| 171 | some interfaces). When a regexp is compiled, the syntax used is | 171 | some interfaces). When a regexp is compiled, the syntax used is |
| 172 | stored in the pattern buffer, so changing this does not affect | 172 | stored in the pattern buffer, so changing this does not affect |
| 173 | already-compiled regexps. */ | 173 | already-compiled regexps. */ |
| 174 | extern reg_syntax_t re_syntax_options; | 174 | /* extern reg_syntax_t re_syntax_options; */ |
| 175 | 175 | ||
| 176 | #ifdef emacs | 176 | #ifdef emacs |
| 177 | # include "lisp.h" | 177 | # include "lisp.h" |
| @@ -180,8 +180,10 @@ extern reg_syntax_t re_syntax_options; | |||
| 180 | 180 | ||
| 181 | If the value is a Lisp string object, we are matching text in that | 181 | If the value is a Lisp string object, we are matching text in that |
| 182 | string; if it's nil, we are matching text in the current buffer; if | 182 | string; if it's nil, we are matching text in the current buffer; if |
| 183 | it's t, we are matching text in a C string. */ | 183 | it's t, we are matching text in a C string. |
| 184 | extern Lisp_Object re_match_object; | 184 | |
| 185 | This is defined as a macro in thread.h, which see. */ | ||
| 186 | /* extern Lisp_Object re_match_object; */ | ||
| 185 | #endif | 187 | #endif |
| 186 | 188 | ||
| 187 | /* Roughly the maximum number of failure points on the stack. */ | 189 | /* Roughly the maximum number of failure points on the stack. */ |
diff --git a/src/search.c b/src/search.c index e597c33a0fb..9d2c8cb04fd 100644 --- a/src/search.c +++ b/src/search.c | |||
| @@ -40,7 +40,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 40 | struct regexp_cache | 40 | struct regexp_cache |
| 41 | { | 41 | { |
| 42 | struct regexp_cache *next; | 42 | struct regexp_cache *next; |
| 43 | Lisp_Object regexp, whitespace_regexp; | 43 | Lisp_Object regexp, f_whitespace_regexp; |
| 44 | /* Syntax table for which the regexp applies. We need this because | 44 | /* Syntax table for which the regexp applies. We need this because |
| 45 | of character classes. If this is t, then the compiled pattern is valid | 45 | of character classes. If this is t, then the compiled pattern is valid |
| 46 | for any syntax-table. */ | 46 | for any syntax-table. */ |
| @@ -75,12 +75,12 @@ static struct regexp_cache *searchbuf_head; | |||
| 75 | to call re_set_registers after compiling a new pattern or after | 75 | to call re_set_registers after compiling a new pattern or after |
| 76 | setting the match registers, so that the regex functions will be | 76 | setting the match registers, so that the regex functions will be |
| 77 | able to free or re-allocate it properly. */ | 77 | able to free or re-allocate it properly. */ |
| 78 | static struct re_registers search_regs; | 78 | /* static struct re_registers search_regs; */ |
| 79 | 79 | ||
| 80 | /* The buffer in which the last search was performed, or | 80 | /* The buffer in which the last search was performed, or |
| 81 | Qt if the last search was done in a string; | 81 | Qt if the last search was done in a string; |
| 82 | Qnil if no searching has been done yet. */ | 82 | Qnil if no searching has been done yet. */ |
| 83 | static Lisp_Object last_thing_searched; | 83 | /* static Lisp_Object last_thing_searched; */ |
| 84 | 84 | ||
| 85 | static void set_search_regs (ptrdiff_t, ptrdiff_t); | 85 | static void set_search_regs (ptrdiff_t, ptrdiff_t); |
| 86 | static void save_search_regs (void); | 86 | static void save_search_regs (void); |
| @@ -122,9 +122,9 @@ compile_pattern_1 (struct regexp_cache *cp, Lisp_Object pattern, | |||
| 122 | cp->buf.multibyte = STRING_MULTIBYTE (pattern); | 122 | cp->buf.multibyte = STRING_MULTIBYTE (pattern); |
| 123 | cp->buf.charset_unibyte = charset_unibyte; | 123 | cp->buf.charset_unibyte = charset_unibyte; |
| 124 | if (STRINGP (Vsearch_spaces_regexp)) | 124 | if (STRINGP (Vsearch_spaces_regexp)) |
| 125 | cp->whitespace_regexp = Vsearch_spaces_regexp; | 125 | cp->f_whitespace_regexp = Vsearch_spaces_regexp; |
| 126 | else | 126 | else |
| 127 | cp->whitespace_regexp = Qnil; | 127 | cp->f_whitespace_regexp = Qnil; |
| 128 | 128 | ||
| 129 | /* rms: I think BLOCK_INPUT is not needed here any more, | 129 | /* rms: I think BLOCK_INPUT is not needed here any more, |
| 130 | because regex.c defines malloc to call xmalloc. | 130 | because regex.c defines malloc to call xmalloc. |
| @@ -217,7 +217,7 @@ compile_pattern (Lisp_Object pattern, struct re_registers *regp, | |||
| 217 | && cp->posix == posix | 217 | && cp->posix == posix |
| 218 | && (EQ (cp->syntax_table, Qt) | 218 | && (EQ (cp->syntax_table, Qt) |
| 219 | || EQ (cp->syntax_table, BVAR (current_buffer, syntax_table))) | 219 | || EQ (cp->syntax_table, BVAR (current_buffer, syntax_table))) |
| 220 | && !NILP (Fequal (cp->whitespace_regexp, Vsearch_spaces_regexp)) | 220 | && !NILP (Fequal (cp->f_whitespace_regexp, Vsearch_spaces_regexp)) |
| 221 | && cp->buf.charset_unibyte == charset_unibyte) | 221 | && cp->buf.charset_unibyte == charset_unibyte) |
| 222 | break; | 222 | break; |
| 223 | 223 | ||
| @@ -3089,9 +3089,9 @@ If optional arg RESEAT is non-nil, make markers on LIST point nowhere. */) | |||
| 3089 | 3089 | ||
| 3090 | /* If true the match data have been saved in saved_search_regs | 3090 | /* If true the match data have been saved in saved_search_regs |
| 3091 | during the execution of a sentinel or filter. */ | 3091 | during the execution of a sentinel or filter. */ |
| 3092 | static bool search_regs_saved; | 3092 | /* static bool search_regs_saved; */ |
| 3093 | static struct re_registers saved_search_regs; | 3093 | /* static struct re_registers saved_search_regs; */ |
| 3094 | static Lisp_Object saved_last_thing_searched; | 3094 | /* static Lisp_Object saved_last_thing_searched; */ |
| 3095 | 3095 | ||
| 3096 | /* Called from Flooking_at, Fstring_match, search_buffer, Fstore_match_data | 3096 | /* Called from Flooking_at, Fstring_match, search_buffer, Fstore_match_data |
| 3097 | if asynchronous code (filter or sentinel) is running. */ | 3097 | if asynchronous code (filter or sentinel) is running. */ |
| @@ -3401,10 +3401,10 @@ syms_of_search (void) | |||
| 3401 | searchbufs[i].buf.buffer = xmalloc (100); | 3401 | searchbufs[i].buf.buffer = xmalloc (100); |
| 3402 | searchbufs[i].buf.fastmap = searchbufs[i].fastmap; | 3402 | searchbufs[i].buf.fastmap = searchbufs[i].fastmap; |
| 3403 | searchbufs[i].regexp = Qnil; | 3403 | searchbufs[i].regexp = Qnil; |
| 3404 | searchbufs[i].whitespace_regexp = Qnil; | 3404 | searchbufs[i].f_whitespace_regexp = Qnil; |
| 3405 | searchbufs[i].syntax_table = Qnil; | 3405 | searchbufs[i].syntax_table = Qnil; |
| 3406 | staticpro (&searchbufs[i].regexp); | 3406 | staticpro (&searchbufs[i].regexp); |
| 3407 | staticpro (&searchbufs[i].whitespace_regexp); | 3407 | staticpro (&searchbufs[i].f_whitespace_regexp); |
| 3408 | staticpro (&searchbufs[i].syntax_table); | 3408 | staticpro (&searchbufs[i].syntax_table); |
| 3409 | searchbufs[i].next = (i == REGEXP_CACHE_SIZE-1 ? 0 : &searchbufs[i+1]); | 3409 | searchbufs[i].next = (i == REGEXP_CACHE_SIZE-1 ? 0 : &searchbufs[i+1]); |
| 3410 | } | 3410 | } |
diff --git a/src/sysdep.c b/src/sysdep.c index 257634292b1..3d2b9bdeeee 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -51,14 +51,19 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 51 | # include <math.h> | 51 | # include <math.h> |
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | #ifdef HAVE_SOCKETS | ||
| 55 | #include <sys/socket.h> | ||
| 56 | #include <netdb.h> | ||
| 57 | #endif /* HAVE_SOCKETS */ | ||
| 58 | |||
| 54 | #ifdef WINDOWSNT | 59 | #ifdef WINDOWSNT |
| 55 | #define read sys_read | 60 | #define read sys_read |
| 56 | #define write sys_write | 61 | #define write sys_write |
| 57 | #ifndef STDERR_FILENO | 62 | #ifndef STDERR_FILENO |
| 58 | #define STDERR_FILENO fileno(GetStdHandle(STD_ERROR_HANDLE)) | 63 | #define STDERR_FILENO fileno(GetStdHandle(STD_ERROR_HANDLE)) |
| 59 | #endif | 64 | #endif |
| 60 | #include <windows.h> | 65 | #include "w32.h" |
| 61 | #endif /* not WINDOWSNT */ | 66 | #endif /* WINDOWSNT */ |
| 62 | 67 | ||
| 63 | #include <sys/types.h> | 68 | #include <sys/types.h> |
| 64 | #include <sys/stat.h> | 69 | #include <sys/stat.h> |
diff --git a/src/systhread.c b/src/systhread.c new file mode 100644 index 00000000000..c11e0247886 --- /dev/null +++ b/src/systhread.c | |||
| @@ -0,0 +1,417 @@ | |||
| 1 | /* System 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 | #include <config.h> | ||
| 20 | #include <setjmp.h> | ||
| 21 | #include "lisp.h" | ||
| 22 | |||
| 23 | #ifndef THREADS_ENABLED | ||
| 24 | |||
| 25 | void | ||
| 26 | sys_mutex_init (sys_mutex_t *m) | ||
| 27 | { | ||
| 28 | *m = 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | void | ||
| 32 | sys_mutex_lock (sys_mutex_t *m) | ||
| 33 | { | ||
| 34 | } | ||
| 35 | |||
| 36 | void | ||
| 37 | sys_mutex_unlock (sys_mutex_t *m) | ||
| 38 | { | ||
| 39 | } | ||
| 40 | |||
| 41 | void | ||
| 42 | sys_mutex_destroy (sys_mutex_t *m) | ||
| 43 | { | ||
| 44 | } | ||
| 45 | |||
| 46 | void | ||
| 47 | sys_cond_init (sys_cond_t *c) | ||
| 48 | { | ||
| 49 | *c = 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | void | ||
| 53 | sys_cond_wait (sys_cond_t *c, sys_mutex_t *m) | ||
| 54 | { | ||
| 55 | } | ||
| 56 | |||
| 57 | void | ||
| 58 | sys_cond_signal (sys_cond_t *c) | ||
| 59 | { | ||
| 60 | } | ||
| 61 | |||
| 62 | void | ||
| 63 | sys_cond_broadcast (sys_cond_t *c) | ||
| 64 | { | ||
| 65 | } | ||
| 66 | |||
| 67 | void | ||
| 68 | sys_cond_destroy (sys_cond_t *c) | ||
| 69 | { | ||
| 70 | } | ||
| 71 | |||
| 72 | sys_thread_t | ||
| 73 | sys_thread_self (void) | ||
| 74 | { | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | int | ||
| 79 | sys_thread_equal (sys_thread_t x, sys_thread_t y) | ||
| 80 | { | ||
| 81 | return x == y; | ||
| 82 | } | ||
| 83 | |||
| 84 | int | ||
| 85 | sys_thread_create (sys_thread_t *t, const char *name, | ||
| 86 | thread_creation_function *func, void *datum) | ||
| 87 | { | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | sys_thread_yield (void) | ||
| 93 | { | ||
| 94 | } | ||
| 95 | |||
| 96 | #elif defined (HAVE_PTHREAD) | ||
| 97 | |||
| 98 | #include <sched.h> | ||
| 99 | |||
| 100 | #ifdef HAVE_SYS_PRCTL_H | ||
| 101 | #include <sys/prctl.h> | ||
| 102 | #endif | ||
| 103 | |||
| 104 | void | ||
| 105 | sys_mutex_init (sys_mutex_t *mutex) | ||
| 106 | { | ||
| 107 | pthread_mutex_init (mutex, NULL); | ||
| 108 | } | ||
| 109 | |||
| 110 | void | ||
| 111 | sys_mutex_lock (sys_mutex_t *mutex) | ||
| 112 | { | ||
| 113 | pthread_mutex_lock (mutex); | ||
| 114 | } | ||
| 115 | |||
| 116 | void | ||
| 117 | sys_mutex_unlock (sys_mutex_t *mutex) | ||
| 118 | { | ||
| 119 | pthread_mutex_unlock (mutex); | ||
| 120 | } | ||
| 121 | |||
| 122 | void | ||
| 123 | sys_mutex_destroy (sys_mutex_t *mutex) | ||
| 124 | { | ||
| 125 | pthread_mutex_destroy (mutex); | ||
| 126 | } | ||
| 127 | |||
| 128 | void | ||
| 129 | sys_cond_init (sys_cond_t *cond) | ||
| 130 | { | ||
| 131 | pthread_cond_init (cond, NULL); | ||
| 132 | } | ||
| 133 | |||
| 134 | void | ||
| 135 | sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) | ||
| 136 | { | ||
| 137 | pthread_cond_wait (cond, mutex); | ||
| 138 | } | ||
| 139 | |||
| 140 | void | ||
| 141 | sys_cond_signal (sys_cond_t *cond) | ||
| 142 | { | ||
| 143 | pthread_cond_signal (cond); | ||
| 144 | } | ||
| 145 | |||
| 146 | void | ||
| 147 | sys_cond_broadcast (sys_cond_t *cond) | ||
| 148 | { | ||
| 149 | pthread_cond_broadcast (cond); | ||
| 150 | } | ||
| 151 | |||
| 152 | void | ||
| 153 | sys_cond_destroy (sys_cond_t *cond) | ||
| 154 | { | ||
| 155 | pthread_cond_destroy (cond); | ||
| 156 | } | ||
| 157 | |||
| 158 | sys_thread_t | ||
| 159 | sys_thread_self (void) | ||
| 160 | { | ||
| 161 | return pthread_self (); | ||
| 162 | } | ||
| 163 | |||
| 164 | int | ||
| 165 | sys_thread_equal (sys_thread_t one, sys_thread_t two) | ||
| 166 | { | ||
| 167 | return pthread_equal (one, two); | ||
| 168 | } | ||
| 169 | |||
| 170 | int | ||
| 171 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, | ||
| 172 | thread_creation_function *func, void *arg) | ||
| 173 | { | ||
| 174 | pthread_attr_t attr; | ||
| 175 | int result = 0; | ||
| 176 | |||
| 177 | if (pthread_attr_init (&attr)) | ||
| 178 | return 0; | ||
| 179 | |||
| 180 | if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED)) | ||
| 181 | { | ||
| 182 | result = pthread_create (thread_ptr, &attr, func, arg) == 0; | ||
| 183 | #if defined (HAVE_SYS_PRCTL_H) && defined (HAVE_PRCTL) && defined (PR_SET_NAME) | ||
| 184 | if (result && name != NULL) | ||
| 185 | prctl (PR_SET_NAME, name); | ||
| 186 | #endif | ||
| 187 | } | ||
| 188 | |||
| 189 | pthread_attr_destroy (&attr); | ||
| 190 | |||
| 191 | return result; | ||
| 192 | } | ||
| 193 | |||
| 194 | void | ||
| 195 | sys_thread_yield (void) | ||
| 196 | { | ||
| 197 | sched_yield (); | ||
| 198 | } | ||
| 199 | |||
| 200 | #elif defined (WINDOWSNT) | ||
| 201 | |||
| 202 | #include <windows.h> | ||
| 203 | |||
| 204 | /* Cannot include <process.h> because of the local header by the same | ||
| 205 | name, sigh. */ | ||
| 206 | uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *); | ||
| 207 | |||
| 208 | /* Mutexes are implemented as critical sections, because they are | ||
| 209 | faster than Windows mutex objects (implemented in userspace), and | ||
| 210 | satisfy the requirements, since we only need to synchronize within a | ||
| 211 | single process. */ | ||
| 212 | void | ||
| 213 | sys_mutex_init (sys_mutex_t *mutex) | ||
| 214 | { | ||
| 215 | InitializeCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 216 | } | ||
| 217 | |||
| 218 | void | ||
| 219 | sys_mutex_lock (sys_mutex_t *mutex) | ||
| 220 | { | ||
| 221 | /* FIXME: What happens if the owning thread exits without releasing | ||
| 222 | the mutex? Accoding to MSDN, the result is undefined behavior. */ | ||
| 223 | EnterCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 224 | } | ||
| 225 | |||
| 226 | void | ||
| 227 | sys_mutex_unlock (sys_mutex_t *mutex) | ||
| 228 | { | ||
| 229 | LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 230 | } | ||
| 231 | |||
| 232 | void | ||
| 233 | sys_mutex_destroy (sys_mutex_t *mutex) | ||
| 234 | { | ||
| 235 | /* FIXME: According to MSDN, deleting a critical session that is | ||
| 236 | owned by a thread leaves the other threads waiting for the | ||
| 237 | critical session in an undefined state. Posix docs seem to say | ||
| 238 | the same about pthread_mutex_destroy. Do we need to protect | ||
| 239 | against such calamities? */ | ||
| 240 | DeleteCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 241 | } | ||
| 242 | |||
| 243 | void | ||
| 244 | sys_cond_init (sys_cond_t *cond) | ||
| 245 | { | ||
| 246 | cond->initialized = false; | ||
| 247 | cond->wait_count = 0; | ||
| 248 | /* Auto-reset event for signal. */ | ||
| 249 | cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
| 250 | /* Manual-reset event for broadcast. */ | ||
| 251 | cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL); | ||
| 252 | if (!cond->events[CONDV_SIGNAL] || !cond->events[CONDV_BROADCAST]) | ||
| 253 | return; | ||
| 254 | InitializeCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 255 | cond->initialized = true; | ||
| 256 | } | ||
| 257 | |||
| 258 | void | ||
| 259 | sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex) | ||
| 260 | { | ||
| 261 | DWORD wait_result; | ||
| 262 | bool last_thread_waiting; | ||
| 263 | |||
| 264 | if (!cond->initialized) | ||
| 265 | return; | ||
| 266 | |||
| 267 | /* Increment the wait count avoiding race conditions. */ | ||
| 268 | EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 269 | cond->wait_count++; | ||
| 270 | LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 271 | |||
| 272 | /* Release the mutex and wait for either the signal or the broadcast | ||
| 273 | event. */ | ||
| 274 | LeaveCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 275 | wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE); | ||
| 276 | |||
| 277 | /* Decrement the wait count and see if we are the last thread | ||
| 278 | waiting on the condition variable. */ | ||
| 279 | EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 280 | cond->wait_count--; | ||
| 281 | last_thread_waiting = | ||
| 282 | wait_result == WAIT_OBJECT_0 + CONDV_BROADCAST | ||
| 283 | && cond->wait_count == 0; | ||
| 284 | LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 285 | |||
| 286 | /* Broadcast uses a manual-reset event, so when the last thread is | ||
| 287 | released, we must manually reset that event. */ | ||
| 288 | if (last_thread_waiting) | ||
| 289 | ResetEvent (cond->events[CONDV_BROADCAST]); | ||
| 290 | |||
| 291 | /* Per the API, re-acquire the mutex. */ | ||
| 292 | EnterCriticalSection ((LPCRITICAL_SECTION)mutex); | ||
| 293 | } | ||
| 294 | |||
| 295 | void | ||
| 296 | sys_cond_signal (sys_cond_t *cond) | ||
| 297 | { | ||
| 298 | bool threads_waiting; | ||
| 299 | |||
| 300 | if (!cond->initialized) | ||
| 301 | return; | ||
| 302 | |||
| 303 | EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 304 | threads_waiting = cond->wait_count > 0; | ||
| 305 | LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 306 | |||
| 307 | if (threads_waiting) | ||
| 308 | SetEvent (cond->events[CONDV_SIGNAL]); | ||
| 309 | } | ||
| 310 | |||
| 311 | void | ||
| 312 | sys_cond_broadcast (sys_cond_t *cond) | ||
| 313 | { | ||
| 314 | bool threads_waiting; | ||
| 315 | |||
| 316 | if (!cond->initialized) | ||
| 317 | return; | ||
| 318 | |||
| 319 | EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 320 | threads_waiting = cond->wait_count > 0; | ||
| 321 | LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 322 | |||
| 323 | if (threads_waiting) | ||
| 324 | SetEvent (cond->events[CONDV_BROADCAST]); | ||
| 325 | } | ||
| 326 | |||
| 327 | void | ||
| 328 | sys_cond_destroy (sys_cond_t *cond) | ||
| 329 | { | ||
| 330 | if (cond->events[CONDV_SIGNAL]) | ||
| 331 | CloseHandle (cond->events[CONDV_SIGNAL]); | ||
| 332 | if (cond->events[CONDV_BROADCAST]) | ||
| 333 | CloseHandle (cond->events[CONDV_BROADCAST]); | ||
| 334 | |||
| 335 | if (!cond->initialized) | ||
| 336 | return; | ||
| 337 | |||
| 338 | /* FIXME: What if wait_count is non-zero, i.e. there are still | ||
| 339 | threads waiting on this condition variable? */ | ||
| 340 | DeleteCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock); | ||
| 341 | } | ||
| 342 | |||
| 343 | sys_thread_t | ||
| 344 | sys_thread_self (void) | ||
| 345 | { | ||
| 346 | return (sys_thread_t) GetCurrentThreadId (); | ||
| 347 | } | ||
| 348 | |||
| 349 | int | ||
| 350 | sys_thread_equal (sys_thread_t one, sys_thread_t two) | ||
| 351 | { | ||
| 352 | return one == two; | ||
| 353 | } | ||
| 354 | |||
| 355 | static thread_creation_function *thread_start_address; | ||
| 356 | |||
| 357 | /* _beginthread wants a void function, while we are passed a function | ||
| 358 | that returns a pointer. So we use a wrapper. */ | ||
| 359 | static void | ||
| 360 | w32_beginthread_wrapper (void *arg) | ||
| 361 | { | ||
| 362 | (void)thread_start_address (arg); | ||
| 363 | } | ||
| 364 | |||
| 365 | int | ||
| 366 | sys_thread_create (sys_thread_t *thread_ptr, const char *name, | ||
| 367 | thread_creation_function *func, void *arg) | ||
| 368 | { | ||
| 369 | /* FIXME: Do threads that run Lisp require some minimum amount of | ||
| 370 | stack? Zero here means each thread will get the same amount as | ||
| 371 | the main program. On GNU/Linux, it seems like the stack is 2MB | ||
| 372 | by default, overridden by RLIMIT_STACK at program start time. | ||
| 373 | Not sure what to do with this. See also the comment in | ||
| 374 | w32proc.c:new_child. */ | ||
| 375 | const unsigned stack_size = 0; | ||
| 376 | uintptr_t thandle; | ||
| 377 | |||
| 378 | thread_start_address = func; | ||
| 379 | |||
| 380 | /* We use _beginthread rather than CreateThread because the former | ||
| 381 | arranges for the thread handle to be automatically closed when | ||
| 382 | the thread exits, thus preventing handle leaks and/or the need to | ||
| 383 | track all the threads and close their handles when they exit. | ||
| 384 | Also, MSDN seems to imply that code which uses CRT _must_ call | ||
| 385 | _beginthread, although if that is true, we already violate that | ||
| 386 | rule in many places... */ | ||
| 387 | thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg); | ||
| 388 | if (thandle == (uintptr_t)-1L) | ||
| 389 | return 0; | ||
| 390 | |||
| 391 | /* Kludge alert! We use the Windows thread ID, an unsigned 32-bit | ||
| 392 | number, as the sys_thread_t type, because that ID is the only | ||
| 393 | unique identifier of a thread on Windows. But _beginthread | ||
| 394 | returns a handle of the thread, and there's no easy way of | ||
| 395 | getting the thread ID given a handle (GetThreadId is available | ||
| 396 | only since Vista, so we cannot use it portably). Fortunately, | ||
| 397 | the value returned by sys_thread_create is not used by its | ||
| 398 | callers; instead, run_thread, which runs in the context of the | ||
| 399 | new thread, calls sys_thread_self and uses its return value; | ||
| 400 | sys_thread_self in this implementation calls GetCurrentThreadId. | ||
| 401 | Therefore, we return some more or less arbitrary value of the | ||
| 402 | thread ID from this function. */ | ||
| 403 | *thread_ptr = thandle & 0xFFFFFFFF; | ||
| 404 | return 1; | ||
| 405 | } | ||
| 406 | |||
| 407 | void | ||
| 408 | sys_thread_yield (void) | ||
| 409 | { | ||
| 410 | Sleep (0); | ||
| 411 | } | ||
| 412 | |||
| 413 | #else | ||
| 414 | |||
| 415 | #error port me | ||
| 416 | |||
| 417 | #endif | ||
diff --git a/src/systhread.h b/src/systhread.h new file mode 100644 index 00000000000..b38fd8ffd45 --- /dev/null +++ b/src/systhread.h | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | /* System 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 SYSTHREAD_H | ||
| 20 | #define SYSTHREAD_H | ||
| 21 | |||
| 22 | #ifdef THREADS_ENABLED | ||
| 23 | |||
| 24 | #ifdef HAVE_PTHREAD | ||
| 25 | |||
| 26 | #include <pthread.h> | ||
| 27 | |||
| 28 | /* A system mutex is just a pthread mutex. This is only used for the | ||
| 29 | GIL. */ | ||
| 30 | typedef pthread_mutex_t sys_mutex_t; | ||
| 31 | |||
| 32 | typedef pthread_cond_t sys_cond_t; | ||
| 33 | |||
| 34 | /* A system thread. */ | ||
| 35 | typedef pthread_t sys_thread_t; | ||
| 36 | |||
| 37 | #else /* HAVE_PTHREAD */ | ||
| 38 | |||
| 39 | #ifdef WINDOWSNT | ||
| 40 | |||
| 41 | /* This header is indirectly included in every source file. We don't | ||
| 42 | want to include windows.h in every source file, so we repeat | ||
| 43 | declarations of the few necessary data types here (under different | ||
| 44 | names, to avoid conflicts with files that do include | ||
| 45 | windows.h). */ | ||
| 46 | |||
| 47 | typedef struct { | ||
| 48 | struct _CRITICAL_SECTION_DEBUG *DebugInfo; | ||
| 49 | long LockCount; | ||
| 50 | long RecursionCount; | ||
| 51 | void *OwningThread; | ||
| 52 | void *LockSemaphore; | ||
| 53 | unsigned long SpinCount; | ||
| 54 | } w32thread_critsect; | ||
| 55 | |||
| 56 | enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 }; | ||
| 57 | |||
| 58 | typedef struct { | ||
| 59 | /* Count of threads that are waiting for this condition variable. */ | ||
| 60 | unsigned wait_count; | ||
| 61 | /* Critical section to protect changes to the count above. */ | ||
| 62 | w32thread_critsect wait_count_lock; | ||
| 63 | /* Handles of events used for signal and broadcast. */ | ||
| 64 | void *events[CONDV_MAX]; | ||
| 65 | bool initialized; | ||
| 66 | } w32thread_cond_t; | ||
| 67 | |||
| 68 | typedef w32thread_critsect sys_mutex_t; | ||
| 69 | |||
| 70 | typedef w32thread_cond_t sys_cond_t; | ||
| 71 | |||
| 72 | typedef unsigned long sys_thread_t; | ||
| 73 | |||
| 74 | #else /* !WINDOWSNT */ | ||
| 75 | |||
| 76 | #error port me | ||
| 77 | |||
| 78 | #endif /* WINDOWSNT */ | ||
| 79 | #endif /* HAVE_PTHREAD */ | ||
| 80 | |||
| 81 | #else /* THREADS_ENABLED */ | ||
| 82 | |||
| 83 | /* For the no-threads case we can simply use dummy definitions. */ | ||
| 84 | typedef int sys_mutex_t; | ||
| 85 | typedef int sys_cond_t; | ||
| 86 | typedef int sys_thread_t; | ||
| 87 | |||
| 88 | #endif /* THREADS_ENABLED */ | ||
| 89 | |||
| 90 | typedef void *(thread_creation_function) (void *); | ||
| 91 | |||
| 92 | extern void sys_mutex_init (sys_mutex_t *); | ||
| 93 | extern void sys_mutex_lock (sys_mutex_t *); | ||
| 94 | extern void sys_mutex_unlock (sys_mutex_t *); | ||
| 95 | extern void sys_mutex_destroy (sys_mutex_t *); | ||
| 96 | |||
| 97 | extern void sys_cond_init (sys_cond_t *); | ||
| 98 | extern void sys_cond_wait (sys_cond_t *, sys_mutex_t *); | ||
| 99 | extern void sys_cond_signal (sys_cond_t *); | ||
| 100 | extern void sys_cond_broadcast (sys_cond_t *); | ||
| 101 | extern void sys_cond_destroy (sys_cond_t *); | ||
| 102 | |||
| 103 | extern sys_thread_t sys_thread_self (void); | ||
| 104 | extern int sys_thread_equal (sys_thread_t, sys_thread_t); | ||
| 105 | |||
| 106 | extern int sys_thread_create (sys_thread_t *, const char *, | ||
| 107 | thread_creation_function *, | ||
| 108 | void *); | ||
| 109 | |||
| 110 | extern void sys_thread_yield (void); | ||
| 111 | |||
| 112 | #endif /* SYSTHREAD_H */ | ||
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 | |||
| 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 | |||
| 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 | |||
| 28 | static struct thread_state primary_thread; | ||
| 29 | |||
| 30 | struct thread_state *current_thread = &primary_thread; | ||
| 31 | |||
| 32 | static struct thread_state *all_threads = &primary_thread; | ||
| 33 | |||
| 34 | static sys_mutex_t global_lock; | ||
| 35 | |||
| 36 | extern int poll_suppress_count; | ||
| 37 | extern 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 | |||
| 47 | static void | ||
| 48 | release_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. */ | ||
| 55 | static void | ||
| 56 | post_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 | |||
| 92 | static void | ||
| 93 | acquire_global_lock (struct thread_state *self) | ||
| 94 | { | ||
| 95 | sys_mutex_lock (&global_lock); | ||
| 96 | post_acquire_global_lock (self); | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | |||
| 101 | static void | ||
| 102 | lisp_mutex_init (lisp_mutex_t *mutex) | ||
| 103 | { | ||
| 104 | mutex->owner = NULL; | ||
| 105 | mutex->count = 0; | ||
| 106 | sys_cond_init (&mutex->condition); | ||
| 107 | } | ||
| 108 | |||
| 109 | static int | ||
| 110 | lisp_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 | |||
| 143 | static int | ||
| 144 | lisp_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 | |||
| 158 | static unsigned int | ||
| 159 | lisp_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 | |||
| 173 | static void | ||
| 174 | lisp_mutex_destroy (lisp_mutex_t *mutex) | ||
| 175 | { | ||
| 176 | sys_cond_destroy (&mutex->condition); | ||
| 177 | } | ||
| 178 | |||
| 179 | static int | ||
| 180 | lisp_mutex_owned_p (lisp_mutex_t *mutex) | ||
| 181 | { | ||
| 182 | return mutex->owner == current_thread; | ||
| 183 | } | ||
| 184 | |||
| 185 | |||
| 186 | |||
| 187 | DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0, | ||
| 188 | doc: /* Create a mutex. | ||
| 189 | A mutex provides a synchronization point for threads. | ||
| 190 | Only one thread at a time can hold a mutex. Other threads attempting | ||
| 191 | to acquire it will block until the mutex is available. | ||
| 192 | |||
| 193 | A thread can acquire a mutex any number of times. | ||
| 194 | |||
| 195 | NAME, if given, is used as the name of the mutex. The name is | ||
| 196 | informational 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 | |||
| 216 | static void | ||
| 217 | mutex_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 | |||
| 226 | static void | ||
| 227 | do_unwind_mutex_lock (void) | ||
| 228 | { | ||
| 229 | current_thread->event_object = Qnil; | ||
| 230 | } | ||
| 231 | |||
| 232 | DEFUN ("mutex-lock", Fmutex_lock, Smutex_lock, 1, 1, 0, | ||
| 233 | doc: /* Acquire a mutex. | ||
| 234 | If the current thread already owns MUTEX, increment the count and | ||
| 235 | return. | ||
| 236 | Otherwise, if no thread owns MUTEX, make the current thread own it. | ||
| 237 | Otherwise, block until MUTEX is available, or until the current thread | ||
| 238 | is signalled using `thread-signal'. | ||
| 239 | Note 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 | |||
| 254 | static void | ||
| 255 | mutex_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 | |||
| 264 | DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, | ||
| 265 | doc: /* Release the mutex. | ||
| 266 | If this thread does not own MUTEX, signal an error. | ||
| 267 | Otherwise, decrement the mutex's count. If the count is zero, | ||
| 268 | release 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 | |||
| 280 | DEFUN ("mutex-name", Fmutex_name, Smutex_name, 1, 1, 0, | ||
| 281 | doc: /* Return the name of MUTEX. | ||
| 282 | If 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 | |||
| 293 | void | ||
| 294 | finalize_one_mutex (struct Lisp_Mutex *mutex) | ||
| 295 | { | ||
| 296 | lisp_mutex_destroy (&mutex->mutex); | ||
| 297 | } | ||
| 298 | |||
| 299 | |||
| 300 | |||
| 301 | DEFUN ("make-condition-variable", | ||
| 302 | Fmake_condition_variable, Smake_condition_variable, | ||
| 303 | 1, 2, 0, | ||
| 304 | doc: /* Make a condition variable associated with MUTEX. | ||
| 305 | A condition variable provides a way for a thread to sleep while | ||
| 306 | waiting for a state change. | ||
| 307 | |||
| 308 | MUTEX is the mutex associated with this condition variable. | ||
| 309 | NAME, if given, is the name of this condition variable. The name is | ||
| 310 | informational 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 | |||
| 332 | static void | ||
| 333 | condition_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 | |||
| 357 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, | ||
| 358 | doc: /* Wait for the condition variable COND to be notified. | ||
| 359 | COND is the condition variable to wait on. | ||
| 360 | |||
| 361 | The mutex associated with COND must be held when this is called. | ||
| 362 | It is an error if it is not held. | ||
| 363 | |||
| 364 | This releases the mutex and waits for COND to be notified or for | ||
| 365 | this thread to be signalled with `thread-signal'. When | ||
| 366 | `condition-wait' returns, COND's mutex will again be locked by | ||
| 367 | this 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. */ | ||
| 386 | struct notify_args | ||
| 387 | { | ||
| 388 | struct Lisp_CondVar *cvar; | ||
| 389 | int all; | ||
| 390 | }; | ||
| 391 | |||
| 392 | static void | ||
| 393 | condition_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 | |||
| 411 | DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0, | ||
| 412 | doc: /* Notify COND, a condition variable. | ||
| 413 | This wakes a thread waiting on COND. | ||
| 414 | If ALL is non-nil, all waiting threads are awoken. | ||
| 415 | |||
| 416 | The mutex associated with COND must be held when this is called. | ||
| 417 | It is an error if it is not held. | ||
| 418 | |||
| 419 | This releases COND's mutex when notifying COND. When | ||
| 420 | `condition-notify' returns, the mutex will again be locked by this | ||
| 421 | thread. */) | ||
| 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 | |||
| 442 | DEFUN ("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 | |||
| 454 | DEFUN ("condition-name", Fcondition_name, Scondition_name, 1, 1, 0, | ||
| 455 | doc: /* Return the name of condition variable COND. | ||
| 456 | If 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 | |||
| 467 | void | ||
| 468 | finalize_one_condvar (struct Lisp_CondVar *condvar) | ||
| 469 | { | ||
| 470 | sys_cond_destroy (&condvar->cond); | ||
| 471 | } | ||
| 472 | |||
| 473 | |||
| 474 | |||
| 475 | struct 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 | |||
| 487 | static void | ||
| 488 | really_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 | |||
| 499 | int | ||
| 500 | thread_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 | |||
| 519 | static void | ||
| 520 | mark_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 | |||
| 547 | static void | ||
| 548 | mark_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 | |||
| 562 | void | ||
| 563 | mark_threads (void) | ||
| 564 | { | ||
| 565 | flush_stack_call_func (mark_threads_callback, NULL); | ||
| 566 | } | ||
| 567 | |||
| 568 | void | ||
| 569 | unmark_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 | |||
| 580 | static void | ||
| 581 | yield_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 | |||
| 590 | DEFUN ("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 | |||
| 598 | static Lisp_Object | ||
| 599 | invoke_thread_function (void) | ||
| 600 | { | ||
| 601 | int count = SPECPDL_INDEX (); | ||
| 602 | |||
| 603 | Ffuncall (1, ¤t_thread->function); | ||
| 604 | return unbind_to (count, Qnil); | ||
| 605 | } | ||
| 606 | |||
| 607 | static Lisp_Object | ||
| 608 | do_nothing (Lisp_Object whatever) | ||
| 609 | { | ||
| 610 | return whatever; | ||
| 611 | } | ||
| 612 | |||
| 613 | static void * | ||
| 614 | run_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 | |||
| 672 | void | ||
| 673 | finalize_one_thread (struct thread_state *state) | ||
| 674 | { | ||
| 675 | sys_cond_destroy (&state->thread_condvar); | ||
| 676 | } | ||
| 677 | |||
| 678 | DEFUN ("make-thread", Fmake_thread, Smake_thread, 1, 2, 0, | ||
| 679 | doc: /* Start a new thread and run FUNCTION in it. | ||
| 680 | When the function exits, the thread dies. | ||
| 681 | If 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 | |||
| 739 | DEFUN ("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 | |||
| 748 | DEFUN ("thread-name", Fthread_name, Sthread_name, 1, 1, 0, | ||
| 749 | doc: /* Return the name of the THREAD. | ||
| 750 | The 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 | |||
| 761 | static void | ||
| 762 | thread_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 | |||
| 771 | DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0, | ||
| 772 | doc: /* Signal an error in a thread. | ||
| 773 | This acts like `signal', but arranges for the signal to be raised | ||
| 774 | in THREAD. If THREAD is the current thread, acts just like `signal'. | ||
| 775 | This will interrupt a blocked call to `mutex-lock', `condition-wait', | ||
| 776 | or `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 | |||
| 798 | DEFUN ("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 | |||
| 810 | DEFUN ("thread--blocker", Fthread_blocker, Sthread_blocker, 1, 1, 0, | ||
| 811 | doc: /* Return the object that THREAD is blocking on. | ||
| 812 | If THREAD is blocked in `thread-join' on a second thread, return that | ||
| 813 | thread. | ||
| 814 | If THREAD is blocked in `mutex-lock', return the mutex. | ||
| 815 | If THREAD is blocked in `condition-wait', return the condition variable. | ||
| 816 | Otherwise, 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 | |||
| 827 | static void | ||
| 828 | thread_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 | |||
| 845 | DEFUN ("thread-join", Fthread_join, Sthread_join, 1, 1, 0, | ||
| 846 | doc: /* Wait for THREAD to exit. | ||
| 847 | This blocks the current thread until THREAD exits or until | ||
| 848 | the current thread is signaled. | ||
| 849 | It 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 | |||
| 866 | DEFUN ("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 | |||
| 889 | bool | ||
| 890 | thread_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 | |||
| 908 | static void | ||
| 909 | init_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 | |||
| 923 | void | ||
| 924 | init_threads_once (void) | ||
| 925 | { | ||
| 926 | init_primary_thread (); | ||
| 927 | } | ||
| 928 | |||
| 929 | void | ||
| 930 | init_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 | |||
| 940 | void | ||
| 941 | syms_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 | } | ||
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 */ | ||
| @@ -272,7 +272,7 @@ static BOOL WINAPI revert_to_self (void); | |||
| 272 | static int sys_access (const char *, int); | 272 | static int sys_access (const char *, int); |
| 273 | extern void *e_malloc (size_t); | 273 | extern void *e_malloc (size_t); |
| 274 | extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, | 274 | extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, |
| 275 | struct timespec *, void *); | 275 | const struct timespec *, const sigset_t *); |
| 276 | extern int sys_dup (int); | 276 | extern int sys_dup (int); |
| 277 | 277 | ||
| 278 | 278 | ||
diff --git a/src/w32proc.c b/src/w32proc.c index 189034c4e2d..6f3a6e0efca 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -72,7 +72,7 @@ extern BOOL g_b_init_compare_string_w; | |||
| 72 | extern BOOL g_b_init_debug_break_process; | 72 | extern BOOL g_b_init_debug_break_process; |
| 73 | 73 | ||
| 74 | int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, | 74 | int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, |
| 75 | struct timespec *, void *); | 75 | const struct timespec *, const sigset_t *); |
| 76 | 76 | ||
| 77 | /* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ | 77 | /* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ |
| 78 | static signal_handler sig_handlers[NSIG]; | 78 | static signal_handler sig_handlers[NSIG]; |
| @@ -849,8 +849,8 @@ alarm (int seconds) | |||
| 849 | stream is terminated, terminates the reader thread as part of | 849 | stream is terminated, terminates the reader thread as part of |
| 850 | deleting the child_process object. | 850 | deleting the child_process object. |
| 851 | 851 | ||
| 852 | The sys_select function emulates the Posix 'pselect' function; it | 852 | The sys_select function emulates the Posix 'pselect' functionality; |
| 853 | is needed because the Windows 'select' function supports only | 853 | it is needed because the Windows 'select' function supports only |
| 854 | network sockets, while Emacs expects 'pselect' to work for any file | 854 | network sockets, while Emacs expects 'pselect' to work for any file |
| 855 | descriptor, including pipes and serial streams. | 855 | descriptor, including pipes and serial streams. |
| 856 | 856 | ||
| @@ -2096,7 +2096,7 @@ extern int proc_buffered_char[]; | |||
| 2096 | 2096 | ||
| 2097 | int | 2097 | int |
| 2098 | sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, | 2098 | sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, |
| 2099 | struct timespec *timeout, void *ignored) | 2099 | const struct timespec *timeout, const sigset_t *ignored) |
| 2100 | { | 2100 | { |
| 2101 | SELECT_TYPE orfds, owfds; | 2101 | SELECT_TYPE orfds, owfds; |
| 2102 | DWORD timeout_ms, start_time; | 2102 | DWORD timeout_ms, start_time; |
diff --git a/src/window.c b/src/window.c index e8798f1e3ee..c3e693182c6 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -6008,7 +6008,7 @@ struct save_window_data | |||
| 6008 | struct vectorlike_header header; | 6008 | struct vectorlike_header header; |
| 6009 | Lisp_Object selected_frame; | 6009 | Lisp_Object selected_frame; |
| 6010 | Lisp_Object current_window; | 6010 | Lisp_Object current_window; |
| 6011 | Lisp_Object current_buffer; | 6011 | Lisp_Object f_current_buffer; |
| 6012 | Lisp_Object minibuf_scroll_window; | 6012 | Lisp_Object minibuf_scroll_window; |
| 6013 | Lisp_Object minibuf_selected_window; | 6013 | Lisp_Object minibuf_selected_window; |
| 6014 | Lisp_Object root_window; | 6014 | Lisp_Object root_window; |
| @@ -6098,7 +6098,7 @@ the return value is nil. Otherwise the value is t. */) | |||
| 6098 | data = (struct save_window_data *) XVECTOR (configuration); | 6098 | data = (struct save_window_data *) XVECTOR (configuration); |
| 6099 | saved_windows = XVECTOR (data->saved_windows); | 6099 | saved_windows = XVECTOR (data->saved_windows); |
| 6100 | 6100 | ||
| 6101 | new_current_buffer = data->current_buffer; | 6101 | new_current_buffer = data->f_current_buffer; |
| 6102 | if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer))) | 6102 | if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer))) |
| 6103 | new_current_buffer = Qnil; | 6103 | new_current_buffer = Qnil; |
| 6104 | else | 6104 | else |
| @@ -6750,7 +6750,7 @@ saved by this function. */) | |||
| 6750 | data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); | 6750 | data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); |
| 6751 | data->selected_frame = selected_frame; | 6751 | data->selected_frame = selected_frame; |
| 6752 | data->current_window = FRAME_SELECTED_WINDOW (f); | 6752 | data->current_window = FRAME_SELECTED_WINDOW (f); |
| 6753 | XSETBUFFER (data->current_buffer, current_buffer); | 6753 | XSETBUFFER (data->f_current_buffer, current_buffer); |
| 6754 | data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil; | 6754 | data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil; |
| 6755 | data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil; | 6755 | data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil; |
| 6756 | data->root_window = FRAME_ROOT_WINDOW (f); | 6756 | data->root_window = FRAME_ROOT_WINDOW (f); |
| @@ -7205,7 +7205,7 @@ compare_window_configurations (Lisp_Object configuration1, | |||
| 7205 | || d1->frame_lines != d2->frame_lines | 7205 | || d1->frame_lines != d2->frame_lines |
| 7206 | || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines | 7206 | || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines |
| 7207 | || !EQ (d1->selected_frame, d2->selected_frame) | 7207 | || !EQ (d1->selected_frame, d2->selected_frame) |
| 7208 | || !EQ (d1->current_buffer, d2->current_buffer) | 7208 | || !EQ (d1->f_current_buffer, d2->f_current_buffer) |
| 7209 | || (!ignore_positions | 7209 | || (!ignore_positions |
| 7210 | && (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window) | 7210 | && (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window) |
| 7211 | || !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))) | 7211 | || !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))) |
diff --git a/src/xgselect.c b/src/xgselect.c index 7850a16e9c0..2f23764ae41 100644 --- a/src/xgselect.c +++ b/src/xgselect.c | |||
| @@ -54,9 +54,8 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, | |||
| 54 | int gfds_size = ARRAYELTS (gfds_buf); | 54 | int gfds_size = ARRAYELTS (gfds_buf); |
| 55 | int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1; | 55 | int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1; |
| 56 | bool context_acquired = false; | 56 | bool context_acquired = false; |
| 57 | int i, nfds, tmo_in_millisec; | 57 | int i, nfds, tmo_in_millisec, must_free = 0; |
| 58 | bool need_to_dispatch; | 58 | bool need_to_dispatch; |
| 59 | USE_SAFE_ALLOCA; | ||
| 60 | 59 | ||
| 61 | context = g_main_context_default (); | 60 | context = g_main_context_default (); |
| 62 | context_acquired = g_main_context_acquire (context); | 61 | context_acquired = g_main_context_acquire (context); |
| @@ -77,7 +76,11 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, | |||
| 77 | 76 | ||
| 78 | if (gfds_size < n_gfds) | 77 | if (gfds_size < n_gfds) |
| 79 | { | 78 | { |
| 80 | SAFE_NALLOCA (gfds, sizeof *gfds, n_gfds); | 79 | /* Avoid using SAFE_NALLOCA, as that implicitly refers to the |
| 80 | current thread. Using xnmalloc avoids thread-switching | ||
| 81 | problems here. */ | ||
| 82 | gfds = xnmalloc (n_gfds, sizeof *gfds); | ||
| 83 | must_free = 1; | ||
| 81 | gfds_size = n_gfds; | 84 | gfds_size = n_gfds; |
| 82 | n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, | 85 | n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, |
| 83 | gfds, gfds_size); | 86 | gfds, gfds_size); |
| @@ -98,7 +101,8 @@ xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, | |||
| 98 | } | 101 | } |
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | SAFE_FREE (); | 104 | if (must_free) |
| 105 | xfree (gfds); | ||
| 102 | 106 | ||
| 103 | if (n_gfds >= 0 && tmo_in_millisec >= 0) | 107 | if (n_gfds >= 0 && tmo_in_millisec >= 0) |
| 104 | { | 108 | { |