diff options
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 151 |
1 files changed, 54 insertions, 97 deletions
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 |