aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
authorAndrea Corallo2021-01-24 21:05:33 +0100
committerAndrea Corallo2021-01-24 21:05:33 +0100
commitb8d3ae78c54db7c7bb65d367a80f9be3d8744c48 (patch)
tree982f190d1dd79685c43a9829dd66e6a7cbbd0c67 /src/process.c
parent0ffb3dfaa483b0c5cf1f7f367efcb5e9c041ab53 (diff)
parente5aaa1251cfb9d6d18682a5eda137a2e12ca4213 (diff)
downloademacs-b8d3ae78c54db7c7bb65d367a80f9be3d8744c48.tar.gz
emacs-b8d3ae78c54db7c7bb65d367a80f9be3d8744c48.zip
Merge remote-tracking branch 'savannah/master' into native-comp
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/src/process.c b/src/process.c
index dac7d0440fa..1df4ed9ce03 100644
--- a/src/process.c
+++ b/src/process.c
@@ -283,6 +283,18 @@ static int max_desc;
283 the file descriptor of a socket that is already bound. */ 283 the file descriptor of a socket that is already bound. */
284static int external_sock_fd; 284static int external_sock_fd;
285 285
286/* File descriptor that becomes readable when we receive SIGCHLD. */
287static int child_signal_read_fd = -1;
288/* The write end thereof. The SIGCHLD handler writes to this file
289 descriptor to notify `wait_reading_process_output' of process
290 status changes. */
291static int child_signal_write_fd = -1;
292static void child_signal_init (void);
293#ifndef WINDOWSNT
294static void child_signal_read (int, void *);
295#endif
296static void child_signal_notify (void);
297
286/* Indexed by descriptor, gives the process (if any) for that descriptor. */ 298/* Indexed by descriptor, gives the process (if any) for that descriptor. */
287static Lisp_Object chan_process[FD_SETSIZE]; 299static Lisp_Object chan_process[FD_SETSIZE];
288static void wait_for_socket_fds (Lisp_Object, char const *); 300static void wait_for_socket_fds (Lisp_Object, char const *);
@@ -2060,6 +2072,10 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
2060 Lisp_Object lisp_pty_name = Qnil; 2072 Lisp_Object lisp_pty_name = Qnil;
2061 sigset_t oldset; 2073 sigset_t oldset;
2062 2074
2075 /* Ensure that the SIGCHLD handler can notify
2076 `wait_reading_process_output'. */
2077 child_signal_init ();
2078
2063 inchannel = outchannel = -1; 2079 inchannel = outchannel = -1;
2064 2080
2065 if (p->pty_flag) 2081 if (p->pty_flag)
@@ -5309,6 +5325,15 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5309 compute_input_wait_mask (&Atemp); 5325 compute_input_wait_mask (&Atemp);
5310 compute_write_mask (&Ctemp); 5326 compute_write_mask (&Ctemp);
5311 5327
5328 /* If a process status has changed, the child signal pipe
5329 will likely be readable. We want to ignore it for now,
5330 because otherwise we wouldn't run into a timeout
5331 below. */
5332 int fd = child_signal_read_fd;
5333 eassert (fd < FD_SETSIZE);
5334 if (0 <= fd)
5335 FD_CLR (fd, &Atemp);
5336
5312 timeout = make_timespec (0, 0); 5337 timeout = make_timespec (0, 0);
5313 if ((thread_select (pselect, max_desc + 1, 5338 if ((thread_select (pselect, max_desc + 1,
5314 &Atemp, 5339 &Atemp,
@@ -5395,6 +5420,14 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
5395 check_write = true; 5420 check_write = true;
5396 } 5421 }
5397 5422
5423 /* We have to be informed when we receive a SIGCHLD signal for
5424 an asynchronous process. Otherwise this might deadlock if we
5425 receive a SIGCHLD during `pselect'. */
5426 int child_fd = child_signal_read_fd;
5427 eassert (child_fd < FD_SETSIZE);
5428 if (0 <= child_fd)
5429 FD_SET (child_fd, &Available);
5430
5398 /* If frame size has changed or the window is newly mapped, 5431 /* If frame size has changed or the window is newly mapped,
5399 redisplay now, before we start to wait. There is a race 5432 redisplay now, before we start to wait. There is a race
5400 condition here; if a SIGIO arrives between now and the select 5433 condition here; if a SIGIO arrives between now and the select
@@ -7114,7 +7147,95 @@ process has been transmitted to the serial port. */)
7114 subprocesses which the main thread should not reap. For example, 7147 subprocesses which the main thread should not reap. For example,
7115 if the main thread attempted to reap an already-reaped child, it 7148 if the main thread attempted to reap an already-reaped child, it
7116 might inadvertently reap a GTK-created process that happened to 7149 might inadvertently reap a GTK-created process that happened to
7117 have the same process ID. */ 7150 have the same process ID.
7151
7152 To avoid a deadlock when receiving SIGCHLD while
7153 'wait_reading_process_output' is in 'pselect', the SIGCHLD handler
7154 will notify the `pselect' using a self-pipe. The deadlock could
7155 occur if SIGCHLD is delivered outside of the 'pselect' call, in
7156 which case 'pselect' will not be interrupted by the signal, and
7157 will therefore wait on the process's output descriptor for the
7158 output that will never come.
7159
7160 WINDOWSNT doesn't need this facility because its 'pselect'
7161 emulation (see 'sys_select' in w32proc.c) waits on a subprocess
7162 handle, which becomes signaled when the process exits, and also
7163 because that emulation delays the delivery of the simulated SIGCHLD
7164 until all the output from the subprocess has been consumed. */
7165
7166/* FIXME: On Unix-like systems that have a proper 'pselect'
7167 (HAVE_PSELECT), we should block SIGCHLD in
7168 'wait_reading_process_output' and pass a non-NULL signal mask to
7169 'pselect' to avoid the need for the self-pipe. */
7170
7171/* Set up `child_signal_read_fd' and `child_signal_write_fd'. */
7172
7173static void
7174child_signal_init (void)
7175{
7176 /* Either both are initialized, or both are uninitialized. */
7177 eassert ((child_signal_read_fd < 0) == (child_signal_write_fd < 0));
7178
7179#ifndef WINDOWSNT
7180 if (0 <= child_signal_read_fd)
7181 return; /* already done */
7182
7183 int fds[2];
7184 if (emacs_pipe (fds) < 0)
7185 report_file_error ("Creating pipe for child signal", Qnil);
7186 if (FD_SETSIZE <= fds[0])
7187 {
7188 /* Since we need to `pselect' on the read end, it has to fit
7189 into an `fd_set'. */
7190 emacs_close (fds[0]);
7191 emacs_close (fds[1]);
7192 report_file_errno ("Creating pipe for child signal", Qnil,
7193 EMFILE);
7194 }
7195
7196 /* We leave the file descriptors open until the Emacs process
7197 exits. */
7198 eassert (0 <= fds[0]);
7199 eassert (0 <= fds[1]);
7200 if (fcntl (fds[0], F_SETFL, O_NONBLOCK) != 0)
7201 emacs_perror ("fcntl");
7202 if (fcntl (fds[1], F_SETFL, O_NONBLOCK) != 0)
7203 emacs_perror ("fcntl");
7204 add_read_fd (fds[0], child_signal_read, NULL);
7205 fd_callback_info[fds[0]].flags &= ~KEYBOARD_FD;
7206 child_signal_read_fd = fds[0];
7207 child_signal_write_fd = fds[1];
7208#endif /* !WINDOWSNT */
7209}
7210
7211#ifndef WINDOWSNT
7212/* Consume a process status change. */
7213
7214static void
7215child_signal_read (int fd, void *data)
7216{
7217 eassert (0 <= fd);
7218 eassert (fd == child_signal_read_fd);
7219 char dummy;
7220 if (emacs_read (fd, &dummy, 1) < 0)
7221 emacs_perror ("reading from child signal FD");
7222}
7223#endif /* !WINDOWSNT */
7224
7225/* Notify `wait_reading_process_output' of a process status
7226 change. */
7227
7228static void
7229child_signal_notify (void)
7230{
7231#ifndef WINDOWSNT
7232 int fd = child_signal_write_fd;
7233 eassert (0 <= fd);
7234 char dummy = 0;
7235 if (emacs_write (fd, &dummy, 1) != 1)
7236 emacs_perror ("writing to child signal FD");
7237#endif
7238}
7118 7239
7119/* LIB_CHILD_HANDLER is a SIGCHLD handler that Emacs calls while doing 7240/* LIB_CHILD_HANDLER is a SIGCHLD handler that Emacs calls while doing
7120 its own SIGCHLD handling. On POSIXish systems, glib needs this to 7241 its own SIGCHLD handling. On POSIXish systems, glib needs this to
@@ -7152,6 +7273,7 @@ static void
7152handle_child_signal (int sig) 7273handle_child_signal (int sig)
7153{ 7274{
7154 Lisp_Object tail, proc; 7275 Lisp_Object tail, proc;
7276 bool changed = false;
7155 7277
7156 /* Find the process that signaled us, and record its status. */ 7278 /* Find the process that signaled us, and record its status. */
7157 7279
@@ -7174,6 +7296,7 @@ handle_child_signal (int sig)
7174 eassert (ok); 7296 eassert (ok);
7175 if (child_status_changed (deleted_pid, 0, 0)) 7297 if (child_status_changed (deleted_pid, 0, 0))
7176 { 7298 {
7299 changed = true;
7177 if (STRINGP (XCDR (head))) 7300 if (STRINGP (XCDR (head)))
7178 unlink (SSDATA (XCDR (head))); 7301 unlink (SSDATA (XCDR (head)));
7179 XSETCAR (tail, Qnil); 7302 XSETCAR (tail, Qnil);
@@ -7191,6 +7314,7 @@ handle_child_signal (int sig)
7191 && child_status_changed (p->pid, &status, WUNTRACED | WCONTINUED)) 7314 && child_status_changed (p->pid, &status, WUNTRACED | WCONTINUED))
7192 { 7315 {
7193 /* Change the status of the process that was found. */ 7316 /* Change the status of the process that was found. */
7317 changed = true;
7194 p->tick = ++process_tick; 7318 p->tick = ++process_tick;
7195 p->raw_status = status; 7319 p->raw_status = status;
7196 p->raw_status_new = 1; 7320 p->raw_status_new = 1;
@@ -7210,6 +7334,10 @@ handle_child_signal (int sig)
7210 } 7334 }
7211 } 7335 }
7212 7336
7337 if (changed)
7338 /* Wake up `wait_reading_process_output'. */
7339 child_signal_notify ();
7340
7213 lib_child_handler (sig); 7341 lib_child_handler (sig);
7214#ifdef NS_IMPL_GNUSTEP 7342#ifdef NS_IMPL_GNUSTEP
7215 /* NSTask in GNUstep sets its child handler each time it is called. 7343 /* NSTask in GNUstep sets its child handler each time it is called.