diff options
| author | Joakim Verona | 2012-12-04 01:46:34 +0100 |
|---|---|---|
| committer | Joakim Verona | 2012-12-04 01:46:34 +0100 |
| commit | d28fde00abbbf26b7c80700b1c9bc18b5079a30e (patch) | |
| tree | 3bf606901b01f67d6b2eed3998ac6fae9f4518a8 /src | |
| parent | fa8510a9aabe34d367d935b960eab0abbf060e18 (diff) | |
| parent | c38a186c2e06e0a351d166c5ef06d7307e145f45 (diff) | |
| download | emacs-d28fde00abbbf26b7c80700b1c9bc18b5079a30e.tar.gz emacs-d28fde00abbbf26b7c80700b1c9bc18b5079a30e.zip | |
auto upstream
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 134 | ||||
| -rw-r--r-- | src/alloc.c | 32 | ||||
| -rw-r--r-- | src/bytecode.c | 4 | ||||
| -rw-r--r-- | src/callproc.c | 255 | ||||
| -rw-r--r-- | src/casefiddle.c | 2 | ||||
| -rw-r--r-- | src/charset.c | 4 | ||||
| -rw-r--r-- | src/data.c | 8 | ||||
| -rw-r--r-- | src/doprnt.c | 5 | ||||
| -rw-r--r-- | src/editfns.c | 91 | ||||
| -rw-r--r-- | src/fileio.c | 2 | ||||
| -rw-r--r-- | src/gtkutil.c | 15 | ||||
| -rw-r--r-- | src/insdel.c | 21 | ||||
| -rw-r--r-- | src/lisp.h | 4 | ||||
| -rw-r--r-- | src/process.c | 151 | ||||
| -rw-r--r-- | src/process.h | 17 | ||||
| -rw-r--r-- | src/sysdep.c | 80 | ||||
| -rw-r--r-- | src/syswait.h | 7 | ||||
| -rw-r--r-- | src/textprop.c | 24 | ||||
| -rw-r--r-- | src/w32.c | 8 | ||||
| -rw-r--r-- | src/w32common.h | 2 | ||||
| -rw-r--r-- | src/w32fns.c | 5 | ||||
| -rw-r--r-- | src/w32proc.c | 28 | ||||
| -rw-r--r-- | src/xdisp.c | 29 | ||||
| -rw-r--r-- | src/xterm.c | 15 |
24 files changed, 535 insertions, 408 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index a6fabdccdea..1a91eb0f1a3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,137 @@ | |||
| 1 | 2012-12-03 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Don't let call-process be a zombie factory (Bug#12980). | ||
| 4 | Fixing this bug required some cleanup of the signal-handling code. | ||
| 5 | As a side effect, this change also fixes a longstanding rare race | ||
| 6 | condition whereby Emacs could mistakenly kill unrelated processes, | ||
| 7 | and it fixes a bug where a second C-g does not kill a recalcitrant | ||
| 8 | synchronous process in GNU/Linux and similar platforms. | ||
| 9 | The patch should also fix the last vestiges of Bug#9488, | ||
| 10 | a bug which has mostly been fixed on the trunk by other changes. | ||
| 11 | * callproc.c, process.h (synch_process_alive, synch_process_death) | ||
| 12 | (synch_process_termsig, sync_process_retcode): | ||
| 13 | Remove. All uses removed, to simplify analysis and so that | ||
| 14 | less consing is done inside critical sections. | ||
| 15 | * callproc.c (call_process_exited): Remove. All uses replaced | ||
| 16 | with !synch_process_pid. | ||
| 17 | * callproc.c (synch_process_pid, synch_process_fd): New static vars. | ||
| 18 | These take the role of what used to be in unwind-protect arg. | ||
| 19 | All uses changed. | ||
| 20 | (block_child_signal, unblock_child_signal): | ||
| 21 | New functions, to avoid races that could kill innocent-victim processes. | ||
| 22 | (call_process_kill, call_process_cleanup, Fcall_process): Use them. | ||
| 23 | (call_process_kill): Record killed processes as deleted, so that | ||
| 24 | zombies do not clutter up the system. Do this inside a critical | ||
| 25 | section, to avoid a race that would allow the clutter. | ||
| 26 | (call_process_cleanup): Fix code so that the second C-g works again | ||
| 27 | on common platforms such as GNU/Linux. | ||
| 28 | (Fcall_process): Create the child process in a critical section, | ||
| 29 | to fix a race condition. If creating an asynchronous process, | ||
| 30 | record it as deleted so that zombies do not clutter up the system. | ||
| 31 | Do unwind-protect for WINDOWSNT too, as that's simpler in the | ||
| 32 | light of these changes. Omit unnecessary call to emacs_close | ||
| 33 | before failure, as the unwind-protect code does that. | ||
| 34 | * callproc.c (call_process_cleanup): | ||
| 35 | * w32proc.c (waitpid): Simplify now that synch_process_alive is gone. | ||
| 36 | * process.c (record_deleted_pid): New function, containing | ||
| 37 | code refactored out of Fdelete_process. | ||
| 38 | (Fdelete_process): Use it. | ||
| 39 | (process_status_retrieved): Remove. All callers changed to use | ||
| 40 | child_status_change. | ||
| 41 | (record_child_status_change): Remove, folding its contents into ... | ||
| 42 | (handle_child_signal): ... this signal handler. Now, this | ||
| 43 | function is purely a handler for SIGCHLD, and is not called after | ||
| 44 | a synchronous waitpid returns; the synchronous code is moved to | ||
| 45 | wait_for_termination. There is no need to worry about reaping | ||
| 46 | more than one child now. | ||
| 47 | * sysdep.c (get_child_status, child_status_changed): New functions. | ||
| 48 | (wait_for_termination): Now takes int * status and bool | ||
| 49 | interruptible arguments, too. Do not record child status change; | ||
| 50 | that's now the caller's responsibility. All callers changed. | ||
| 51 | Reimplement in terms of get_child_status. | ||
| 52 | (wait_for_termination_1, interruptible_wait_for_termination): | ||
| 53 | Remove. All callers changed to use wait_for_termination. | ||
| 54 | * syswait.h: Include <stdbool.h>, for bool. | ||
| 55 | (record_child_status_change, interruptible_wait_for_termination): | ||
| 56 | Remove decls. | ||
| 57 | (record_deleted_pid, child_status_changed): New decls. | ||
| 58 | (wait_for_termination): Adjust to API changes noted above. | ||
| 59 | |||
| 60 | * bytecode.c, lisp.h (Qbytecode): Remove. | ||
| 61 | No longer needed after 2012-11-20 interactive-p changes. | ||
| 62 | |||
| 63 | 2012-12-03 Eli Zaretskii <eliz@gnu.org> | ||
| 64 | |||
| 65 | * xdisp.c (redisplay_window): If the cursor is visible, but inside | ||
| 66 | the scroll margin, move point outside the margin. (Bug#13055) | ||
| 67 | |||
| 68 | 2012-12-03 Jan Djärv <jan.h.d@swipnet.se> | ||
| 69 | |||
| 70 | * gtkutil.c (my_log_handler): New function. | ||
| 71 | (xg_set_geometry): Set log handler to my_log_handler (Bug#11177). | ||
| 72 | |||
| 73 | 2012-12-03 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 74 | |||
| 75 | * lisp.h (modify_region): Rename to... | ||
| 76 | (modify_region_1): ...new prototype. | ||
| 77 | * textprop.c (modify_region): Now static. Adjust users. | ||
| 78 | * insdel.c (modify_region): Rename to... | ||
| 79 | (modify_region_1): ...new function to work with current buffer. | ||
| 80 | Adjust comment and users. Use true and false for booleans. | ||
| 81 | |||
| 82 | 2012-12-03 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 83 | |||
| 84 | * alloc.c (free_save_value): New function. | ||
| 85 | (safe_alloca_unwind): Use it. | ||
| 86 | * lisp.h (free_save_value): New prototype. | ||
| 87 | * editfns.c (save_excursion_save): Use Lisp_Misc_Save_Value. | ||
| 88 | Add comment. | ||
| 89 | (save_excursion_restore): Adjust to match saved data structure. | ||
| 90 | Use free_save_value to offload some work from GC. Drop obsolete | ||
| 91 | #if 0 code. | ||
| 92 | |||
| 93 | 2012-12-03 Chong Yidong <cyd@gnu.org> | ||
| 94 | |||
| 95 | * fileio.c (Vauto_save_list_file_name): Doc fix. | ||
| 96 | |||
| 97 | 2012-12-03 Fabrice Popineau <fabrice.popineau@gmail.com> | ||
| 98 | |||
| 99 | * w32fns.c: Remove prototype of atof. | ||
| 100 | (syspage_mask): Declared DWORD_PTR, for compatibility with 64-bit | ||
| 101 | builds. | ||
| 102 | (file_dialog_callback): Declared UINT_PTR. | ||
| 103 | |||
| 104 | * w32common.h (syspage_mask): Declare DWORD_PTR, for compatibility | ||
| 105 | with 64-bit builds. | ||
| 106 | |||
| 107 | * w32.c (FILE_DEVICE_FILE_SYSTEM, METHOD_BUFFERED) | ||
| 108 | (FILE_ANY_ACCESS, CTL_CODE) [_MSC_VER]: Define only if not already | ||
| 109 | defined. | ||
| 110 | |||
| 111 | 2012-12-03 Glenn Morris <rgm@gnu.org> | ||
| 112 | |||
| 113 | * data.c (Fboundp, Fsymbol_value): Doc fix re lexical-binding. | ||
| 114 | |||
| 115 | 2012-12-02 Paul Eggert <eggert@cs.ucla.edu> | ||
| 116 | |||
| 117 | Fix xpalloc confusion after memory is exhausted. | ||
| 118 | * alloc.c (xpalloc): Comment fix. | ||
| 119 | * charset.c (Fdefine_charset_internal): If xpalloc exhausts memory | ||
| 120 | and signals an error, do not clear charset_table_size, as | ||
| 121 | charset_table is still valid. | ||
| 122 | * doprnt.c (evxprintf): Clear *BUF after freeing it. | ||
| 123 | |||
| 124 | Use execve to avoid need to munge environ (Bug#13054). | ||
| 125 | * callproc.c (Fcall_process): | ||
| 126 | * process.c (create_process): | ||
| 127 | Don't save and restore environ; no longer needed. | ||
| 128 | * callproc.c (child_setup): | ||
| 129 | Use execve, not execvp, to preserve environ. | ||
| 130 | |||
| 131 | 2012-12-01 Paul Eggert <eggert@cs.ucla.edu> | ||
| 132 | |||
| 133 | * xterm.c (x_draw_image_relief): Remove unused locals (Bug#10500). | ||
| 134 | |||
| 1 | 2012-12-01 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> | 135 | 2012-12-01 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> |
| 2 | 136 | ||
| 3 | * xterm.c (x_draw_relief_rect, x_draw_image_relief): Fix relief | 137 | * xterm.c (x_draw_relief_rect, x_draw_image_relief): Fix relief |
diff --git a/src/alloc.c b/src/alloc.c index 28c9b51dab4..0f105f87207 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -761,13 +761,17 @@ xnrealloc (void *pa, ptrdiff_t nitems, ptrdiff_t item_size) | |||
| 761 | infinity. | 761 | infinity. |
| 762 | 762 | ||
| 763 | If PA is null, then allocate a new array instead of reallocating | 763 | If PA is null, then allocate a new array instead of reallocating |
| 764 | the old one. Thus, to grow an array A without saving its old | 764 | the old one. |
| 765 | contents, invoke xfree (A) immediately followed by xgrowalloc (0, | ||
| 766 | &NITEMS, ...). | ||
| 767 | 765 | ||
| 768 | Block interrupt input as needed. If memory exhaustion occurs, set | 766 | Block interrupt input as needed. If memory exhaustion occurs, set |
| 769 | *NITEMS to zero if PA is null, and signal an error (i.e., do not | 767 | *NITEMS to zero if PA is null, and signal an error (i.e., do not |
| 770 | return). */ | 768 | return). |
| 769 | |||
| 770 | Thus, to grow an array A without saving its old contents, do | ||
| 771 | { xfree (A); A = NULL; A = xpalloc (NULL, &AITEMS, ...); }. | ||
| 772 | The A = NULL avoids a dangling pointer if xpalloc exhausts memory | ||
| 773 | and signals an error, and later this code is reexecuted and | ||
| 774 | attempts to free A. */ | ||
| 771 | 775 | ||
| 772 | void * | 776 | void * |
| 773 | xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, | 777 | xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, |
| @@ -822,12 +826,7 @@ xstrdup (const char *s) | |||
| 822 | Lisp_Object | 826 | Lisp_Object |
| 823 | safe_alloca_unwind (Lisp_Object arg) | 827 | safe_alloca_unwind (Lisp_Object arg) |
| 824 | { | 828 | { |
| 825 | register struct Lisp_Save_Value *p = XSAVE_VALUE (arg); | 829 | free_save_value (arg); |
| 826 | |||
| 827 | p->dogc = 0; | ||
| 828 | xfree (p->pointer); | ||
| 829 | p->pointer = 0; | ||
| 830 | free_misc (arg); | ||
| 831 | return Qnil; | 830 | return Qnil; |
| 832 | } | 831 | } |
| 833 | 832 | ||
| @@ -3361,6 +3360,19 @@ make_save_value (void *pointer, ptrdiff_t integer) | |||
| 3361 | return val; | 3360 | return val; |
| 3362 | } | 3361 | } |
| 3363 | 3362 | ||
| 3363 | /* Free a Lisp_Misc_Save_Value object. */ | ||
| 3364 | |||
| 3365 | void | ||
| 3366 | free_save_value (Lisp_Object save) | ||
| 3367 | { | ||
| 3368 | register struct Lisp_Save_Value *p = XSAVE_VALUE (save); | ||
| 3369 | |||
| 3370 | p->dogc = 0; | ||
| 3371 | xfree (p->pointer); | ||
| 3372 | p->pointer = NULL; | ||
| 3373 | free_misc (save); | ||
| 3374 | } | ||
| 3375 | |||
| 3364 | /* Return a Lisp_Misc_Overlay object with specified START, END and PLIST. */ | 3376 | /* Return a Lisp_Misc_Overlay object with specified START, END and PLIST. */ |
| 3365 | 3377 | ||
| 3366 | Lisp_Object | 3378 | Lisp_Object |
diff --git a/src/bytecode.c b/src/bytecode.c index 3267c7c8c76..4c5ac151de1 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -87,8 +87,6 @@ Lisp_Object Qbyte_code_meter; | |||
| 87 | #endif /* BYTE_CODE_METER */ | 87 | #endif /* BYTE_CODE_METER */ |
| 88 | 88 | ||
| 89 | 89 | ||
| 90 | Lisp_Object Qbytecode; | ||
| 91 | |||
| 92 | /* Byte codes: */ | 90 | /* Byte codes: */ |
| 93 | 91 | ||
| 94 | #define BYTE_CODES \ | 92 | #define BYTE_CODES \ |
| @@ -1963,8 +1961,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1963 | void | 1961 | void |
| 1964 | syms_of_bytecode (void) | 1962 | syms_of_bytecode (void) |
| 1965 | { | 1963 | { |
| 1966 | DEFSYM (Qbytecode, "byte-code"); | ||
| 1967 | |||
| 1968 | defsubr (&Sbyte_code); | 1964 | defsubr (&Sbyte_code); |
| 1969 | 1965 | ||
| 1970 | #ifdef BYTE_CODE_METER | 1966 | #ifdef BYTE_CODE_METER |
diff --git a/src/callproc.c b/src/callproc.c index 167663a45c6..21c52d09e6b 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -67,88 +67,110 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 67 | /* Pattern used by call-process-region to make temp files. */ | 67 | /* Pattern used by call-process-region to make temp files. */ |
| 68 | static Lisp_Object Vtemp_file_name_pattern; | 68 | static Lisp_Object Vtemp_file_name_pattern; |
| 69 | 69 | ||
| 70 | /* True if we are about to fork off a synchronous process or if we | 70 | /* The next two variables are valid only while record-unwind-protect |
| 71 | are waiting for it. */ | 71 | is in place during call-process for a synchronous subprocess. At |
| 72 | bool synch_process_alive; | 72 | other times, their contents are irrelevant. Doing this via static |
| 73 | 73 | C variables is more convenient than putting them into the arguments | |
| 74 | /* Nonzero => this is a string explaining death of synchronous subprocess. */ | 74 | of record-unwind-protect, as they need to be updated at randomish |
| 75 | const char *synch_process_death; | 75 | times in the code, and Lisp cannot always store these values as |
| 76 | Emacs integers. It's safe to use static variables here, as the | ||
| 77 | code is never invoked reentrantly. */ | ||
| 78 | |||
| 79 | /* If nonzero, a process-ID that has not been reaped. */ | ||
| 80 | static pid_t synch_process_pid; | ||
| 81 | |||
| 82 | /* If nonnegative, a file descriptor that has not been closed. */ | ||
| 83 | static int synch_process_fd; | ||
| 84 | |||
| 85 | /* Block SIGCHLD. */ | ||
| 76 | 86 | ||
| 77 | /* Nonzero => this is the signal number that terminated the subprocess. */ | 87 | static void |
| 78 | int synch_process_termsig; | 88 | block_child_signal (void) |
| 89 | { | ||
| 90 | #ifdef SIGCHLD | ||
| 91 | sigset_t blocked; | ||
| 92 | sigemptyset (&blocked); | ||
| 93 | sigaddset (&blocked, SIGCHLD); | ||
| 94 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 95 | #endif | ||
| 96 | } | ||
| 79 | 97 | ||
| 80 | /* If synch_process_death is zero, | 98 | /* Unblock SIGCHLD. */ |
| 81 | this is exit code of synchronous subprocess. */ | ||
| 82 | int synch_process_retcode; | ||
| 83 | 99 | ||
| 84 | 100 | static void | |
| 85 | /* Clean up when exiting Fcall_process. | 101 | unblock_child_signal (void) |
| 86 | On MSDOS, delete the temporary file on any kind of termination. | 102 | { |
| 87 | On Unix, kill the process and any children on termination by signal. */ | 103 | #ifdef SIGCHLD |
| 104 | pthread_sigmask (SIG_SETMASK, &empty_mask, 0); | ||
| 105 | #endif | ||
| 106 | } | ||
| 88 | 107 | ||
| 89 | /* True if this is termination due to exit. */ | 108 | /* Clean up when exiting call_process_cleanup. */ |
| 90 | static bool call_process_exited; | ||
| 91 | 109 | ||
| 92 | static Lisp_Object | 110 | static Lisp_Object |
| 93 | call_process_kill (Lisp_Object fdpid) | 111 | call_process_kill (Lisp_Object ignored) |
| 94 | { | 112 | { |
| 95 | int fd; | 113 | if (0 <= synch_process_fd) |
| 96 | pid_t pid; | 114 | emacs_close (synch_process_fd); |
| 97 | CONS_TO_INTEGER (Fcar (fdpid), int, fd); | 115 | |
| 98 | CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid); | 116 | /* If PID is reapable, kill it and record it as a deleted process. |
| 99 | emacs_close (fd); | 117 | Do this in a critical section. Unless PID is wedged it will be |
| 100 | EMACS_KILLPG (pid, SIGKILL); | 118 | reaped on receipt of the first SIGCHLD after the critical section. */ |
| 101 | synch_process_alive = 0; | 119 | if (synch_process_pid) |
| 120 | { | ||
| 121 | block_child_signal (); | ||
| 122 | record_deleted_pid (synch_process_pid); | ||
| 123 | EMACS_KILLPG (synch_process_pid, SIGKILL); | ||
| 124 | unblock_child_signal (); | ||
| 125 | } | ||
| 126 | |||
| 102 | return Qnil; | 127 | return Qnil; |
| 103 | } | 128 | } |
| 104 | 129 | ||
| 130 | /* Clean up when exiting Fcall_process. | ||
| 131 | On MSDOS, delete the temporary file on any kind of termination. | ||
| 132 | On Unix, kill the process and any children on termination by signal. */ | ||
| 133 | |||
| 105 | static Lisp_Object | 134 | static Lisp_Object |
| 106 | call_process_cleanup (Lisp_Object arg) | 135 | call_process_cleanup (Lisp_Object arg) |
| 107 | { | 136 | { |
| 108 | Lisp_Object fdpid = Fcdr (arg); | 137 | #ifdef MSDOS |
| 109 | int fd; | 138 | Lisp_Object buffer = Fcar (arg); |
| 110 | #if defined (MSDOS) | 139 | Lisp_Object file = Fcdr (arg); |
| 111 | Lisp_Object file; | ||
| 112 | #else | 140 | #else |
| 113 | pid_t pid; | 141 | Lisp_Object buffer = arg; |
| 114 | #endif | 142 | #endif |
| 115 | 143 | ||
| 116 | Fset_buffer (Fcar (arg)); | 144 | Fset_buffer (buffer); |
| 117 | CONS_TO_INTEGER (Fcar (fdpid), int, fd); | ||
| 118 | |||
| 119 | #if defined (MSDOS) | ||
| 120 | /* for MSDOS fdpid is really (fd . tempfile) */ | ||
| 121 | file = Fcdr (fdpid); | ||
| 122 | /* FD is -1 and FILE is "" when we didn't actually create a | ||
| 123 | temporary file in call-process. */ | ||
| 124 | if (fd >= 0) | ||
| 125 | emacs_close (fd); | ||
| 126 | if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0')) | ||
| 127 | unlink (SDATA (file)); | ||
| 128 | #else /* not MSDOS */ | ||
| 129 | CONS_TO_INTEGER (Fcdr (fdpid), pid_t, pid); | ||
| 130 | |||
| 131 | if (call_process_exited) | ||
| 132 | { | ||
| 133 | emacs_close (fd); | ||
| 134 | return Qnil; | ||
| 135 | } | ||
| 136 | 145 | ||
| 137 | if (EMACS_KILLPG (pid, SIGINT) == 0) | 146 | #ifndef MSDOS |
| 147 | /* If the process still exists, kill its process group. */ | ||
| 148 | if (synch_process_pid) | ||
| 138 | { | 149 | { |
| 139 | ptrdiff_t count = SPECPDL_INDEX (); | 150 | ptrdiff_t count = SPECPDL_INDEX (); |
| 140 | record_unwind_protect (call_process_kill, fdpid); | 151 | EMACS_KILLPG (synch_process_pid, SIGINT); |
| 152 | record_unwind_protect (call_process_kill, make_number (0)); | ||
| 141 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); | 153 | message1 ("Waiting for process to die...(type C-g again to kill it instantly)"); |
| 142 | immediate_quit = 1; | 154 | immediate_quit = 1; |
| 143 | QUIT; | 155 | QUIT; |
| 144 | wait_for_termination (pid); | 156 | wait_for_termination (synch_process_pid, 0, 1); |
| 157 | synch_process_pid = 0; | ||
| 145 | immediate_quit = 0; | 158 | immediate_quit = 0; |
| 146 | specpdl_ptr = specpdl + count; /* Discard the unwind protect. */ | 159 | specpdl_ptr = specpdl + count; /* Discard the unwind protect. */ |
| 147 | message1 ("Waiting for process to die...done"); | 160 | message1 ("Waiting for process to die...done"); |
| 148 | } | 161 | } |
| 149 | synch_process_alive = 0; | 162 | #endif |
| 150 | emacs_close (fd); | 163 | |
| 151 | #endif /* not MSDOS */ | 164 | if (0 <= synch_process_fd) |
| 165 | emacs_close (synch_process_fd); | ||
| 166 | |||
| 167 | #ifdef MSDOS | ||
| 168 | /* FILE is "" when we didn't actually create a temporary file in | ||
| 169 | call-process. */ | ||
| 170 | if (!(strcmp (SDATA (file), NULL_DEVICE) == 0 || SREF (file, 0) == '\0')) | ||
| 171 | unlink (SDATA (file)); | ||
| 172 | #endif | ||
| 173 | |||
| 152 | return Qnil; | 174 | return Qnil; |
| 153 | } | 175 | } |
| 154 | 176 | ||
| @@ -181,9 +203,10 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. | |||
| 181 | usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | 203 | usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) |
| 182 | (ptrdiff_t nargs, Lisp_Object *args) | 204 | (ptrdiff_t nargs, Lisp_Object *args) |
| 183 | { | 205 | { |
| 184 | Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail; | 206 | Lisp_Object infile, buffer, current_dir, path; |
| 185 | bool display_p; | 207 | bool display_p; |
| 186 | int fd0, fd1, filefd; | 208 | int fd0, fd1, filefd; |
| 209 | int status; | ||
| 187 | ptrdiff_t count = SPECPDL_INDEX (); | 210 | ptrdiff_t count = SPECPDL_INDEX (); |
| 188 | USE_SAFE_ALLOCA; | 211 | USE_SAFE_ALLOCA; |
| 189 | 212 | ||
| @@ -199,7 +222,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 199 | #else | 222 | #else |
| 200 | pid_t pid; | 223 | pid_t pid; |
| 201 | #endif | 224 | #endif |
| 202 | int vfork_errno; | 225 | int child_errno; |
| 203 | int fd_output = -1; | 226 | int fd_output = -1; |
| 204 | struct coding_system process_coding; /* coding-system of process output */ | 227 | struct coding_system process_coding; /* coding-system of process output */ |
| 205 | struct coding_system argument_coding; /* coding-system of arguments */ | 228 | struct coding_system argument_coding; /* coding-system of arguments */ |
| @@ -488,24 +511,11 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 488 | } | 511 | } |
| 489 | 512 | ||
| 490 | { | 513 | { |
| 491 | /* child_setup must clobber environ in systems with true vfork. | ||
| 492 | Protect it from permanent change. */ | ||
| 493 | char **save_environ = environ; | ||
| 494 | int fd_error = fd1; | 514 | int fd_error = fd1; |
| 495 | 515 | ||
| 496 | if (fd_output >= 0) | 516 | if (fd_output >= 0) |
| 497 | fd1 = fd_output; | 517 | fd1 = fd_output; |
| 498 | 518 | ||
| 499 | /* Record that we're about to create a synchronous process. */ | ||
| 500 | synch_process_alive = 1; | ||
| 501 | |||
| 502 | /* These vars record information from process termination. | ||
| 503 | Clear them now before process can possibly terminate, | ||
| 504 | to avoid timing error if process terminates soon. */ | ||
| 505 | synch_process_death = 0; | ||
| 506 | synch_process_retcode = 0; | ||
| 507 | synch_process_termsig = 0; | ||
| 508 | |||
| 509 | if (NILP (error_file)) | 519 | if (NILP (error_file)) |
| 510 | fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); | 520 | fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); |
| 511 | else if (STRINGP (error_file)) | 521 | else if (STRINGP (error_file)) |
| @@ -538,23 +548,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 538 | 548 | ||
| 539 | #ifdef MSDOS /* MW, July 1993 */ | 549 | #ifdef MSDOS /* MW, July 1993 */ |
| 540 | /* Note that on MSDOS `child_setup' actually returns the child process | 550 | /* Note that on MSDOS `child_setup' actually returns the child process |
| 541 | exit status, not its PID, so we assign it to `synch_process_retcode' | 551 | exit status, not its PID, so assign it to status below. */ |
| 542 | below. */ | ||
| 543 | pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); | 552 | pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); |
| 544 | 553 | child_errno = errno; | |
| 545 | /* Record that the synchronous process exited and note its | ||
| 546 | termination status. */ | ||
| 547 | synch_process_alive = 0; | ||
| 548 | synch_process_retcode = pid; | ||
| 549 | if (synch_process_retcode < 0) /* means it couldn't be exec'ed */ | ||
| 550 | { | ||
| 551 | synchronize_system_messages_locale (); | ||
| 552 | synch_process_death = strerror (errno); | ||
| 553 | } | ||
| 554 | 554 | ||
| 555 | emacs_close (outfilefd); | 555 | emacs_close (outfilefd); |
| 556 | if (fd_error != outfilefd) | 556 | if (fd_error != outfilefd) |
| 557 | emacs_close (fd_error); | 557 | emacs_close (fd_error); |
| 558 | if (pid < 0) | ||
| 559 | { | ||
| 560 | synchronize_system_messages_locale (); | ||
| 561 | return | ||
| 562 | code_convert_string_norecord (build_string (strerror (child_errno)), | ||
| 563 | Vlocale_coding_system, 0); | ||
| 564 | } | ||
| 565 | status = pid; | ||
| 558 | fd1 = -1; /* No harm in closing that one! */ | 566 | fd1 = -1; /* No harm in closing that one! */ |
| 559 | if (tempfile) | 567 | if (tempfile) |
| 560 | { | 568 | { |
| @@ -572,12 +580,21 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 572 | else | 580 | else |
| 573 | fd0 = -1; /* We are not going to read from tempfile. */ | 581 | fd0 = -1; /* We are not going to read from tempfile. */ |
| 574 | #else /* not MSDOS */ | 582 | #else /* not MSDOS */ |
| 583 | |||
| 584 | /* Do the unwind-protect now, even though the pid is not known, so | ||
| 585 | that no storage allocation is done in the critical section. | ||
| 586 | The actual PID will be filled in during the critical section. */ | ||
| 587 | synch_process_pid = 0; | ||
| 588 | synch_process_fd = fd0; | ||
| 589 | record_unwind_protect (call_process_cleanup, Fcurrent_buffer ()); | ||
| 590 | |||
| 591 | block_input (); | ||
| 592 | block_child_signal (); | ||
| 593 | |||
| 575 | #ifdef WINDOWSNT | 594 | #ifdef WINDOWSNT |
| 576 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 595 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 577 | #else /* not WINDOWSNT */ | 596 | #else /* not WINDOWSNT */ |
| 578 | 597 | ||
| 579 | block_input (); | ||
| 580 | |||
| 581 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 598 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| 582 | { | 599 | { |
| 583 | Lisp_Object volatile buffer_volatile = buffer; | 600 | Lisp_Object volatile buffer_volatile = buffer; |
| @@ -594,9 +611,9 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 594 | ptrdiff_t volatile count_volatile = count; | 611 | ptrdiff_t volatile count_volatile = count; |
| 595 | ptrdiff_t volatile sa_count_volatile = sa_count; | 612 | ptrdiff_t volatile sa_count_volatile = sa_count; |
| 596 | char **volatile new_argv_volatile = new_argv; | 613 | char **volatile new_argv_volatile = new_argv; |
| 597 | char **volatile new_save_environ = save_environ; | ||
| 598 | 614 | ||
| 599 | pid = vfork (); | 615 | pid = vfork (); |
| 616 | child_errno = errno; | ||
| 600 | 617 | ||
| 601 | buffer = buffer_volatile; | 618 | buffer = buffer_volatile; |
| 602 | coding_systems = coding_systems_volatile; | 619 | coding_systems = coding_systems_volatile; |
| @@ -612,11 +629,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 612 | count = count_volatile; | 629 | count = count_volatile; |
| 613 | sa_count = sa_count_volatile; | 630 | sa_count = sa_count_volatile; |
| 614 | new_argv = new_argv_volatile; | 631 | new_argv = new_argv_volatile; |
| 615 | save_environ = new_save_environ; | ||
| 616 | } | 632 | } |
| 617 | 633 | ||
| 618 | if (pid == 0) | 634 | if (pid == 0) |
| 619 | { | 635 | { |
| 636 | unblock_child_signal (); | ||
| 637 | |||
| 620 | if (fd0 >= 0) | 638 | if (fd0 >= 0) |
| 621 | emacs_close (fd0); | 639 | emacs_close (fd0); |
| 622 | 640 | ||
| @@ -628,18 +646,26 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 628 | child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 646 | child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 629 | } | 647 | } |
| 630 | 648 | ||
| 631 | vfork_errno = errno; | ||
| 632 | unblock_input (); | ||
| 633 | |||
| 634 | #endif /* not WINDOWSNT */ | 649 | #endif /* not WINDOWSNT */ |
| 635 | 650 | ||
| 651 | child_errno = errno; | ||
| 652 | |||
| 653 | if (0 < pid) | ||
| 654 | { | ||
| 655 | if (INTEGERP (buffer)) | ||
| 656 | record_deleted_pid (pid); | ||
| 657 | else | ||
| 658 | synch_process_pid = pid; | ||
| 659 | } | ||
| 660 | |||
| 661 | unblock_child_signal (); | ||
| 662 | unblock_input (); | ||
| 663 | |||
| 636 | /* The MSDOS case did this already. */ | 664 | /* The MSDOS case did this already. */ |
| 637 | if (fd_error >= 0) | 665 | if (fd_error >= 0) |
| 638 | emacs_close (fd_error); | 666 | emacs_close (fd_error); |
| 639 | #endif /* not MSDOS */ | 667 | #endif /* not MSDOS */ |
| 640 | 668 | ||
| 641 | environ = save_environ; | ||
| 642 | |||
| 643 | /* Close most of our file descriptors, but not fd0 | 669 | /* Close most of our file descriptors, but not fd0 |
| 644 | since we will use that to read input from. */ | 670 | since we will use that to read input from. */ |
| 645 | emacs_close (filefd); | 671 | emacs_close (filefd); |
| @@ -651,9 +677,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 651 | 677 | ||
| 652 | if (pid < 0) | 678 | if (pid < 0) |
| 653 | { | 679 | { |
| 654 | if (fd0 >= 0) | 680 | errno = child_errno; |
| 655 | emacs_close (fd0); | ||
| 656 | errno = vfork_errno; | ||
| 657 | report_file_error ("Doing vfork", Qnil); | 681 | report_file_error ("Doing vfork", Qnil); |
| 658 | } | 682 | } |
| 659 | 683 | ||
| @@ -664,19 +688,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 664 | return Qnil; | 688 | return Qnil; |
| 665 | } | 689 | } |
| 666 | 690 | ||
| 667 | /* Enable sending signal if user quits below. */ | ||
| 668 | call_process_exited = 0; | ||
| 669 | |||
| 670 | #if defined (MSDOS) | 691 | #if defined (MSDOS) |
| 671 | /* MSDOS needs different cleanup information. */ | 692 | /* MSDOS needs different cleanup information. */ |
| 672 | cleanup_info_tail = build_string (tempfile ? tempfile : ""); | ||
| 673 | #else | ||
| 674 | cleanup_info_tail = INTEGER_TO_CONS (pid); | ||
| 675 | #endif /* not MSDOS */ | ||
| 676 | record_unwind_protect (call_process_cleanup, | 693 | record_unwind_protect (call_process_cleanup, |
| 677 | Fcons (Fcurrent_buffer (), | 694 | Fcons (Fcurrent_buffer (), |
| 678 | Fcons (INTEGER_TO_CONS (fd0), | 695 | build_string (tempfile ? tempfile : ""))); |
| 679 | cleanup_info_tail))); | 696 | #endif |
| 680 | 697 | ||
| 681 | if (BUFFERP (buffer)) | 698 | if (BUFFERP (buffer)) |
| 682 | Fset_buffer (buffer); | 699 | Fset_buffer (buffer); |
| @@ -863,38 +880,34 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 863 | 880 | ||
| 864 | #ifndef MSDOS | 881 | #ifndef MSDOS |
| 865 | /* Wait for it to terminate, unless it already has. */ | 882 | /* Wait for it to terminate, unless it already has. */ |
| 866 | if (output_to_buffer) | 883 | wait_for_termination (pid, &status, !output_to_buffer); |
| 867 | wait_for_termination (pid); | ||
| 868 | else | ||
| 869 | interruptible_wait_for_termination (pid); | ||
| 870 | #endif | 884 | #endif |
| 871 | 885 | ||
| 872 | immediate_quit = 0; | 886 | immediate_quit = 0; |
| 873 | 887 | ||
| 874 | /* Don't kill any children that the subprocess may have left behind | 888 | /* Don't kill any children that the subprocess may have left behind |
| 875 | when exiting. */ | 889 | when exiting. */ |
| 876 | call_process_exited = 1; | 890 | synch_process_pid = 0; |
| 877 | 891 | ||
| 878 | SAFE_FREE (); | 892 | SAFE_FREE (); |
| 879 | unbind_to (count, Qnil); | 893 | unbind_to (count, Qnil); |
| 880 | 894 | ||
| 881 | if (synch_process_termsig) | 895 | if (WIFSIGNALED (status)) |
| 882 | { | 896 | { |
| 883 | const char *signame; | 897 | const char *signame; |
| 884 | 898 | ||
| 885 | synchronize_system_messages_locale (); | 899 | synchronize_system_messages_locale (); |
| 886 | signame = strsignal (synch_process_termsig); | 900 | signame = strsignal (WTERMSIG (status)); |
| 887 | 901 | ||
| 888 | if (signame == 0) | 902 | if (signame == 0) |
| 889 | signame = "unknown"; | 903 | signame = "unknown"; |
| 890 | 904 | ||
| 891 | synch_process_death = signame; | 905 | return code_convert_string_norecord (build_string (signame), |
| 906 | Vlocale_coding_system, 0); | ||
| 892 | } | 907 | } |
| 893 | 908 | ||
| 894 | if (synch_process_death) | 909 | eassert (WIFEXITED (status)); |
| 895 | return code_convert_string_norecord (build_string (synch_process_death), | 910 | return make_number (WEXITSTATUS (status)); |
| 896 | Vlocale_coding_system, 0); | ||
| 897 | return make_number (synch_process_retcode); | ||
| 898 | } | 911 | } |
| 899 | 912 | ||
| 900 | static Lisp_Object | 913 | static Lisp_Object |
| @@ -1092,10 +1105,6 @@ add_env (char **env, char **new_env, char *string) | |||
| 1092 | Initialize inferior's priority, pgrp, connected dir and environment. | 1105 | Initialize inferior's priority, pgrp, connected dir and environment. |
| 1093 | then exec another program based on new_argv. | 1106 | then exec another program based on new_argv. |
| 1094 | 1107 | ||
| 1095 | This function may change environ for the superior process. | ||
| 1096 | Therefore, the superior process must save and restore the value | ||
| 1097 | of environ around the vfork and the call to this function. | ||
| 1098 | |||
| 1099 | If SET_PGRP, put the subprocess into a separate process group. | 1108 | If SET_PGRP, put the subprocess into a separate process group. |
| 1100 | 1109 | ||
| 1101 | CURRENT_DIR is an elisp string giving the path of the current | 1110 | CURRENT_DIR is an elisp string giving the path of the current |
| @@ -1298,11 +1307,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, | |||
| 1298 | setpgid (0, 0); | 1307 | setpgid (0, 0); |
| 1299 | tcsetpgrp (0, pid); | 1308 | tcsetpgrp (0, pid); |
| 1300 | 1309 | ||
| 1301 | /* execvp does not accept an environment arg so the only way | 1310 | execve (new_argv[0], new_argv, env); |
| 1302 | to pass this environment is to set environ. Our caller | ||
| 1303 | is responsible for restoring the ambient value of environ. */ | ||
| 1304 | environ = env; | ||
| 1305 | execvp (new_argv[0], new_argv); | ||
| 1306 | 1311 | ||
| 1307 | emacs_write (1, "Can't exec program: ", 20); | 1312 | emacs_write (1, "Can't exec program: ", 20); |
| 1308 | emacs_write (1, new_argv[0], strlen (new_argv[0])); | 1313 | emacs_write (1, new_argv[0], strlen (new_argv[0])); |
diff --git a/src/casefiddle.c b/src/casefiddle.c index e3654627576..d9c6a078973 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c | |||
| @@ -213,7 +213,7 @@ casify_region (enum case_action flag, Lisp_Object b, Lisp_Object e) | |||
| 213 | validate_region (&b, &e); | 213 | validate_region (&b, &e); |
| 214 | start = XFASTINT (b); | 214 | start = XFASTINT (b); |
| 215 | end = XFASTINT (e); | 215 | end = XFASTINT (e); |
| 216 | modify_region (current_buffer, start, end, 0); | 216 | modify_region_1 (start, end, false); |
| 217 | record_change (start, end - start); | 217 | record_change (start, end - start); |
| 218 | start_byte = CHAR_TO_BYTE (start); | 218 | start_byte = CHAR_TO_BYTE (start); |
| 219 | 219 | ||
diff --git a/src/charset.c b/src/charset.c index c9133c780e8..43be0e9c780 100644 --- a/src/charset.c +++ b/src/charset.c | |||
| @@ -1142,12 +1142,14 @@ usage: (define-charset-internal ...) */) | |||
| 1142 | example, the IDs are stuffed into struct | 1142 | example, the IDs are stuffed into struct |
| 1143 | coding_system.charbuf[i] entries, which are 'int'. */ | 1143 | coding_system.charbuf[i] entries, which are 'int'. */ |
| 1144 | int old_size = charset_table_size; | 1144 | int old_size = charset_table_size; |
| 1145 | ptrdiff_t new_size = old_size; | ||
| 1145 | struct charset *new_table = | 1146 | struct charset *new_table = |
| 1146 | xpalloc (0, &charset_table_size, 1, | 1147 | xpalloc (0, &new_size, 1, |
| 1147 | min (INT_MAX, MOST_POSITIVE_FIXNUM), | 1148 | min (INT_MAX, MOST_POSITIVE_FIXNUM), |
| 1148 | sizeof *charset_table); | 1149 | sizeof *charset_table); |
| 1149 | memcpy (new_table, charset_table, old_size * sizeof *new_table); | 1150 | memcpy (new_table, charset_table, old_size * sizeof *new_table); |
| 1150 | charset_table = new_table; | 1151 | charset_table = new_table; |
| 1152 | charset_table_size = new_size; | ||
| 1151 | /* FIXME: This leaks memory, as the old charset_table becomes | 1153 | /* FIXME: This leaks memory, as the old charset_table becomes |
| 1152 | unreachable. If the old charset table is charset_table_init | 1154 | unreachable. If the old charset table is charset_table_init |
| 1153 | then this leak is intentional; otherwise, it's unclear. | 1155 | then this leak is intentional; otherwise, it's unclear. |
diff --git a/src/data.c b/src/data.c index 5fc6afaaa03..a72fa3e2b5f 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -506,7 +506,9 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0, | |||
| 506 | /* Extract and set components of symbols. */ | 506 | /* Extract and set components of symbols. */ |
| 507 | 507 | ||
| 508 | DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0, | 508 | DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0, |
| 509 | doc: /* Return t if SYMBOL's value is not void. */) | 509 | doc: /* Return t if SYMBOL's value is not void. |
| 510 | Note that if `lexical-binding' is in effect, this refers to the | ||
| 511 | global value outside of any lexical scope. */) | ||
| 510 | (register Lisp_Object symbol) | 512 | (register Lisp_Object symbol) |
| 511 | { | 513 | { |
| 512 | Lisp_Object valcontents; | 514 | Lisp_Object valcontents; |
| @@ -1047,7 +1049,9 @@ find_symbol_value (Lisp_Object symbol) | |||
| 1047 | } | 1049 | } |
| 1048 | 1050 | ||
| 1049 | DEFUN ("symbol-value", Fsymbol_value, Ssymbol_value, 1, 1, 0, | 1051 | DEFUN ("symbol-value", Fsymbol_value, Ssymbol_value, 1, 1, 0, |
| 1050 | doc: /* Return SYMBOL's value. Error if that is void. */) | 1052 | doc: /* Return SYMBOL's value. Error if that is void. |
| 1053 | Note that if `lexical-binding' is in effect, this returns the | ||
| 1054 | global value outside of any lexical scope. */) | ||
| 1051 | (Lisp_Object symbol) | 1055 | (Lisp_Object symbol) |
| 1052 | { | 1056 | { |
| 1053 | Lisp_Object val; | 1057 | Lisp_Object val; |
diff --git a/src/doprnt.c b/src/doprnt.c index caa56d6ae88..8cab219aafa 100644 --- a/src/doprnt.c +++ b/src/doprnt.c | |||
| @@ -521,7 +521,10 @@ evxprintf (char **buf, ptrdiff_t *bufsize, | |||
| 521 | if (nbytes < *bufsize - 1) | 521 | if (nbytes < *bufsize - 1) |
| 522 | return nbytes; | 522 | return nbytes; |
| 523 | if (*buf != nonheapbuf) | 523 | if (*buf != nonheapbuf) |
| 524 | xfree (*buf); | 524 | { |
| 525 | xfree (*buf); | ||
| 526 | *buf = NULL; | ||
| 527 | } | ||
| 525 | *buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1); | 528 | *buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1); |
| 526 | } | 529 | } |
| 527 | } | 530 | } |
diff --git a/src/editfns.c b/src/editfns.c index 8122ffdd0d4..d60f417e561 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -813,38 +813,43 @@ This function does not move point. */) | |||
| 813 | Qnil, Qt, Qnil); | 813 | Qnil, Qt, Qnil); |
| 814 | } | 814 | } |
| 815 | 815 | ||
| 816 | 816 | /* Save current buffer state for `save-excursion' special form. | |
| 817 | We (ab)use Lisp_Misc_Save_Value to allow explicit free and so | ||
| 818 | offload some work from GC. */ | ||
| 819 | |||
| 817 | Lisp_Object | 820 | Lisp_Object |
| 818 | save_excursion_save (void) | 821 | save_excursion_save (void) |
| 819 | { | 822 | { |
| 820 | bool visible = (XBUFFER (XWINDOW (selected_window)->buffer) | 823 | Lisp_Object save, *data = xmalloc (word_size * 4); |
| 821 | == current_buffer); | 824 | |
| 825 | data[0] = Fpoint_marker (); | ||
| 822 | /* Do not copy the mark if it points to nowhere. */ | 826 | /* Do not copy the mark if it points to nowhere. */ |
| 823 | Lisp_Object mark = (XMARKER (BVAR (current_buffer, mark))->buffer | 827 | data[1] = (XMARKER (BVAR (current_buffer, mark))->buffer |
| 824 | ? Fcopy_marker (BVAR (current_buffer, mark), Qnil) | 828 | ? Fcopy_marker (BVAR (current_buffer, mark), Qnil) |
| 825 | : Qnil); | 829 | : Qnil); |
| 826 | 830 | /* Selected window if current buffer is shown in it, nil otherwise. */ | |
| 827 | return Fcons (Fpoint_marker (), | 831 | data[2] = ((XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) |
| 828 | Fcons (mark, | 832 | ? selected_window : Qnil); |
| 829 | Fcons (visible ? Qt : Qnil, | 833 | data[3] = BVAR (current_buffer, mark_active); |
| 830 | Fcons (BVAR (current_buffer, mark_active), | 834 | |
| 831 | selected_window)))); | 835 | save = make_save_value (data, 4); |
| 836 | XSAVE_VALUE (save)->dogc = 1; | ||
| 837 | return save; | ||
| 832 | } | 838 | } |
| 833 | 839 | ||
| 840 | /* Restore saved buffer before leaving `save-excursion' special form. */ | ||
| 841 | |||
| 834 | Lisp_Object | 842 | Lisp_Object |
| 835 | save_excursion_restore (Lisp_Object info) | 843 | save_excursion_restore (Lisp_Object info) |
| 836 | { | 844 | { |
| 837 | Lisp_Object tem, tem1, omark, nmark; | 845 | Lisp_Object tem, tem1, omark, nmark, *data = XSAVE_VALUE (info)->pointer; |
| 838 | struct gcpro gcpro1, gcpro2, gcpro3; | 846 | struct gcpro gcpro1, gcpro2, gcpro3; |
| 839 | bool visible_p; | ||
| 840 | 847 | ||
| 841 | tem = Fmarker_buffer (XCAR (info)); | 848 | tem = Fmarker_buffer (data[0]); |
| 842 | /* If buffer being returned to is now deleted, avoid error */ | 849 | /* If we're unwinding to top level, saved buffer may be deleted. This |
| 843 | /* Otherwise could get error here while unwinding to top level | 850 | means that all of its markers are unchained and so tem is nil. */ |
| 844 | and crash */ | ||
| 845 | /* In that case, Fmarker_buffer returns nil now. */ | ||
| 846 | if (NILP (tem)) | 851 | if (NILP (tem)) |
| 847 | return Qnil; | 852 | goto out; |
| 848 | 853 | ||
| 849 | omark = nmark = Qnil; | 854 | omark = nmark = Qnil; |
| 850 | GCPRO3 (info, omark, nmark); | 855 | GCPRO3 (info, omark, nmark); |
| @@ -852,13 +857,12 @@ save_excursion_restore (Lisp_Object info) | |||
| 852 | Fset_buffer (tem); | 857 | Fset_buffer (tem); |
| 853 | 858 | ||
| 854 | /* Point marker. */ | 859 | /* Point marker. */ |
| 855 | tem = XCAR (info); | 860 | tem = data[0]; |
| 856 | Fgoto_char (tem); | 861 | Fgoto_char (tem); |
| 857 | unchain_marker (XMARKER (tem)); | 862 | unchain_marker (XMARKER (tem)); |
| 858 | 863 | ||
| 859 | /* Mark marker. */ | 864 | /* Mark marker. */ |
| 860 | info = XCDR (info); | 865 | tem = data[1]; |
| 861 | tem = XCAR (info); | ||
| 862 | omark = Fmarker_position (BVAR (current_buffer, mark)); | 866 | omark = Fmarker_position (BVAR (current_buffer, mark)); |
| 863 | if (NILP (tem)) | 867 | if (NILP (tem)) |
| 864 | unchain_marker (XMARKER (BVAR (current_buffer, mark))); | 868 | unchain_marker (XMARKER (BVAR (current_buffer, mark))); |
| @@ -869,23 +873,8 @@ save_excursion_restore (Lisp_Object info) | |||
| 869 | unchain_marker (XMARKER (tem)); | 873 | unchain_marker (XMARKER (tem)); |
| 870 | } | 874 | } |
| 871 | 875 | ||
| 872 | /* visible */ | 876 | /* Mark active. */ |
| 873 | info = XCDR (info); | 877 | tem = data[3]; |
| 874 | visible_p = !NILP (XCAR (info)); | ||
| 875 | |||
| 876 | #if 0 /* We used to make the current buffer visible in the selected window | ||
| 877 | if that was true previously. That avoids some anomalies. | ||
| 878 | But it creates others, and it wasn't documented, and it is simpler | ||
| 879 | and cleaner never to alter the window/buffer connections. */ | ||
| 880 | tem1 = Fcar (tem); | ||
| 881 | if (!NILP (tem1) | ||
| 882 | && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer)) | ||
| 883 | Fswitch_to_buffer (Fcurrent_buffer (), Qnil); | ||
| 884 | #endif /* 0 */ | ||
| 885 | |||
| 886 | /* Mark active */ | ||
| 887 | info = XCDR (info); | ||
| 888 | tem = XCAR (info); | ||
| 889 | tem1 = BVAR (current_buffer, mark_active); | 878 | tem1 = BVAR (current_buffer, mark_active); |
| 890 | bset_mark_active (current_buffer, tem); | 879 | bset_mark_active (current_buffer, tem); |
| 891 | 880 | ||
| @@ -909,8 +898,8 @@ save_excursion_restore (Lisp_Object info) | |||
| 909 | /* If buffer was visible in a window, and a different window was | 898 | /* If buffer was visible in a window, and a different window was |
| 910 | selected, and the old selected window is still showing this | 899 | selected, and the old selected window is still showing this |
| 911 | buffer, restore point in that window. */ | 900 | buffer, restore point in that window. */ |
| 912 | tem = XCDR (info); | 901 | tem = data[2]; |
| 913 | if (visible_p | 902 | if (WINDOWP (tem) |
| 914 | && !EQ (tem, selected_window) | 903 | && !EQ (tem, selected_window) |
| 915 | && (tem1 = XWINDOW (tem)->buffer, | 904 | && (tem1 = XWINDOW (tem)->buffer, |
| 916 | (/* Window is live... */ | 905 | (/* Window is live... */ |
| @@ -920,6 +909,10 @@ save_excursion_restore (Lisp_Object info) | |||
| 920 | Fset_window_point (tem, make_number (PT)); | 909 | Fset_window_point (tem, make_number (PT)); |
| 921 | 910 | ||
| 922 | UNGCPRO; | 911 | UNGCPRO; |
| 912 | |||
| 913 | out: | ||
| 914 | |||
| 915 | free_save_value (info); | ||
| 923 | return Qnil; | 916 | return Qnil; |
| 924 | } | 917 | } |
| 925 | 918 | ||
| @@ -2929,7 +2922,7 @@ Both characters must have the same length of multi-byte form. */) | |||
| 2929 | else if (!changed) | 2922 | else if (!changed) |
| 2930 | { | 2923 | { |
| 2931 | changed = -1; | 2924 | changed = -1; |
| 2932 | modify_region (current_buffer, pos, XINT (end), 0); | 2925 | modify_region_1 (pos, XINT (end), false); |
| 2933 | 2926 | ||
| 2934 | if (! NILP (noundo)) | 2927 | if (! NILP (noundo)) |
| 2935 | { | 2928 | { |
| @@ -3105,7 +3098,7 @@ It returns the number of characters changed. */) | |||
| 3105 | pos = XINT (start); | 3098 | pos = XINT (start); |
| 3106 | pos_byte = CHAR_TO_BYTE (pos); | 3099 | pos_byte = CHAR_TO_BYTE (pos); |
| 3107 | end_pos = XINT (end); | 3100 | end_pos = XINT (end); |
| 3108 | modify_region (current_buffer, pos, end_pos, 0); | 3101 | modify_region_1 (pos, end_pos, false); |
| 3109 | 3102 | ||
| 3110 | cnt = 0; | 3103 | cnt = 0; |
| 3111 | for (; pos < end_pos; ) | 3104 | for (; pos < end_pos; ) |
| @@ -4629,7 +4622,7 @@ Transposing beyond buffer boundaries is an error. */) | |||
| 4629 | 4622 | ||
| 4630 | if (end1 == start2) /* adjacent regions */ | 4623 | if (end1 == start2) /* adjacent regions */ |
| 4631 | { | 4624 | { |
| 4632 | modify_region (current_buffer, start1, end2, 0); | 4625 | modify_region_1 (start1, end2, false); |
| 4633 | record_change (start1, len1 + len2); | 4626 | record_change (start1, len1 + len2); |
| 4634 | 4627 | ||
| 4635 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); | 4628 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); |
| @@ -4688,8 +4681,8 @@ Transposing beyond buffer boundaries is an error. */) | |||
| 4688 | { | 4681 | { |
| 4689 | USE_SAFE_ALLOCA; | 4682 | USE_SAFE_ALLOCA; |
| 4690 | 4683 | ||
| 4691 | modify_region (current_buffer, start1, end1, 0); | 4684 | modify_region_1 (start1, end1, false); |
| 4692 | modify_region (current_buffer, start2, end2, 0); | 4685 | modify_region_1 (start2, end2, false); |
| 4693 | record_change (start1, len1); | 4686 | record_change (start1, len1); |
| 4694 | record_change (start2, len2); | 4687 | record_change (start2, len2); |
| 4695 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); | 4688 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); |
| @@ -4722,7 +4715,7 @@ Transposing beyond buffer boundaries is an error. */) | |||
| 4722 | { | 4715 | { |
| 4723 | USE_SAFE_ALLOCA; | 4716 | USE_SAFE_ALLOCA; |
| 4724 | 4717 | ||
| 4725 | modify_region (current_buffer, start1, end2, 0); | 4718 | modify_region_1 (start1, end2, false); |
| 4726 | record_change (start1, (end2 - start1)); | 4719 | record_change (start1, (end2 - start1)); |
| 4727 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); | 4720 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); |
| 4728 | tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); | 4721 | tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); |
| @@ -4755,7 +4748,7 @@ Transposing beyond buffer boundaries is an error. */) | |||
| 4755 | USE_SAFE_ALLOCA; | 4748 | USE_SAFE_ALLOCA; |
| 4756 | 4749 | ||
| 4757 | record_change (start1, (end2 - start1)); | 4750 | record_change (start1, (end2 - start1)); |
| 4758 | modify_region (current_buffer, start1, end2, 0); | 4751 | modify_region_1 (start1, end2, false); |
| 4759 | 4752 | ||
| 4760 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); | 4753 | tmp_interval1 = copy_intervals (cur_intv, start1, len1); |
| 4761 | tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); | 4754 | tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid); |
diff --git a/src/fileio.c b/src/fileio.c index 48dbf20b88f..9edd88ca64f 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -5771,7 +5771,7 @@ This applies only to the operation `inhibit-file-name-operation'. */); | |||
| 5771 | DEFVAR_LISP ("auto-save-list-file-name", Vauto_save_list_file_name, | 5771 | DEFVAR_LISP ("auto-save-list-file-name", Vauto_save_list_file_name, |
| 5772 | doc: /* File name in which we write a list of all auto save file names. | 5772 | doc: /* File name in which we write a list of all auto save file names. |
| 5773 | This variable is initialized automatically from `auto-save-list-file-prefix' | 5773 | This variable is initialized automatically from `auto-save-list-file-prefix' |
| 5774 | shortly after Emacs reads your `.emacs' file, if you have not yet given it | 5774 | shortly after Emacs reads your init file, if you have not yet given it |
| 5775 | a non-nil value. */); | 5775 | a non-nil value. */); |
| 5776 | Vauto_save_list_file_name = Qnil; | 5776 | Vauto_save_list_file_name = Qnil; |
| 5777 | 5777 | ||
diff --git a/src/gtkutil.c b/src/gtkutil.c index 4367b534cb9..52a6c37b0d5 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c | |||
| @@ -813,6 +813,14 @@ xg_hide_tooltip (FRAME_PTR f) | |||
| 813 | General functions for creating widgets, resizing, events, e.t.c. | 813 | General functions for creating widgets, resizing, events, e.t.c. |
| 814 | ***********************************************************************/ | 814 | ***********************************************************************/ |
| 815 | 815 | ||
| 816 | static void | ||
| 817 | my_log_handler (const gchar *log_domain, GLogLevelFlags log_level, | ||
| 818 | const gchar *msg, gpointer user_data) | ||
| 819 | { | ||
| 820 | if (!strstr (msg, "visible children")) | ||
| 821 | fprintf (stderr, "XX %s-WARNING **: %s\n", log_domain, msg); | ||
| 822 | } | ||
| 823 | |||
| 816 | /* Make a geometry string and pass that to GTK. It seems this is the | 824 | /* Make a geometry string and pass that to GTK. It seems this is the |
| 817 | only way to get geometry position right if the user explicitly | 825 | only way to get geometry position right if the user explicitly |
| 818 | asked for a position when starting Emacs. | 826 | asked for a position when starting Emacs. |
| @@ -828,6 +836,7 @@ xg_set_geometry (FRAME_PTR f) | |||
| 828 | int top = f->top_pos; | 836 | int top = f->top_pos; |
| 829 | int yneg = f->size_hint_flags & YNegative; | 837 | int yneg = f->size_hint_flags & YNegative; |
| 830 | char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)]; | 838 | char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)]; |
| 839 | guint id; | ||
| 831 | 840 | ||
| 832 | if (xneg) | 841 | if (xneg) |
| 833 | left = -left; | 842 | left = -left; |
| @@ -840,9 +849,15 @@ xg_set_geometry (FRAME_PTR f) | |||
| 840 | (xneg ? '-' : '+'), left, | 849 | (xneg ? '-' : '+'), left, |
| 841 | (yneg ? '-' : '+'), top); | 850 | (yneg ? '-' : '+'), top); |
| 842 | 851 | ||
| 852 | /* Silence warning about visible children. */ | ||
| 853 | id = g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | ||
| 854 | | G_LOG_FLAG_RECURSION, my_log_handler, NULL); | ||
| 855 | |||
| 843 | if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), | 856 | if (!gtk_window_parse_geometry (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), |
| 844 | geom_str)) | 857 | geom_str)) |
| 845 | fprintf (stderr, "Failed to parse: '%s'\n", geom_str); | 858 | fprintf (stderr, "Failed to parse: '%s'\n", geom_str); |
| 859 | |||
| 860 | g_log_remove_handler ("Gtk", id); | ||
| 846 | } | 861 | } |
| 847 | } | 862 | } |
| 848 | 863 | ||
diff --git a/src/insdel.c b/src/insdel.c index 87010cd8251..892ca3d5216 100644 --- a/src/insdel.c +++ b/src/insdel.c | |||
| @@ -1755,9 +1755,9 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, | |||
| 1755 | 1755 | ||
| 1756 | return deletion; | 1756 | return deletion; |
| 1757 | } | 1757 | } |
| 1758 | 1758 | ||
| 1759 | /* Call this if you're about to change the region of BUFFER from | 1759 | /* Call this if you're about to change the region of current buffer |
| 1760 | character positions START to END. This checks the read-only | 1760 | from character positions START to END. This checks the read-only |
| 1761 | properties of the region, calls the necessary modification hooks, | 1761 | properties of the region, calls the necessary modification hooks, |
| 1762 | and warns the next redisplay that it should pay attention to that | 1762 | and warns the next redisplay that it should pay attention to that |
| 1763 | area. | 1763 | area. |
| @@ -1766,16 +1766,11 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, | |||
| 1766 | Otherwise set CHARS_MODIFF to the new value of MODIFF. */ | 1766 | Otherwise set CHARS_MODIFF to the new value of MODIFF. */ |
| 1767 | 1767 | ||
| 1768 | void | 1768 | void |
| 1769 | modify_region (struct buffer *buffer, ptrdiff_t start, ptrdiff_t end, | 1769 | modify_region_1 (ptrdiff_t start, ptrdiff_t end, bool preserve_chars_modiff) |
| 1770 | bool preserve_chars_modiff) | ||
| 1771 | { | 1770 | { |
| 1772 | struct buffer *old_buffer = current_buffer; | ||
| 1773 | |||
| 1774 | set_buffer_internal (buffer); | ||
| 1775 | |||
| 1776 | prepare_to_modify_buffer (start, end, NULL); | 1771 | prepare_to_modify_buffer (start, end, NULL); |
| 1777 | 1772 | ||
| 1778 | BUF_COMPUTE_UNCHANGED (buffer, start - 1, end); | 1773 | BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end); |
| 1779 | 1774 | ||
| 1780 | if (MODIFF <= SAVE_MODIFF) | 1775 | if (MODIFF <= SAVE_MODIFF) |
| 1781 | record_first_change (); | 1776 | record_first_change (); |
| @@ -1783,11 +1778,9 @@ modify_region (struct buffer *buffer, ptrdiff_t start, ptrdiff_t end, | |||
| 1783 | if (! preserve_chars_modiff) | 1778 | if (! preserve_chars_modiff) |
| 1784 | CHARS_MODIFF = MODIFF; | 1779 | CHARS_MODIFF = MODIFF; |
| 1785 | 1780 | ||
| 1786 | bset_point_before_scroll (buffer, Qnil); | 1781 | bset_point_before_scroll (current_buffer, Qnil); |
| 1787 | |||
| 1788 | set_buffer_internal (old_buffer); | ||
| 1789 | } | 1782 | } |
| 1790 | 1783 | ||
| 1791 | /* Check that it is okay to modify the buffer between START and END, | 1784 | /* Check that it is okay to modify the buffer between START and END, |
| 1792 | which are char positions. | 1785 | which are char positions. |
| 1793 | 1786 | ||
diff --git a/src/lisp.h b/src/lisp.h index a5c4f862d37..ad249a2c66b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2801,7 +2801,7 @@ extern void del_range_byte (ptrdiff_t, ptrdiff_t, bool); | |||
| 2801 | extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); | 2801 | extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); |
| 2802 | extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, | 2802 | extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, |
| 2803 | ptrdiff_t, ptrdiff_t, bool); | 2803 | ptrdiff_t, ptrdiff_t, bool); |
| 2804 | extern void modify_region (struct buffer *, ptrdiff_t, ptrdiff_t, bool); | 2804 | extern void modify_region_1 (ptrdiff_t, ptrdiff_t, bool); |
| 2805 | extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); | 2805 | extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); |
| 2806 | extern void signal_after_change (ptrdiff_t, ptrdiff_t, ptrdiff_t); | 2806 | extern void signal_after_change (ptrdiff_t, ptrdiff_t, ptrdiff_t); |
| 2807 | extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t, | 2807 | extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t, |
| @@ -2968,6 +2968,7 @@ extern Lisp_Object make_float (double); | |||
| 2968 | extern void display_malloc_warning (void); | 2968 | extern void display_malloc_warning (void); |
| 2969 | extern ptrdiff_t inhibit_garbage_collection (void); | 2969 | extern ptrdiff_t inhibit_garbage_collection (void); |
| 2970 | extern Lisp_Object make_save_value (void *, ptrdiff_t); | 2970 | extern Lisp_Object make_save_value (void *, ptrdiff_t); |
| 2971 | extern void free_save_value (Lisp_Object); | ||
| 2971 | extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); | 2972 | extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); |
| 2972 | extern void free_marker (Lisp_Object); | 2973 | extern void free_marker (Lisp_Object); |
| 2973 | extern void free_cons (struct Lisp_Cons *); | 2974 | extern void free_cons (struct Lisp_Cons *); |
| @@ -3398,7 +3399,6 @@ extern void syms_of_doc (void); | |||
| 3398 | extern int read_bytecode_char (bool); | 3399 | extern int read_bytecode_char (bool); |
| 3399 | 3400 | ||
| 3400 | /* Defined in bytecode.c. */ | 3401 | /* Defined in bytecode.c. */ |
| 3401 | extern Lisp_Object Qbytecode; | ||
| 3402 | extern void syms_of_bytecode (void); | 3402 | extern void syms_of_bytecode (void); |
| 3403 | extern struct byte_stack *byte_stack_list; | 3403 | extern struct byte_stack *byte_stack_list; |
| 3404 | #if BYTE_MARK_STACK | 3404 | #if BYTE_MARK_STACK |
diff --git a/src/process.c b/src/process.c index b23f06fd025..27009882c99 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -777,10 +777,23 @@ get_process (register Lisp_Object name) | |||
| 777 | /* Fdelete_process promises to immediately forget about the process, but in | 777 | /* Fdelete_process promises to immediately forget about the process, but in |
| 778 | reality, Emacs needs to remember those processes until they have been | 778 | reality, Emacs needs to remember those processes until they have been |
| 779 | treated by the SIGCHLD handler and waitpid has been invoked on them; | 779 | treated by the SIGCHLD handler and waitpid has been invoked on them; |
| 780 | otherwise they might fill up the kernel's process table. */ | 780 | otherwise they might fill up the kernel's process table. |
| 781 | |||
| 782 | Some processes created by call-process are also put onto this list. */ | ||
| 781 | static Lisp_Object deleted_pid_list; | 783 | static Lisp_Object deleted_pid_list; |
| 782 | #endif | 784 | #endif |
| 783 | 785 | ||
| 786 | void | ||
| 787 | record_deleted_pid (pid_t pid) | ||
| 788 | { | ||
| 789 | #ifdef SIGCHLD | ||
| 790 | deleted_pid_list = Fcons (make_fixnum_or_float (pid), | ||
| 791 | /* GC treated elements set to nil. */ | ||
| 792 | Fdelq (Qnil, deleted_pid_list)); | ||
| 793 | |||
| 794 | #endif | ||
| 795 | } | ||
| 796 | |||
| 784 | DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, | 797 | DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, |
| 785 | doc: /* Delete PROCESS: kill it and forget about it immediately. | 798 | doc: /* Delete PROCESS: kill it and forget about it immediately. |
| 786 | PROCESS may be a process, a buffer, the name of a process or buffer, or | 799 | PROCESS may be a process, a buffer, the name of a process or buffer, or |
| @@ -807,9 +820,7 @@ nil, indicating the current buffer's process. */) | |||
| 807 | pid_t pid = p->pid; | 820 | pid_t pid = p->pid; |
| 808 | 821 | ||
| 809 | /* No problem storing the pid here, as it is still in Vprocess_alist. */ | 822 | /* No problem storing the pid here, as it is still in Vprocess_alist. */ |
| 810 | deleted_pid_list = Fcons (make_fixnum_or_float (pid), | 823 | record_deleted_pid (pid); |
| 811 | /* GC treated elements set to nil. */ | ||
| 812 | Fdelq (Qnil, deleted_pid_list)); | ||
| 813 | /* If the process has already signaled, remove it from the list. */ | 824 | /* If the process has already signaled, remove it from the list. */ |
| 814 | if (p->raw_status_new) | 825 | if (p->raw_status_new) |
| 815 | update_status (p); | 826 | update_status (p); |
| @@ -1586,9 +1597,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1586 | volatile int pty_flag = 0; | 1597 | volatile int pty_flag = 0; |
| 1587 | volatile Lisp_Object lisp_pty_name = Qnil; | 1598 | volatile Lisp_Object lisp_pty_name = Qnil; |
| 1588 | volatile Lisp_Object encoded_current_dir; | 1599 | volatile Lisp_Object encoded_current_dir; |
| 1589 | #if HAVE_WORKING_VFORK | ||
| 1590 | char **volatile save_environ; | ||
| 1591 | #endif | ||
| 1592 | 1600 | ||
| 1593 | inchannel = outchannel = -1; | 1601 | inchannel = outchannel = -1; |
| 1594 | 1602 | ||
| @@ -1688,12 +1696,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1688 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | 1696 | pthread_sigmask (SIG_BLOCK, &blocked, 0); |
| 1689 | #endif | 1697 | #endif |
| 1690 | 1698 | ||
| 1691 | #if HAVE_WORKING_VFORK | ||
| 1692 | /* child_setup must clobber environ on systems with true vfork. | ||
| 1693 | Protect it from permanent change. */ | ||
| 1694 | save_environ = environ; | ||
| 1695 | #endif | ||
| 1696 | |||
| 1697 | #ifndef WINDOWSNT | 1699 | #ifndef WINDOWSNT |
| 1698 | pid = vfork (); | 1700 | pid = vfork (); |
| 1699 | if (pid == 0) | 1701 | if (pid == 0) |
| @@ -1819,10 +1821,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1819 | 1821 | ||
| 1820 | /* Back in the parent process. */ | 1822 | /* Back in the parent process. */ |
| 1821 | 1823 | ||
| 1822 | #if HAVE_WORKING_VFORK | ||
| 1823 | environ = save_environ; | ||
| 1824 | #endif | ||
| 1825 | |||
| 1826 | XPROCESS (process)->pid = pid; | 1824 | XPROCESS (process)->pid = pid; |
| 1827 | if (0 <= pid) | 1825 | if (0 <= pid) |
| 1828 | XPROCESS (process)->alive = 1; | 1826 | XPROCESS (process)->alive = 1; |
| @@ -1874,7 +1872,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1874 | /* Wait for child_setup to complete in case that vfork is | 1872 | /* Wait for child_setup to complete in case that vfork is |
| 1875 | actually defined as fork. The descriptor wait_child_setup[1] | 1873 | actually defined as fork. The descriptor wait_child_setup[1] |
| 1876 | of a pipe is closed at the child side either by close-on-exec | 1874 | of a pipe is closed at the child side either by close-on-exec |
| 1877 | on successful execvp or the _exit call in child_setup. */ | 1875 | on successful execve or the _exit call in child_setup. */ |
| 1878 | { | 1876 | { |
| 1879 | char dummy; | 1877 | char dummy; |
| 1880 | 1878 | ||
| @@ -6160,35 +6158,37 @@ process has been transmitted to the serial port. */) | |||
| 6160 | return process; | 6158 | return process; |
| 6161 | } | 6159 | } |
| 6162 | 6160 | ||
| 6163 | /* If the status of the process DESIRED has changed, return true and | 6161 | #ifdef SIGCHLD |
| 6164 | set *STATUS to its exit status; otherwise, return false. | ||
| 6165 | If HAVE is nonnegative, assume that HAVE = waitpid (HAVE, STATUS, ...) | ||
| 6166 | has already been invoked, and do not invoke waitpid again. */ | ||
| 6167 | 6162 | ||
| 6168 | static bool | 6163 | /* The main Emacs thread records child processes in three places: |
| 6169 | process_status_retrieved (pid_t desired, pid_t have, int *status) | ||
| 6170 | { | ||
| 6171 | if (have < 0) | ||
| 6172 | { | ||
| 6173 | /* Invoke waitpid only with a known process ID; do not invoke | ||
| 6174 | waitpid with a nonpositive argument. Otherwise, Emacs might | ||
| 6175 | reap an unwanted process by mistake. For example, invoking | ||
| 6176 | waitpid (-1, ...) can mess up glib by reaping glib's subprocesses, | ||
| 6177 | so that another thread running glib won't find them. */ | ||
| 6178 | do | ||
| 6179 | have = waitpid (desired, status, WNOHANG | WUNTRACED); | ||
| 6180 | while (have < 0 && errno == EINTR); | ||
| 6181 | } | ||
| 6182 | 6164 | ||
| 6183 | return have == desired; | 6165 | - Vprocess_alist, for asynchronous subprocesses, which are child |
| 6184 | } | 6166 | processes visible to Lisp. |
| 6185 | 6167 | ||
| 6186 | /* If PID is nonnegative, the child process PID with wait status W has | 6168 | - deleted_pid_list, for child processes invisible to Lisp, |
| 6187 | changed its status; record this and return true. | 6169 | typically because of delete-process. These are recorded so that |
| 6170 | the processes can be reaped when they exit, so that the operating | ||
| 6171 | system's process table is not cluttered by zombies. | ||
| 6188 | 6172 | ||
| 6189 | If PID is negative, ignore W, and look for known child processes | 6173 | - the local variable PID in Fcall_process, call_process_cleanup and |
| 6190 | of Emacs whose status have changed. For each one found, record its new | 6174 | call_process_kill, for synchronous subprocesses. |
| 6191 | status. | 6175 | record_unwind_protect is used to make sure this process is not |
| 6176 | forgotten: if the user interrupts call-process and the child | ||
| 6177 | process refuses to exit immediately even with two C-g's, | ||
| 6178 | call_process_kill adds PID's contents to deleted_pid_list before | ||
| 6179 | returning. | ||
| 6180 | |||
| 6181 | The main Emacs thread invokes waitpid only on child processes that | ||
| 6182 | it creates and that have not been reaped. This avoid races on | ||
| 6183 | platforms such as GTK, where other threads create their own | ||
| 6184 | subprocesses which the main thread should not reap. For example, | ||
| 6185 | if the main thread attempted to reap an already-reaped child, it | ||
| 6186 | might inadvertently reap a GTK-created process that happened to | ||
| 6187 | have the same process ID. */ | ||
| 6188 | |||
| 6189 | /* Handle a SIGCHLD signal by looking for known child processes of | ||
| 6190 | Emacs whose status have changed. For each one found, record its | ||
| 6191 | new status. | ||
| 6192 | 6192 | ||
| 6193 | All we do is change the status; we do not run sentinels or print | 6193 | All we do is change the status; we do not run sentinels or print |
| 6194 | notifications. That is saved for the next time keyboard input is | 6194 | notifications. That is saved for the next time keyboard input is |
| @@ -6211,20 +6211,15 @@ process_status_retrieved (pid_t desired, pid_t have, int *status) | |||
| 6211 | ** Malloc WARNING: This should never call malloc either directly or | 6211 | ** Malloc WARNING: This should never call malloc either directly or |
| 6212 | indirectly; if it does, that is a bug */ | 6212 | indirectly; if it does, that is a bug */ |
| 6213 | 6213 | ||
| 6214 | void | 6214 | static void |
| 6215 | record_child_status_change (pid_t pid, int w) | 6215 | handle_child_signal (int sig) |
| 6216 | { | 6216 | { |
| 6217 | #ifdef SIGCHLD | ||
| 6218 | |||
| 6219 | /* Record at most one child only if we already know one child that | ||
| 6220 | has exited. */ | ||
| 6221 | bool record_at_most_one_child = 0 <= pid; | ||
| 6222 | |||
| 6223 | Lisp_Object tail; | 6217 | Lisp_Object tail; |
| 6224 | 6218 | ||
| 6225 | /* Find the process that signaled us, and record its status. */ | 6219 | /* Find the process that signaled us, and record its status. */ |
| 6226 | 6220 | ||
| 6227 | /* The process can have been deleted by Fdelete_process. */ | 6221 | /* The process can have been deleted by Fdelete_process, or have |
| 6222 | been started asynchronously by Fcall_process. */ | ||
| 6228 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) | 6223 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) |
| 6229 | { | 6224 | { |
| 6230 | bool all_pids_are_fixnums | 6225 | bool all_pids_are_fixnums |
| @@ -6238,12 +6233,8 @@ record_child_status_change (pid_t pid, int w) | |||
| 6238 | deleted_pid = XINT (xpid); | 6233 | deleted_pid = XINT (xpid); |
| 6239 | else | 6234 | else |
| 6240 | deleted_pid = XFLOAT_DATA (xpid); | 6235 | deleted_pid = XFLOAT_DATA (xpid); |
| 6241 | if (process_status_retrieved (deleted_pid, pid, &w)) | 6236 | if (child_status_changed (deleted_pid, 0, 0)) |
| 6242 | { | 6237 | XSETCAR (tail, Qnil); |
| 6243 | XSETCAR (tail, Qnil); | ||
| 6244 | if (record_at_most_one_child) | ||
| 6245 | return; | ||
| 6246 | } | ||
| 6247 | } | 6238 | } |
| 6248 | } | 6239 | } |
| 6249 | 6240 | ||
| @@ -6252,15 +6243,17 @@ record_child_status_change (pid_t pid, int w) | |||
| 6252 | { | 6243 | { |
| 6253 | Lisp_Object proc = XCDR (XCAR (tail)); | 6244 | Lisp_Object proc = XCDR (XCAR (tail)); |
| 6254 | struct Lisp_Process *p = XPROCESS (proc); | 6245 | struct Lisp_Process *p = XPROCESS (proc); |
| 6255 | if (p->alive && process_status_retrieved (p->pid, pid, &w)) | 6246 | int status; |
| 6247 | |||
| 6248 | if (p->alive && child_status_changed (p->pid, &status, WUNTRACED)) | ||
| 6256 | { | 6249 | { |
| 6257 | /* Change the status of the process that was found. */ | 6250 | /* Change the status of the process that was found. */ |
| 6258 | p->tick = ++process_tick; | 6251 | p->tick = ++process_tick; |
| 6259 | p->raw_status = w; | 6252 | p->raw_status = status; |
| 6260 | p->raw_status_new = 1; | 6253 | p->raw_status_new = 1; |
| 6261 | 6254 | ||
| 6262 | /* If process has terminated, stop waiting for its output. */ | 6255 | /* If process has terminated, stop waiting for its output. */ |
| 6263 | if (WIFSIGNALED (w) || WIFEXITED (w)) | 6256 | if (WIFSIGNALED (status) || WIFEXITED (status)) |
| 6264 | { | 6257 | { |
| 6265 | int clear_desc_flag = 0; | 6258 | int clear_desc_flag = 0; |
| 6266 | p->alive = 0; | 6259 | p->alive = 0; |
| @@ -6274,44 +6267,8 @@ record_child_status_change (pid_t pid, int w) | |||
| 6274 | FD_CLR (p->infd, &non_keyboard_wait_mask); | 6267 | FD_CLR (p->infd, &non_keyboard_wait_mask); |
| 6275 | } | 6268 | } |
| 6276 | } | 6269 | } |
| 6277 | |||
| 6278 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6279 | look around. */ | ||
| 6280 | if (input_available_clear_time) | ||
| 6281 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6282 | |||
| 6283 | if (record_at_most_one_child) | ||
| 6284 | return; | ||
| 6285 | } | 6270 | } |
| 6286 | } | 6271 | } |
| 6287 | |||
| 6288 | if (0 <= pid) | ||
| 6289 | { | ||
| 6290 | /* The caller successfully waited for a pid but no asynchronous | ||
| 6291 | process was found for it, so this is a synchronous process. */ | ||
| 6292 | |||
| 6293 | synch_process_alive = 0; | ||
| 6294 | |||
| 6295 | /* Report the status of the synchronous process. */ | ||
| 6296 | if (WIFEXITED (w)) | ||
| 6297 | synch_process_retcode = WEXITSTATUS (w); | ||
| 6298 | else if (WIFSIGNALED (w)) | ||
| 6299 | synch_process_termsig = WTERMSIG (w); | ||
| 6300 | |||
| 6301 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6302 | look around. */ | ||
| 6303 | if (input_available_clear_time) | ||
| 6304 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6305 | } | ||
| 6306 | #endif | ||
| 6307 | } | ||
| 6308 | |||
| 6309 | #ifdef SIGCHLD | ||
| 6310 | |||
| 6311 | static void | ||
| 6312 | handle_child_signal (int sig) | ||
| 6313 | { | ||
| 6314 | record_child_status_change (-1, 0); | ||
| 6315 | } | 6272 | } |
| 6316 | 6273 | ||
| 6317 | static void | 6274 | static void |
diff --git a/src/process.h b/src/process.h index 74d1a124060..4fa22747ca9 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -185,23 +185,6 @@ pset_gnutls_cred_type (struct Lisp_Process *p, Lisp_Object val) | |||
| 185 | } | 185 | } |
| 186 | #endif | 186 | #endif |
| 187 | 187 | ||
| 188 | /* True if we are about to fork off a synchronous process or if we | ||
| 189 | are waiting for it. */ | ||
| 190 | extern bool synch_process_alive; | ||
| 191 | |||
| 192 | /* Communicate exit status of sync process to from sigchld_handler | ||
| 193 | to Fcall_process. */ | ||
| 194 | |||
| 195 | /* Nonzero => this is a string explaining death of synchronous subprocess. */ | ||
| 196 | extern const char *synch_process_death; | ||
| 197 | |||
| 198 | /* Nonzero => this is the signal number that terminated the subprocess. */ | ||
| 199 | extern int synch_process_termsig; | ||
| 200 | |||
| 201 | /* If synch_process_death is zero, | ||
| 202 | this is exit code of synchronous subprocess. */ | ||
| 203 | extern int synch_process_retcode; | ||
| 204 | |||
| 205 | /* Nonzero means don't run process sentinels. This is used | 188 | /* Nonzero means don't run process sentinels. This is used |
| 206 | when exiting. */ | 189 | when exiting. */ |
| 207 | extern int inhibit_sentinels; | 190 | extern int inhibit_sentinels; |
diff --git a/src/sysdep.c b/src/sysdep.c index 1a3834f0379..7068a4f0977 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -266,45 +266,71 @@ init_baud_rate (int fd) | |||
| 266 | 266 | ||
| 267 | #ifndef MSDOS | 267 | #ifndef MSDOS |
| 268 | 268 | ||
| 269 | static void | 269 | /* Wait for the subprocess with process id CHILD to terminate or change status. |
| 270 | wait_for_termination_1 (pid_t pid, int interruptible) | 270 | CHILD must be a child process that has not been reaped. |
| 271 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 272 | and tell wait_reading_process_output that it needs to look around. | ||
| 273 | Use waitpid-style OPTIONS when waiting. | ||
| 274 | If INTERRUPTIBLE, this function is interruptible by a signal. | ||
| 275 | |||
| 276 | Return CHILD if successful, 0 if no status is available; | ||
| 277 | the latter is possible only when options & NOHANG. */ | ||
| 278 | static pid_t | ||
| 279 | get_child_status (pid_t child, int *status, int options, bool interruptible) | ||
| 271 | { | 280 | { |
| 272 | while (1) | 281 | pid_t pid; |
| 282 | |||
| 283 | /* Invoke waitpid only with a known process ID; do not invoke | ||
| 284 | waitpid with a nonpositive argument. Otherwise, Emacs might | ||
| 285 | reap an unwanted process by mistake. For example, invoking | ||
| 286 | waitpid (-1, ...) can mess up glib by reaping glib's subprocesses, | ||
| 287 | so that another thread running glib won't find them. */ | ||
| 288 | eassert (0 < child); | ||
| 289 | |||
| 290 | while ((pid = waitpid (child, status, options)) < 0) | ||
| 273 | { | 291 | { |
| 274 | int status; | 292 | /* CHILD must be a child process that has not been reaped, and |
| 275 | int wait_result = waitpid (pid, &status, 0); | 293 | STATUS and OPTIONS must be valid. */ |
| 276 | if (wait_result < 0) | 294 | eassert (errno == EINTR); |
| 277 | { | ||
| 278 | if (errno != EINTR) | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | else | ||
| 282 | { | ||
| 283 | record_child_status_change (wait_result, status); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | 295 | ||
| 287 | /* Note: the MS-Windows emulation of waitpid calls QUIT | 296 | /* Note: the MS-Windows emulation of waitpid calls QUIT |
| 288 | internally. */ | 297 | internally. */ |
| 289 | if (interruptible) | 298 | if (interruptible) |
| 290 | QUIT; | 299 | QUIT; |
| 291 | } | 300 | } |
| 292 | } | ||
| 293 | 301 | ||
| 294 | /* Wait for subprocess with process id `pid' to terminate and | 302 | /* If successful and status is requested, tell wait_reading_process_output |
| 295 | make sure it will get eliminated (not remain forever as a zombie) */ | 303 | that it needs to wake up and look around. */ |
| 304 | if (pid && status && input_available_clear_time) | ||
| 305 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 296 | 306 | ||
| 307 | return pid; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Wait for the subprocess with process id CHILD to terminate. | ||
| 311 | CHILD must be a child process that has not been reaped. | ||
| 312 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 313 | and tell wait_reading_process_output that it needs to look around. | ||
| 314 | If INTERRUPTIBLE, this function is interruptible by a signal. */ | ||
| 297 | void | 315 | void |
| 298 | wait_for_termination (pid_t pid) | 316 | wait_for_termination (pid_t child, int *status, bool interruptible) |
| 299 | { | 317 | { |
| 300 | wait_for_termination_1 (pid, 0); | 318 | get_child_status (child, status, 0, interruptible); |
| 301 | } | 319 | } |
| 302 | 320 | ||
| 303 | /* Like the above, but allow keyboard interruption. */ | 321 | /* Report whether the subprocess with process id CHILD has changed status. |
| 304 | void | 322 | Termination counts as a change of status. |
| 305 | interruptible_wait_for_termination (pid_t pid) | 323 | CHILD must be a child process that has not been reaped. |
| 324 | If STATUS is non-null, store the waitpid-style exit status into *STATUS | ||
| 325 | and tell wait_reading_process_output that it needs to look around. | ||
| 326 | Use waitpid-style OPTIONS to check status, but do not wait. | ||
| 327 | |||
| 328 | Return CHILD if successful, 0 if no status is available because | ||
| 329 | the process's state has not changed. */ | ||
| 330 | pid_t | ||
| 331 | child_status_changed (pid_t child, int *status, int options) | ||
| 306 | { | 332 | { |
| 307 | wait_for_termination_1 (pid, 1); | 333 | return get_child_status (child, status, WNOHANG | options, 0); |
| 308 | } | 334 | } |
| 309 | 335 | ||
| 310 | /* | 336 | /* |
| @@ -454,6 +480,7 @@ sys_subshell (void) | |||
| 454 | char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ | 480 | char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ |
| 455 | #endif | 481 | #endif |
| 456 | pid_t pid; | 482 | pid_t pid; |
| 483 | int status; | ||
| 457 | struct save_signal saved_handlers[5]; | 484 | struct save_signal saved_handlers[5]; |
| 458 | Lisp_Object dir; | 485 | Lisp_Object dir; |
| 459 | unsigned char *volatile str_volatile = 0; | 486 | unsigned char *volatile str_volatile = 0; |
| @@ -491,7 +518,6 @@ sys_subshell (void) | |||
| 491 | #ifdef DOS_NT | 518 | #ifdef DOS_NT |
| 492 | pid = 0; | 519 | pid = 0; |
| 493 | save_signal_handlers (saved_handlers); | 520 | save_signal_handlers (saved_handlers); |
| 494 | synch_process_alive = 1; | ||
| 495 | #else | 521 | #else |
| 496 | pid = vfork (); | 522 | pid = vfork (); |
| 497 | if (pid == -1) | 523 | if (pid == -1) |
| @@ -560,14 +586,12 @@ sys_subshell (void) | |||
| 560 | /* Do this now if we did not do it before. */ | 586 | /* Do this now if we did not do it before. */ |
| 561 | #ifndef MSDOS | 587 | #ifndef MSDOS |
| 562 | save_signal_handlers (saved_handlers); | 588 | save_signal_handlers (saved_handlers); |
| 563 | synch_process_alive = 1; | ||
| 564 | #endif | 589 | #endif |
| 565 | 590 | ||
| 566 | #ifndef DOS_NT | 591 | #ifndef DOS_NT |
| 567 | wait_for_termination (pid); | 592 | wait_for_termination (pid, &status, 0); |
| 568 | #endif | 593 | #endif |
| 569 | restore_signal_handlers (saved_handlers); | 594 | restore_signal_handlers (saved_handlers); |
| 570 | synch_process_alive = 0; | ||
| 571 | } | 595 | } |
| 572 | 596 | ||
| 573 | static void | 597 | static void |
diff --git a/src/syswait.h b/src/syswait.h index aa4c4bcf527..360407d558e 100644 --- a/src/syswait.h +++ b/src/syswait.h | |||
| @@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 23 | #ifndef EMACS_SYSWAIT_H | 23 | #ifndef EMACS_SYSWAIT_H |
| 24 | #define EMACS_SYSWAIT_H | 24 | #define EMACS_SYSWAIT_H |
| 25 | 25 | ||
| 26 | #include <stdbool.h> | ||
| 26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
| 27 | 28 | ||
| 28 | #ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */ | 29 | #ifdef HAVE_SYS_WAIT_H /* We have sys/wait.h with POSIXoid definitions. */ |
| @@ -52,10 +53,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 52 | #endif | 53 | #endif |
| 53 | 54 | ||
| 54 | /* Defined in process.c. */ | 55 | /* Defined in process.c. */ |
| 55 | extern void record_child_status_change (pid_t, int); | 56 | extern void record_deleted_pid (pid_t); |
| 56 | 57 | ||
| 57 | /* Defined in sysdep.c. */ | 58 | /* Defined in sysdep.c. */ |
| 58 | extern void wait_for_termination (pid_t); | 59 | extern void wait_for_termination (pid_t, int *, bool); |
| 59 | extern void interruptible_wait_for_termination (pid_t); | 60 | extern pid_t child_status_changed (pid_t, int *, int); |
| 60 | 61 | ||
| 61 | #endif /* EMACS_SYSWAIT_H */ | 62 | #endif /* EMACS_SYSWAIT_H */ |
diff --git a/src/textprop.c b/src/textprop.c index 379eafb73f7..1ce44ad60ac 100644 --- a/src/textprop.c +++ b/src/textprop.c | |||
| @@ -85,8 +85,18 @@ text_read_only (Lisp_Object propval) | |||
| 85 | xsignal0 (Qtext_read_only); | 85 | xsignal0 (Qtext_read_only); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /* Prepare to modify the region of BUFFER from START to END. */ | ||
| 89 | |||
| 90 | static void | ||
| 91 | modify_region (Lisp_Object buffer, Lisp_Object start, Lisp_Object end) | ||
| 92 | { | ||
| 93 | struct buffer *buf = XBUFFER (buffer), *old = current_buffer; | ||
| 94 | |||
| 95 | set_buffer_internal (buf); | ||
| 96 | modify_region_1 (XINT (start), XINT (end), true); | ||
| 97 | set_buffer_internal (old); | ||
| 98 | } | ||
| 88 | 99 | ||
| 89 | |||
| 90 | /* Extract the interval at the position pointed to by BEGIN from | 100 | /* Extract the interval at the position pointed to by BEGIN from |
| 91 | OBJECT, a string or buffer. Additionally, check that the positions | 101 | OBJECT, a string or buffer. Additionally, check that the positions |
| 92 | pointed to by BEGIN and END are within the bounds of OBJECT, and | 102 | pointed to by BEGIN and END are within the bounds of OBJECT, and |
| @@ -1164,7 +1174,7 @@ Return t if any property value actually changed, nil otherwise. */) | |||
| 1164 | } | 1174 | } |
| 1165 | 1175 | ||
| 1166 | if (BUFFERP (object)) | 1176 | if (BUFFERP (object)) |
| 1167 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1177 | modify_region (object, start, end); |
| 1168 | 1178 | ||
| 1169 | /* We are at the beginning of interval I, with LEN chars to scan. */ | 1179 | /* We are at the beginning of interval I, with LEN chars to scan. */ |
| 1170 | for (;;) | 1180 | for (;;) |
| @@ -1302,7 +1312,7 @@ set_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object properties, | |||
| 1302 | } | 1312 | } |
| 1303 | 1313 | ||
| 1304 | if (BUFFERP (object) && !NILP (coherent_change_p)) | 1314 | if (BUFFERP (object) && !NILP (coherent_change_p)) |
| 1305 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1315 | modify_region (object, start, end); |
| 1306 | 1316 | ||
| 1307 | set_text_properties_1 (start, end, properties, object, i); | 1317 | set_text_properties_1 (start, end, properties, object, i); |
| 1308 | 1318 | ||
| @@ -1451,7 +1461,7 @@ Use `set-text-properties' if you want to remove all text properties. */) | |||
| 1451 | } | 1461 | } |
| 1452 | 1462 | ||
| 1453 | if (BUFFERP (object)) | 1463 | if (BUFFERP (object)) |
| 1454 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1464 | modify_region (object, start, end); |
| 1455 | 1465 | ||
| 1456 | /* We are at the beginning of an interval, with len to scan */ | 1466 | /* We are at the beginning of an interval, with len to scan */ |
| 1457 | for (;;) | 1467 | for (;;) |
| @@ -1565,7 +1575,7 @@ Return t if any property was actually removed, nil otherwise. */) | |||
| 1565 | else if (LENGTH (i) == len) | 1575 | else if (LENGTH (i) == len) |
| 1566 | { | 1576 | { |
| 1567 | if (!modified && BUFFERP (object)) | 1577 | if (!modified && BUFFERP (object)) |
| 1568 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1578 | modify_region (object, start, end); |
| 1569 | remove_properties (Qnil, properties, i, object); | 1579 | remove_properties (Qnil, properties, i, object); |
| 1570 | if (BUFFERP (object)) | 1580 | if (BUFFERP (object)) |
| 1571 | signal_after_change (XINT (start), XINT (end) - XINT (start), | 1581 | signal_after_change (XINT (start), XINT (end) - XINT (start), |
| @@ -1578,7 +1588,7 @@ Return t if any property was actually removed, nil otherwise. */) | |||
| 1578 | i = split_interval_left (i, len); | 1588 | i = split_interval_left (i, len); |
| 1579 | copy_properties (unchanged, i); | 1589 | copy_properties (unchanged, i); |
| 1580 | if (!modified && BUFFERP (object)) | 1590 | if (!modified && BUFFERP (object)) |
| 1581 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1591 | modify_region (object, start, end); |
| 1582 | remove_properties (Qnil, properties, i, object); | 1592 | remove_properties (Qnil, properties, i, object); |
| 1583 | if (BUFFERP (object)) | 1593 | if (BUFFERP (object)) |
| 1584 | signal_after_change (XINT (start), XINT (end) - XINT (start), | 1594 | signal_after_change (XINT (start), XINT (end) - XINT (start), |
| @@ -1589,7 +1599,7 @@ Return t if any property was actually removed, nil otherwise. */) | |||
| 1589 | if (interval_has_some_properties_list (properties, i)) | 1599 | if (interval_has_some_properties_list (properties, i)) |
| 1590 | { | 1600 | { |
| 1591 | if (!modified && BUFFERP (object)) | 1601 | if (!modified && BUFFERP (object)) |
| 1592 | modify_region (XBUFFER (object), XINT (start), XINT (end), 1); | 1602 | modify_region (object, start, end); |
| 1593 | remove_properties (Qnil, properties, i, object); | 1603 | remove_properties (Qnil, properties, i, object); |
| 1594 | modified = 1; | 1604 | modified = 1; |
| 1595 | } | 1605 | } |
| @@ -150,10 +150,18 @@ typedef struct _REPARSE_DATA_BUFFER { | |||
| 150 | } DUMMYUNIONNAME; | 150 | } DUMMYUNIONNAME; |
| 151 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; | 151 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; |
| 152 | 152 | ||
| 153 | #ifndef FILE_DEVICE_FILE_SYSTEM | ||
| 153 | #define FILE_DEVICE_FILE_SYSTEM 9 | 154 | #define FILE_DEVICE_FILE_SYSTEM 9 |
| 155 | #endif | ||
| 156 | #ifndef METHOD_BUFFERED | ||
| 154 | #define METHOD_BUFFERED 0 | 157 | #define METHOD_BUFFERED 0 |
| 158 | #endif | ||
| 159 | #ifndef FILE_ANY_ACCESS | ||
| 155 | #define FILE_ANY_ACCESS 0x00000000 | 160 | #define FILE_ANY_ACCESS 0x00000000 |
| 161 | #endif | ||
| 162 | #ifndef CTL_CODE | ||
| 156 | #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) | 163 | #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) |
| 164 | #endif | ||
| 157 | #define FSCTL_GET_REPARSE_POINT \ | 165 | #define FSCTL_GET_REPARSE_POINT \ |
| 158 | CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) | 166 | CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) |
| 159 | #endif | 167 | #endif |
diff --git a/src/w32common.h b/src/w32common.h index 50724e5553c..5e9b61824ae 100644 --- a/src/w32common.h +++ b/src/w32common.h | |||
| @@ -34,7 +34,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |||
| 34 | 34 | ||
| 35 | extern SYSTEM_INFO sysinfo_cache; | 35 | extern SYSTEM_INFO sysinfo_cache; |
| 36 | extern OSVERSIONINFO osinfo_cache; | 36 | extern OSVERSIONINFO osinfo_cache; |
| 37 | extern unsigned long syspage_mask; | 37 | extern DWORD_PTR syspage_mask; |
| 38 | 38 | ||
| 39 | extern int w32_major_version; | 39 | extern int w32_major_version; |
| 40 | extern int w32_minor_version; | 40 | extern int w32_minor_version; |
diff --git a/src/w32fns.c b/src/w32fns.c index 90f5b1695ea..044c377f496 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -82,7 +82,6 @@ void syms_of_w32fns (void); | |||
| 82 | void globals_of_w32fns (void); | 82 | void globals_of_w32fns (void); |
| 83 | 83 | ||
| 84 | extern void free_frame_menubar (struct frame *); | 84 | extern void free_frame_menubar (struct frame *); |
| 85 | extern double atof (const char *); | ||
| 86 | extern int w32_console_toggle_lock_key (int, Lisp_Object); | 85 | extern int w32_console_toggle_lock_key (int, Lisp_Object); |
| 87 | extern void w32_menu_display_help (HWND, HMENU, UINT, UINT); | 86 | extern void w32_menu_display_help (HWND, HMENU, UINT, UINT); |
| 88 | extern void w32_free_menu_strings (HWND); | 87 | extern void w32_free_menu_strings (HWND); |
| @@ -223,7 +222,7 @@ SYSTEM_INFO sysinfo_cache; | |||
| 223 | /* This gives us version, build, and platform identification. */ | 222 | /* This gives us version, build, and platform identification. */ |
| 224 | OSVERSIONINFO osinfo_cache; | 223 | OSVERSIONINFO osinfo_cache; |
| 225 | 224 | ||
| 226 | unsigned long syspage_mask = 0; | 225 | DWORD_PTR syspage_mask = 0; |
| 227 | 226 | ||
| 228 | /* The major and minor versions of NT. */ | 227 | /* The major and minor versions of NT. */ |
| 229 | int w32_major_version; | 228 | int w32_major_version; |
| @@ -6035,7 +6034,7 @@ typedef char guichar_t; | |||
| 6035 | read-only when "Directories" is selected in the filter. This | 6034 | read-only when "Directories" is selected in the filter. This |
| 6036 | allows us to work around the fact that the standard Open File | 6035 | allows us to work around the fact that the standard Open File |
| 6037 | dialog does not support directories. */ | 6036 | dialog does not support directories. */ |
| 6038 | static UINT CALLBACK | 6037 | static UINT_PTR CALLBACK |
| 6039 | file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | 6038 | file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
| 6040 | { | 6039 | { |
| 6041 | if (msg == WM_NOTIFY) | 6040 | if (msg == WM_NOTIFY) |
diff --git a/src/w32proc.c b/src/w32proc.c index 9b111b40e36..87af8682390 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -1274,33 +1274,7 @@ waitpid (pid_t pid, int *status, int options) | |||
| 1274 | #endif | 1274 | #endif |
| 1275 | 1275 | ||
| 1276 | if (status) | 1276 | if (status) |
| 1277 | { | 1277 | *status = retval; |
| 1278 | *status = retval; | ||
| 1279 | } | ||
| 1280 | else if (synch_process_alive) | ||
| 1281 | { | ||
| 1282 | synch_process_alive = 0; | ||
| 1283 | |||
| 1284 | /* Report the status of the synchronous process. */ | ||
| 1285 | if (WIFEXITED (retval)) | ||
| 1286 | synch_process_retcode = WEXITSTATUS (retval); | ||
| 1287 | else if (WIFSIGNALED (retval)) | ||
| 1288 | { | ||
| 1289 | int code = WTERMSIG (retval); | ||
| 1290 | const char *signame; | ||
| 1291 | |||
| 1292 | synchronize_system_messages_locale (); | ||
| 1293 | signame = strsignal (code); | ||
| 1294 | |||
| 1295 | if (signame == 0) | ||
| 1296 | signame = "unknown"; | ||
| 1297 | |||
| 1298 | synch_process_death = signame; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | reap_subprocess (cp); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | reap_subprocess (cp); | 1278 | reap_subprocess (cp); |
| 1305 | 1279 | ||
| 1306 | return pid; | 1280 | return pid; |
diff --git a/src/xdisp.c b/src/xdisp.c index 2f7b0a21f3b..4bab2756e64 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -15778,6 +15778,35 @@ redisplay_window (Lisp_Object window, int just_this_one_p) | |||
| 15778 | Move it back to a fully-visible line. */ | 15778 | Move it back to a fully-visible line. */ |
| 15779 | new_vpos = window_box_height (w); | 15779 | new_vpos = window_box_height (w); |
| 15780 | } | 15780 | } |
| 15781 | else if (w->cursor.vpos >=0) | ||
| 15782 | { | ||
| 15783 | /* Some people insist on not letting point enter the scroll | ||
| 15784 | margin, even though this part handles windows that didn't | ||
| 15785 | scroll at all. */ | ||
| 15786 | struct frame *f = XFRAME (w->frame); | ||
| 15787 | int margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4); | ||
| 15788 | int pixel_margin = margin * FRAME_LINE_HEIGHT (f); | ||
| 15789 | bool header_line = WINDOW_WANTS_HEADER_LINE_P (w); | ||
| 15790 | |||
| 15791 | /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop | ||
| 15792 | below, which finds the row to move point to, advances by | ||
| 15793 | the Y coordinate of the _next_ row, see the definition of | ||
| 15794 | MATRIX_ROW_BOTTOM_Y. */ | ||
| 15795 | if (w->cursor.vpos < margin + header_line) | ||
| 15796 | new_vpos | ||
| 15797 | = pixel_margin + (header_line | ||
| 15798 | ? CURRENT_HEADER_LINE_HEIGHT (w) | ||
| 15799 | : 0) + FRAME_LINE_HEIGHT (f); | ||
| 15800 | else | ||
| 15801 | { | ||
| 15802 | int window_height = window_box_height (w); | ||
| 15803 | |||
| 15804 | if (header_line) | ||
| 15805 | window_height += CURRENT_HEADER_LINE_HEIGHT (w); | ||
| 15806 | if (w->cursor.y >= window_height - pixel_margin) | ||
| 15807 | new_vpos = window_height - pixel_margin; | ||
| 15808 | } | ||
| 15809 | } | ||
| 15781 | 15810 | ||
| 15782 | /* If we need to move point for either of the above reasons, | 15811 | /* If we need to move point for either of the above reasons, |
| 15783 | now actually do it. */ | 15812 | now actually do it. */ |
diff --git a/src/xterm.c b/src/xterm.c index 8f7ed8ef561..68d2dd7c70d 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -2261,7 +2261,6 @@ static void | |||
| 2261 | x_draw_image_relief (struct glyph_string *s) | 2261 | x_draw_image_relief (struct glyph_string *s) |
| 2262 | { | 2262 | { |
| 2263 | int x1, y1, thick, raised_p, top_p, bot_p, left_p, right_p; | 2263 | int x1, y1, thick, raised_p, top_p, bot_p, left_p, right_p; |
| 2264 | int extra_x, extra_y; | ||
| 2265 | XRectangle r; | 2264 | XRectangle r; |
| 2266 | int x = s->x; | 2265 | int x = s->x; |
| 2267 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | 2266 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); |
| @@ -2292,20 +2291,6 @@ x_draw_image_relief (struct glyph_string *s) | |||
| 2292 | raised_p = s->img->relief > 0; | 2291 | raised_p = s->img->relief > 0; |
| 2293 | } | 2292 | } |
| 2294 | 2293 | ||
| 2295 | extra_x = extra_y = 0; | ||
| 2296 | if (s->face->id == TOOL_BAR_FACE_ID) | ||
| 2297 | { | ||
| 2298 | if (CONSP (Vtool_bar_button_margin) | ||
| 2299 | && INTEGERP (XCAR (Vtool_bar_button_margin)) | ||
| 2300 | && INTEGERP (XCDR (Vtool_bar_button_margin))) | ||
| 2301 | { | ||
| 2302 | extra_x = XINT (XCAR (Vtool_bar_button_margin)); | ||
| 2303 | extra_y = XINT (XCDR (Vtool_bar_button_margin)); | ||
| 2304 | } | ||
| 2305 | else if (INTEGERP (Vtool_bar_button_margin)) | ||
| 2306 | extra_x = extra_y = XINT (Vtool_bar_button_margin); | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | x1 = x + s->slice.width - 1; | 2294 | x1 = x + s->slice.width - 1; |
| 2310 | y1 = y + s->slice.height - 1; | 2295 | y1 = y + s->slice.height - 1; |
| 2311 | top_p = bot_p = left_p = right_p = 0; | 2296 | top_p = bot_p = left_p = right_p = 0; |