aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoakim Verona2012-12-04 01:46:34 +0100
committerJoakim Verona2012-12-04 01:46:34 +0100
commitd28fde00abbbf26b7c80700b1c9bc18b5079a30e (patch)
tree3bf606901b01f67d6b2eed3998ac6fae9f4518a8 /src
parentfa8510a9aabe34d367d935b960eab0abbf060e18 (diff)
parentc38a186c2e06e0a351d166c5ef06d7307e145f45 (diff)
downloademacs-d28fde00abbbf26b7c80700b1c9bc18b5079a30e.tar.gz
emacs-d28fde00abbbf26b7c80700b1c9bc18b5079a30e.zip
auto upstream
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog134
-rw-r--r--src/alloc.c32
-rw-r--r--src/bytecode.c4
-rw-r--r--src/callproc.c255
-rw-r--r--src/casefiddle.c2
-rw-r--r--src/charset.c4
-rw-r--r--src/data.c8
-rw-r--r--src/doprnt.c5
-rw-r--r--src/editfns.c91
-rw-r--r--src/fileio.c2
-rw-r--r--src/gtkutil.c15
-rw-r--r--src/insdel.c21
-rw-r--r--src/lisp.h4
-rw-r--r--src/process.c151
-rw-r--r--src/process.h17
-rw-r--r--src/sysdep.c80
-rw-r--r--src/syswait.h7
-rw-r--r--src/textprop.c24
-rw-r--r--src/w32.c8
-rw-r--r--src/w32common.h2
-rw-r--r--src/w32fns.c5
-rw-r--r--src/w32proc.c28
-rw-r--r--src/xdisp.c29
-rw-r--r--src/xterm.c15
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 @@
12012-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
632012-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
682012-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
732012-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
822012-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
932012-12-03 Chong Yidong <cyd@gnu.org>
94
95 * fileio.c (Vauto_save_list_file_name): Doc fix.
96
972012-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
1112012-12-03 Glenn Morris <rgm@gnu.org>
112
113 * data.c (Fboundp, Fsymbol_value): Doc fix re lexical-binding.
114
1152012-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
1312012-12-01 Paul Eggert <eggert@cs.ucla.edu>
132
133 * xterm.c (x_draw_image_relief): Remove unused locals (Bug#10500).
134
12012-12-01 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> 1352012-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
772void * 776void *
773xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min, 777xpalloc (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
@@ -822,12 +826,7 @@ xstrdup (const char *s)
822Lisp_Object 826Lisp_Object
823safe_alloca_unwind (Lisp_Object arg) 827safe_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
3365void
3366free_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
3366Lisp_Object 3378Lisp_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
90Lisp_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,
1963void 1961void
1964syms_of_bytecode (void) 1962syms_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. */
68static Lisp_Object Vtemp_file_name_pattern; 68static 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
72bool 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
75const 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. */
80static pid_t synch_process_pid;
81
82/* If nonnegative, a file descriptor that has not been closed. */
83static int synch_process_fd;
84
85/* Block SIGCHLD. */
76 86
77/* Nonzero => this is the signal number that terminated the subprocess. */ 87static void
78int synch_process_termsig; 88block_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. */
82int synch_process_retcode;
83 99
84 100static void
85/* Clean up when exiting Fcall_process. 101unblock_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. */
90static bool call_process_exited;
91 109
92static Lisp_Object 110static Lisp_Object
93call_process_kill (Lisp_Object fdpid) 111call_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
105static Lisp_Object 134static Lisp_Object
106call_process_cleanup (Lisp_Object arg) 135call_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.
181usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) 203usage: (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
900static Lisp_Object 913static 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
508DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0, 508DEFUN ("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.
510Note that if `lexical-binding' is in effect, this refers to the
511global 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
1049DEFUN ("symbol-value", Fsymbol_value, Ssymbol_value, 1, 1, 0, 1051DEFUN ("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.
1053Note that if `lexical-binding' is in effect, this returns the
1054global 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
817Lisp_Object 820Lisp_Object
818save_excursion_save (void) 821save_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
834Lisp_Object 842Lisp_Object
835save_excursion_restore (Lisp_Object info) 843save_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.
5773This variable is initialized automatically from `auto-save-list-file-prefix' 5773This variable is initialized automatically from `auto-save-list-file-prefix'
5774shortly after Emacs reads your `.emacs' file, if you have not yet given it 5774shortly after Emacs reads your init file, if you have not yet given it
5775a non-nil value. */); 5775a 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
816static void
817my_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
1768void 1768void
1769modify_region (struct buffer *buffer, ptrdiff_t start, ptrdiff_t end, 1769modify_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);
2801extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool); 2801extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool);
2802extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t, 2802extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t,
2803 ptrdiff_t, ptrdiff_t, bool); 2803 ptrdiff_t, ptrdiff_t, bool);
2804extern void modify_region (struct buffer *, ptrdiff_t, ptrdiff_t, bool); 2804extern void modify_region_1 (ptrdiff_t, ptrdiff_t, bool);
2805extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *); 2805extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
2806extern void signal_after_change (ptrdiff_t, ptrdiff_t, ptrdiff_t); 2806extern void signal_after_change (ptrdiff_t, ptrdiff_t, ptrdiff_t);
2807extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t, 2807extern void adjust_after_insert (ptrdiff_t, ptrdiff_t, ptrdiff_t,
@@ -2968,6 +2968,7 @@ extern Lisp_Object make_float (double);
2968extern void display_malloc_warning (void); 2968extern void display_malloc_warning (void);
2969extern ptrdiff_t inhibit_garbage_collection (void); 2969extern ptrdiff_t inhibit_garbage_collection (void);
2970extern Lisp_Object make_save_value (void *, ptrdiff_t); 2970extern Lisp_Object make_save_value (void *, ptrdiff_t);
2971extern void free_save_value (Lisp_Object);
2971extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); 2972extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object);
2972extern void free_marker (Lisp_Object); 2973extern void free_marker (Lisp_Object);
2973extern void free_cons (struct Lisp_Cons *); 2974extern void free_cons (struct Lisp_Cons *);
@@ -3398,7 +3399,6 @@ extern void syms_of_doc (void);
3398extern int read_bytecode_char (bool); 3399extern int read_bytecode_char (bool);
3399 3400
3400/* Defined in bytecode.c. */ 3401/* Defined in bytecode.c. */
3401extern Lisp_Object Qbytecode;
3402extern void syms_of_bytecode (void); 3402extern void syms_of_bytecode (void);
3403extern struct byte_stack *byte_stack_list; 3403extern 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. */
781static Lisp_Object deleted_pid_list; 783static Lisp_Object deleted_pid_list;
782#endif 784#endif
783 785
786void
787record_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
784DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0, 797DEFUN ("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.
786PROCESS may be a process, a buffer, the name of a process or buffer, or 799PROCESS 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
6168static bool 6163/* The main Emacs thread records child processes in three places:
6169process_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
6214void 6214static void
6215record_child_status_change (pid_t pid, int w) 6215handle_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
6311static void
6312handle_child_signal (int sig)
6313{
6314 record_child_status_change (-1, 0);
6315} 6272}
6316 6273
6317static void 6274static 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. */
190extern 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. */
196extern const char *synch_process_death;
197
198/* Nonzero => this is the signal number that terminated the subprocess. */
199extern int synch_process_termsig;
200
201/* If synch_process_death is zero,
202 this is exit code of synchronous subprocess. */
203extern 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. */
207extern int inhibit_sentinels; 190extern 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
269static void 269/* Wait for the subprocess with process id CHILD to terminate or change status.
270wait_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. */
278static pid_t
279get_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. */
297void 315void
298wait_for_termination (pid_t pid) 316wait_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.
304void 322 Termination counts as a change of status.
305interruptible_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. */
330pid_t
331child_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
573static void 597static 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. */
55extern void record_child_status_change (pid_t, int); 56extern void record_deleted_pid (pid_t);
56 57
57/* Defined in sysdep.c. */ 58/* Defined in sysdep.c. */
58extern void wait_for_termination (pid_t); 59extern void wait_for_termination (pid_t, int *, bool);
59extern void interruptible_wait_for_termination (pid_t); 60extern 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
90static void
91modify_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 }
diff --git a/src/w32.c b/src/w32.c
index c8e16dfaa94..e81fc7b4f3e 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -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
35extern SYSTEM_INFO sysinfo_cache; 35extern SYSTEM_INFO sysinfo_cache;
36extern OSVERSIONINFO osinfo_cache; 36extern OSVERSIONINFO osinfo_cache;
37extern unsigned long syspage_mask; 37extern DWORD_PTR syspage_mask;
38 38
39extern int w32_major_version; 39extern int w32_major_version;
40extern int w32_minor_version; 40extern 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);
82void globals_of_w32fns (void); 82void globals_of_w32fns (void);
83 83
84extern void free_frame_menubar (struct frame *); 84extern void free_frame_menubar (struct frame *);
85extern double atof (const char *);
86extern int w32_console_toggle_lock_key (int, Lisp_Object); 85extern int w32_console_toggle_lock_key (int, Lisp_Object);
87extern void w32_menu_display_help (HWND, HMENU, UINT, UINT); 86extern void w32_menu_display_help (HWND, HMENU, UINT, UINT);
88extern void w32_free_menu_strings (HWND); 87extern 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. */
224OSVERSIONINFO osinfo_cache; 223OSVERSIONINFO osinfo_cache;
225 224
226unsigned long syspage_mask = 0; 225DWORD_PTR syspage_mask = 0;
227 226
228/* The major and minor versions of NT. */ 227/* The major and minor versions of NT. */
229int w32_major_version; 228int 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. */
6038static UINT CALLBACK 6037static UINT_PTR CALLBACK
6039file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 6038file_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
2261x_draw_image_relief (struct glyph_string *s) 2261x_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;