diff options
| author | Kenichi Handa | 2012-09-06 10:49:15 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2012-09-06 10:49:15 +0900 |
| commit | fca81a8d405cd4c825e144099c54dd163636aa3b (patch) | |
| tree | ee09be4b0e079b9c8863c8b570496a169227b218 /src/process.c | |
| parent | f41d6f9db69ce77fe9b3a637de407e8b589e0dc4 (diff) | |
| parent | 067b39d4296765e83f9530eca456168f6cda95fc (diff) | |
| download | emacs-fca81a8d405cd4c825e144099c54dd163636aa3b.tar.gz emacs-fca81a8d405cd4c825e144099c54dd163636aa3b.zip | |
merge trunk
Diffstat (limited to 'src/process.c')
| -rw-r--r-- | src/process.c | 256 |
1 files changed, 129 insertions, 127 deletions
diff --git a/src/process.c b/src/process.c index 5677da36881..3a6615fb505 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -124,6 +124,14 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 124 | #include "xgselect.h" | 124 | #include "xgselect.h" |
| 125 | #endif | 125 | #endif |
| 126 | 126 | ||
| 127 | #ifndef WNOHANG | ||
| 128 | # undef waitpid | ||
| 129 | # define waitpid(pid, status, options) wait (status) | ||
| 130 | #endif | ||
| 131 | #ifndef WUNTRACED | ||
| 132 | # define WUNTRACED 0 | ||
| 133 | #endif | ||
| 134 | |||
| 127 | /* Work around GCC 4.7.0 bug with strict overflow checking; see | 135 | /* Work around GCC 4.7.0 bug with strict overflow checking; see |
| 128 | <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. | 136 | <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. |
| 129 | These lines can be removed once the GCC bug is fixed. */ | 137 | These lines can be removed once the GCC bug is fixed. */ |
| @@ -801,7 +809,7 @@ get_process (register Lisp_Object name) | |||
| 801 | #ifdef SIGCHLD | 809 | #ifdef SIGCHLD |
| 802 | /* Fdelete_process promises to immediately forget about the process, but in | 810 | /* Fdelete_process promises to immediately forget about the process, but in |
| 803 | reality, Emacs needs to remember those processes until they have been | 811 | reality, Emacs needs to remember those processes until they have been |
| 804 | treated by sigchld_handler; otherwise this handler would consider the | 812 | treated by the SIGCHLD handler; otherwise this handler would consider the |
| 805 | process as being synchronous and say that the synchronous process is | 813 | process as being synchronous and say that the synchronous process is |
| 806 | dead. */ | 814 | dead. */ |
| 807 | static Lisp_Object deleted_pid_list; | 815 | static Lisp_Object deleted_pid_list; |
| @@ -849,7 +857,8 @@ nil, indicating the current buffer's process. */) | |||
| 849 | #endif | 857 | #endif |
| 850 | { | 858 | { |
| 851 | Fkill_process (process, Qnil); | 859 | Fkill_process (process, Qnil); |
| 852 | /* Do this now, since remove_process will make sigchld_handler do nothing. */ | 860 | /* Do this now, since remove_process will make the |
| 861 | SIGCHLD handler do nothing. */ | ||
| 853 | pset_status (p, Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil))); | 862 | pset_status (p, Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil))); |
| 854 | p->tick = ++process_tick; | 863 | p->tick = ++process_tick; |
| 855 | status_notify (p); | 864 | status_notify (p); |
| @@ -1728,7 +1737,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1728 | if (inchannel > max_process_desc) | 1737 | if (inchannel > max_process_desc) |
| 1729 | max_process_desc = inchannel; | 1738 | max_process_desc = inchannel; |
| 1730 | 1739 | ||
| 1731 | /* Until we store the proper pid, enable sigchld_handler | 1740 | /* Until we store the proper pid, enable the SIGCHLD handler |
| 1732 | to recognize an unknown pid as standing for this process. | 1741 | to recognize an unknown pid as standing for this process. |
| 1733 | It is very important not to let this `marker' value stay | 1742 | It is very important not to let this `marker' value stay |
| 1734 | in the table after this function has returned; if it does | 1743 | in the table after this function has returned; if it does |
| @@ -4956,8 +4965,8 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 4956 | 4965 | ||
| 4957 | if (p->pid == -2) | 4966 | if (p->pid == -2) |
| 4958 | { | 4967 | { |
| 4959 | /* If the EIO occurs on a pty, sigchld_handler's | 4968 | /* If the EIO occurs on a pty, the SIGCHLD handler's |
| 4960 | waitpid() will not find the process object to | 4969 | waitpid call will not find the process object to |
| 4961 | delete. Do it here. */ | 4970 | delete. Do it here. */ |
| 4962 | p->tick = ++process_tick; | 4971 | p->tick = ++process_tick; |
| 4963 | pset_status (p, Qfailed); | 4972 | pset_status (p, Qfailed); |
| @@ -5422,18 +5431,19 @@ read_process_output (Lisp_Object proc, register int channel) | |||
| 5422 | static jmp_buf send_process_frame; | 5431 | static jmp_buf send_process_frame; |
| 5423 | static Lisp_Object process_sent_to; | 5432 | static Lisp_Object process_sent_to; |
| 5424 | 5433 | ||
| 5425 | #ifndef FORWARD_SIGNAL_TO_MAIN_THREAD | 5434 | static _Noreturn void |
| 5426 | static _Noreturn void send_process_trap (int); | 5435 | handle_pipe_signal (int sig) |
| 5427 | #endif | ||
| 5428 | |||
| 5429 | static void | ||
| 5430 | send_process_trap (int ignore) | ||
| 5431 | { | 5436 | { |
| 5432 | SIGNAL_THREAD_CHECK (SIGPIPE); | ||
| 5433 | sigunblock (sigmask (SIGPIPE)); | 5437 | sigunblock (sigmask (SIGPIPE)); |
| 5434 | _longjmp (send_process_frame, 1); | 5438 | _longjmp (send_process_frame, 1); |
| 5435 | } | 5439 | } |
| 5436 | 5440 | ||
| 5441 | static void | ||
| 5442 | deliver_pipe_signal (int sig) | ||
| 5443 | { | ||
| 5444 | handle_on_main_thread (sig, handle_pipe_signal); | ||
| 5445 | } | ||
| 5446 | |||
| 5437 | /* In send_process, when a write fails temporarily, | 5447 | /* In send_process, when a write fails temporarily, |
| 5438 | wait_reading_process_output is called. It may execute user code, | 5448 | wait_reading_process_output is called. It may execute user code, |
| 5439 | e.g. timers, that attempts to write new data to the same process. | 5449 | e.g. timers, that attempts to write new data to the same process. |
| @@ -5663,7 +5673,7 @@ send_process (volatile Lisp_Object proc, const char *volatile buf, | |||
| 5663 | /* Send this batch, using one or more write calls. */ | 5673 | /* Send this batch, using one or more write calls. */ |
| 5664 | ptrdiff_t written = 0; | 5674 | ptrdiff_t written = 0; |
| 5665 | int outfd = p->outfd; | 5675 | int outfd = p->outfd; |
| 5666 | old_sigpipe = (void (*) (int)) signal (SIGPIPE, send_process_trap); | 5676 | old_sigpipe = signal (SIGPIPE, deliver_pipe_signal); |
| 5667 | #ifdef DATAGRAM_SOCKETS | 5677 | #ifdef DATAGRAM_SOCKETS |
| 5668 | if (DATAGRAM_CHAN_P (outfd)) | 5678 | if (DATAGRAM_CHAN_P (outfd)) |
| 5669 | { | 5679 | { |
| @@ -6397,143 +6407,135 @@ process has been transmitted to the serial port. */) | |||
| 6397 | indirectly; if it does, that is a bug */ | 6407 | indirectly; if it does, that is a bug */ |
| 6398 | 6408 | ||
| 6399 | #ifdef SIGCHLD | 6409 | #ifdef SIGCHLD |
| 6400 | static void | 6410 | |
| 6401 | sigchld_handler (int signo) | 6411 | /* Record one child's changed status. Return true if a child was found. */ |
| 6412 | static bool | ||
| 6413 | record_child_status_change (void) | ||
| 6402 | { | 6414 | { |
| 6403 | int old_errno = errno; | ||
| 6404 | Lisp_Object proc; | 6415 | Lisp_Object proc; |
| 6405 | struct Lisp_Process *p; | 6416 | struct Lisp_Process *p; |
| 6417 | pid_t pid; | ||
| 6418 | int w; | ||
| 6419 | Lisp_Object tail; | ||
| 6406 | 6420 | ||
| 6407 | SIGNAL_THREAD_CHECK (signo); | 6421 | do |
| 6408 | 6422 | pid = waitpid (-1, &w, WNOHANG | WUNTRACED); | |
| 6409 | while (1) | 6423 | while (pid < 0 && errno == EINTR); |
| 6410 | { | ||
| 6411 | pid_t pid; | ||
| 6412 | int w; | ||
| 6413 | Lisp_Object tail; | ||
| 6414 | |||
| 6415 | #ifdef WNOHANG | ||
| 6416 | #ifndef WUNTRACED | ||
| 6417 | #define WUNTRACED 0 | ||
| 6418 | #endif /* no WUNTRACED */ | ||
| 6419 | /* Keep trying to get a status until we get a definitive result. */ | ||
| 6420 | do | ||
| 6421 | { | ||
| 6422 | errno = 0; | ||
| 6423 | pid = waitpid (-1, &w, WNOHANG | WUNTRACED); | ||
| 6424 | } | ||
| 6425 | while (pid < 0 && errno == EINTR); | ||
| 6426 | |||
| 6427 | if (pid <= 0) | ||
| 6428 | { | ||
| 6429 | /* PID == 0 means no processes found, PID == -1 means a real | ||
| 6430 | failure. We have done all our job, so return. */ | ||
| 6431 | 6424 | ||
| 6432 | errno = old_errno; | 6425 | /* PID == 0 means no processes found, PID == -1 means a real failure. |
| 6433 | return; | 6426 | Either way, we have done all our job. */ |
| 6434 | } | 6427 | if (pid <= 0) |
| 6435 | #else | 6428 | return false; |
| 6436 | pid = wait (&w); | ||
| 6437 | #endif /* no WNOHANG */ | ||
| 6438 | 6429 | ||
| 6439 | /* Find the process that signaled us, and record its status. */ | 6430 | /* Find the process that signaled us, and record its status. */ |
| 6440 | 6431 | ||
| 6441 | /* The process can have been deleted by Fdelete_process. */ | 6432 | /* The process can have been deleted by Fdelete_process. */ |
| 6442 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) | 6433 | for (tail = deleted_pid_list; CONSP (tail); tail = XCDR (tail)) |
| 6434 | { | ||
| 6435 | Lisp_Object xpid = XCAR (tail); | ||
| 6436 | if ((INTEGERP (xpid) && pid == XINT (xpid)) | ||
| 6437 | || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid))) | ||
| 6443 | { | 6438 | { |
| 6444 | Lisp_Object xpid = XCAR (tail); | 6439 | XSETCAR (tail, Qnil); |
| 6445 | if ((INTEGERP (xpid) && pid == XINT (xpid)) | 6440 | return true; |
| 6446 | || (FLOATP (xpid) && pid == XFLOAT_DATA (xpid))) | ||
| 6447 | { | ||
| 6448 | XSETCAR (tail, Qnil); | ||
| 6449 | goto sigchld_end_of_loop; | ||
| 6450 | } | ||
| 6451 | } | 6441 | } |
| 6442 | } | ||
| 6452 | 6443 | ||
| 6453 | /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ | 6444 | /* Otherwise, if it is asynchronous, it is in Vprocess_alist. */ |
| 6445 | p = 0; | ||
| 6446 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) | ||
| 6447 | { | ||
| 6448 | proc = XCDR (XCAR (tail)); | ||
| 6449 | p = XPROCESS (proc); | ||
| 6450 | if (EQ (p->type, Qreal) && p->pid == pid) | ||
| 6451 | break; | ||
| 6454 | p = 0; | 6452 | p = 0; |
| 6455 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) | 6453 | } |
| 6456 | { | ||
| 6457 | proc = XCDR (XCAR (tail)); | ||
| 6458 | p = XPROCESS (proc); | ||
| 6459 | if (EQ (p->type, Qreal) && p->pid == pid) | ||
| 6460 | break; | ||
| 6461 | p = 0; | ||
| 6462 | } | ||
| 6463 | |||
| 6464 | /* Look for an asynchronous process whose pid hasn't been filled | ||
| 6465 | in yet. */ | ||
| 6466 | if (p == 0) | ||
| 6467 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) | ||
| 6468 | { | ||
| 6469 | proc = XCDR (XCAR (tail)); | ||
| 6470 | p = XPROCESS (proc); | ||
| 6471 | if (p->pid == -1) | ||
| 6472 | break; | ||
| 6473 | p = 0; | ||
| 6474 | } | ||
| 6475 | |||
| 6476 | /* Change the status of the process that was found. */ | ||
| 6477 | if (p != 0) | ||
| 6478 | { | ||
| 6479 | int clear_desc_flag = 0; | ||
| 6480 | 6454 | ||
| 6481 | p->tick = ++process_tick; | 6455 | /* Look for an asynchronous process whose pid hasn't been filled |
| 6482 | p->raw_status = w; | 6456 | in yet. */ |
| 6483 | p->raw_status_new = 1; | 6457 | if (! p) |
| 6458 | for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail)) | ||
| 6459 | { | ||
| 6460 | proc = XCDR (XCAR (tail)); | ||
| 6461 | p = XPROCESS (proc); | ||
| 6462 | if (p->pid == -1) | ||
| 6463 | break; | ||
| 6464 | p = 0; | ||
| 6465 | } | ||
| 6484 | 6466 | ||
| 6485 | /* If process has terminated, stop waiting for its output. */ | 6467 | /* Change the status of the process that was found. */ |
| 6486 | if ((WIFSIGNALED (w) || WIFEXITED (w)) | 6468 | if (p) |
| 6487 | && p->infd >= 0) | 6469 | { |
| 6488 | clear_desc_flag = 1; | 6470 | int clear_desc_flag = 0; |
| 6489 | 6471 | ||
| 6490 | /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */ | 6472 | p->tick = ++process_tick; |
| 6491 | if (clear_desc_flag) | 6473 | p->raw_status = w; |
| 6492 | { | 6474 | p->raw_status_new = 1; |
| 6493 | FD_CLR (p->infd, &input_wait_mask); | ||
| 6494 | FD_CLR (p->infd, &non_keyboard_wait_mask); | ||
| 6495 | } | ||
| 6496 | 6475 | ||
| 6497 | /* Tell wait_reading_process_output that it needs to wake up and | 6476 | /* If process has terminated, stop waiting for its output. */ |
| 6498 | look around. */ | 6477 | if ((WIFSIGNALED (w) || WIFEXITED (w)) |
| 6499 | if (input_available_clear_time) | 6478 | && p->infd >= 0) |
| 6500 | *input_available_clear_time = make_emacs_time (0, 0); | 6479 | clear_desc_flag = 1; |
| 6501 | } | ||
| 6502 | 6480 | ||
| 6503 | /* There was no asynchronous process found for that pid: we have | 6481 | /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */ |
| 6504 | a synchronous process. */ | 6482 | if (clear_desc_flag) |
| 6505 | else | ||
| 6506 | { | 6483 | { |
| 6507 | synch_process_alive = 0; | 6484 | FD_CLR (p->infd, &input_wait_mask); |
| 6508 | 6485 | FD_CLR (p->infd, &non_keyboard_wait_mask); | |
| 6509 | /* Report the status of the synchronous process. */ | ||
| 6510 | if (WIFEXITED (w)) | ||
| 6511 | synch_process_retcode = WEXITSTATUS (w); | ||
| 6512 | else if (WIFSIGNALED (w)) | ||
| 6513 | synch_process_termsig = WTERMSIG (w); | ||
| 6514 | |||
| 6515 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6516 | look around. */ | ||
| 6517 | if (input_available_clear_time) | ||
| 6518 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6519 | } | 6486 | } |
| 6520 | 6487 | ||
| 6521 | sigchld_end_of_loop: | 6488 | /* Tell wait_reading_process_output that it needs to wake up and |
| 6522 | ; | 6489 | look around. */ |
| 6490 | if (input_available_clear_time) | ||
| 6491 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6492 | } | ||
| 6493 | /* There was no asynchronous process found for that pid: we have | ||
| 6494 | a synchronous process. */ | ||
| 6495 | else | ||
| 6496 | { | ||
| 6497 | synch_process_alive = 0; | ||
| 6498 | |||
| 6499 | /* Report the status of the synchronous process. */ | ||
| 6500 | if (WIFEXITED (w)) | ||
| 6501 | synch_process_retcode = WEXITSTATUS (w); | ||
| 6502 | else if (WIFSIGNALED (w)) | ||
| 6503 | synch_process_termsig = WTERMSIG (w); | ||
| 6504 | |||
| 6505 | /* Tell wait_reading_process_output that it needs to wake up and | ||
| 6506 | look around. */ | ||
| 6507 | if (input_available_clear_time) | ||
| 6508 | *input_available_clear_time = make_emacs_time (0, 0); | ||
| 6509 | } | ||
| 6510 | |||
| 6511 | return true; | ||
| 6512 | } | ||
| 6523 | 6513 | ||
| 6524 | /* On some systems, we must return right away. | 6514 | /* On some systems, the SIGCHLD handler must return right away. If |
| 6525 | If any more processes want to signal us, we will | 6515 | any more processes want to signal us, we will get another signal. |
| 6526 | get another signal. | 6516 | Otherwise, loop around to use up all the processes that have |
| 6527 | Otherwise (on systems that have WNOHANG), loop around | 6517 | something to tell us. */ |
| 6528 | to use up all the processes that have something to tell us. */ | ||
| 6529 | #if (defined WINDOWSNT \ | 6518 | #if (defined WINDOWSNT \ |
| 6530 | || (defined USG && !defined GNU_LINUX \ | 6519 | || (defined USG && !defined GNU_LINUX \ |
| 6531 | && !(defined HPUX && defined WNOHANG))) | 6520 | && !(defined HPUX && defined WNOHANG))) |
| 6532 | errno = old_errno; | 6521 | enum { CAN_HANDLE_MULTIPLE_CHILDREN = 1 }; |
| 6533 | return; | 6522 | #else |
| 6534 | #endif /* USG, but not HPUX with WNOHANG */ | 6523 | enum { CAN_HANDLE_MULTIPLE_CHILDREN = 0 }; |
| 6535 | } | 6524 | #endif |
| 6525 | |||
| 6526 | static void | ||
| 6527 | handle_child_signal (int sig) | ||
| 6528 | { | ||
| 6529 | while (record_child_status_change () && CAN_HANDLE_MULTIPLE_CHILDREN) | ||
| 6530 | continue; | ||
| 6536 | } | 6531 | } |
| 6532 | |||
| 6533 | static void | ||
| 6534 | deliver_child_signal (int sig) | ||
| 6535 | { | ||
| 6536 | handle_on_main_thread (sig, handle_child_signal); | ||
| 6537 | } | ||
| 6538 | |||
| 6537 | #endif /* SIGCHLD */ | 6539 | #endif /* SIGCHLD */ |
| 6538 | 6540 | ||
| 6539 | 6541 | ||
| @@ -7387,7 +7389,7 @@ init_process_emacs (void) | |||
| 7387 | #ifndef CANNOT_DUMP | 7389 | #ifndef CANNOT_DUMP |
| 7388 | if (! noninteractive || initialized) | 7390 | if (! noninteractive || initialized) |
| 7389 | #endif | 7391 | #endif |
| 7390 | signal (SIGCHLD, sigchld_handler); | 7392 | signal (SIGCHLD, deliver_child_signal); |
| 7391 | #endif | 7393 | #endif |
| 7392 | 7394 | ||
| 7393 | FD_ZERO (&input_wait_mask); | 7395 | FD_ZERO (&input_wait_mask); |