diff options
| author | Paul Eggert | 2013-06-23 17:31:31 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-06-23 17:31:31 -0700 |
| commit | fa55d2aaa23d5916b87a6980c9606466e07df124 (patch) | |
| tree | 673a2d3e86802766c2183a8d6f5744722fd73737 /src | |
| parent | 5e400cb3ed7b0ffc5f166e4cd9c4e18f4e58c14e (diff) | |
| download | emacs-fa55d2aaa23d5916b87a6980c9606466e07df124.tar.gz emacs-fa55d2aaa23d5916b87a6980c9606466e07df124.zip | |
A more-conservative workaround for Cygwin SIGCHLD issues.
* callproc.c (Fcall_process):
* process.c (create_process):
Make sure SIGCHLD is caught before we fork,
since Emacs startup no arranges to catch SIGCHLD.
* process.c (lib_child_handler): Initialize to null, not to
dummy_handler.
(catch_child_signal): Allow self to be called lazily.
Do nothing if it's already been called.
Assume caller has blocked SIGCHLD (all callers do now).
* emacs.c (main): Do not catch SIGCHLD here; defer it until
just before it's really needed.
* nsterm.m (ns_term_init): No need to re-catch SIGCHLD here,
since it hasn't been caught yet.
Fixes: debbugs:14569
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 17 | ||||
| -rw-r--r-- | src/callproc.c | 1 | ||||
| -rw-r--r-- | src/emacs.c | 7 | ||||
| -rw-r--r-- | src/nsterm.m | 6 | ||||
| -rw-r--r-- | src/process.c | 56 |
5 files changed, 52 insertions, 35 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index f9451711f32..6357491725d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,20 @@ | |||
| 1 | 2013-06-23 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | A more-conservative workaround for Cygwin SIGCHLD issues (Bug#14569). | ||
| 4 | * callproc.c (Fcall_process): | ||
| 5 | * process.c (create_process): | ||
| 6 | Make sure SIGCHLD is caught before we fork, | ||
| 7 | since Emacs startup no arranges to catch SIGCHLD. | ||
| 8 | * process.c (lib_child_handler): Initialize to null, not to | ||
| 9 | dummy_handler. | ||
| 10 | (catch_child_signal): Allow self to be called lazily. | ||
| 11 | Do nothing if it's already been called. | ||
| 12 | Assume caller has blocked SIGCHLD (all callers do now). | ||
| 13 | * emacs.c (main): Do not catch SIGCHLD here; defer it until | ||
| 14 | just before it's really needed. | ||
| 15 | * nsterm.m (ns_term_init): No need to re-catch SIGCHLD here, | ||
| 16 | since it hasn't been caught yet. | ||
| 17 | |||
| 1 | 2013-06-23 Lars Magne Ingebrigtsen <larsi@gnus.org> | 18 | 2013-06-23 Lars Magne Ingebrigtsen <larsi@gnus.org> |
| 2 | 19 | ||
| 3 | * image.c (compute_image_size): New function to implement | 20 | * image.c (compute_image_size): New function to implement |
diff --git a/src/callproc.c b/src/callproc.c index f0aa8222342..7db984fa71c 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -613,6 +613,7 @@ usage: (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS) * | |||
| 613 | 613 | ||
| 614 | block_input (); | 614 | block_input (); |
| 615 | block_child_signal (); | 615 | block_child_signal (); |
| 616 | catch_child_signal (); | ||
| 616 | 617 | ||
| 617 | #ifdef WINDOWSNT | 618 | #ifdef WINDOWSNT |
| 618 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 619 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
diff --git a/src/emacs.c b/src/emacs.c index c5b32c7c0e7..13f6d117ebc 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -1257,13 +1257,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1257 | tzset (); | 1257 | tzset (); |
| 1258 | #endif /* MSDOS */ | 1258 | #endif /* MSDOS */ |
| 1259 | 1259 | ||
| 1260 | /* Do this after initializing the memory allocator, since it uses | ||
| 1261 | glib and glib uses malloc. And do it before anything else that | ||
| 1262 | invokes glib, to avoid potential races among glib subthreads in | ||
| 1263 | Cygwin glib. gfilenotify invokes glib, so this can't be delayed | ||
| 1264 | further. */ | ||
| 1265 | catch_child_signal (); | ||
| 1266 | |||
| 1267 | #ifdef HAVE_GFILENOTIFY | 1260 | #ifdef HAVE_GFILENOTIFY |
| 1268 | globals_of_gfilenotify (); | 1261 | globals_of_gfilenotify (); |
| 1269 | #endif | 1262 | #endif |
diff --git a/src/nsterm.m b/src/nsterm.m index 93f693fe55e..c88e5034d39 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -4360,12 +4360,6 @@ ns_term_init (Lisp_Object display_name) | |||
| 4360 | 4360 | ||
| 4361 | [NSApp run]; | 4361 | [NSApp run]; |
| 4362 | ns_do_open_file = YES; | 4362 | ns_do_open_file = YES; |
| 4363 | |||
| 4364 | #ifdef NS_IMPL_GNUSTEP | ||
| 4365 | /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask. | ||
| 4366 | We must re-catch it so subprocess works. */ | ||
| 4367 | catch_child_signal (); | ||
| 4368 | #endif | ||
| 4369 | return dpyinfo; | 4363 | return dpyinfo; |
| 4370 | } | 4364 | } |
| 4371 | 4365 | ||
diff --git a/src/process.c b/src/process.c index 6df1bf7eff7..3f062b6db16 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -1590,7 +1590,6 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1590 | #ifndef WINDOWSNT | 1590 | #ifndef WINDOWSNT |
| 1591 | int wait_child_setup[2]; | 1591 | int wait_child_setup[2]; |
| 1592 | #endif | 1592 | #endif |
| 1593 | sigset_t blocked; | ||
| 1594 | int forkin, forkout; | 1593 | int forkin, forkout; |
| 1595 | bool pty_flag = 0; | 1594 | bool pty_flag = 0; |
| 1596 | Lisp_Object lisp_pty_name = Qnil; | 1595 | Lisp_Object lisp_pty_name = Qnil; |
| @@ -1685,12 +1684,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1685 | encoded_current_dir = ENCODE_FILE (current_dir); | 1684 | encoded_current_dir = ENCODE_FILE (current_dir); |
| 1686 | 1685 | ||
| 1687 | block_input (); | 1686 | block_input (); |
| 1688 | 1687 | block_child_signal (); | |
| 1689 | /* Block SIGCHLD until we have a chance to store the new fork's | 1688 | catch_child_signal (); |
| 1690 | pid in its process structure. */ | ||
| 1691 | sigemptyset (&blocked); | ||
| 1692 | sigaddset (&blocked, SIGCHLD); | ||
| 1693 | pthread_sigmask (SIG_BLOCK, &blocked, 0); | ||
| 1694 | 1689 | ||
| 1695 | #ifndef WINDOWSNT | 1690 | #ifndef WINDOWSNT |
| 1696 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 1691 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| @@ -1822,8 +1817,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1822 | /* Emacs ignores SIGPIPE, but the child should not. */ | 1817 | /* Emacs ignores SIGPIPE, but the child should not. */ |
| 1823 | signal (SIGPIPE, SIG_DFL); | 1818 | signal (SIGPIPE, SIG_DFL); |
| 1824 | 1819 | ||
| 1825 | /* Stop blocking signals in the child. */ | 1820 | /* Stop blocking SIGCHLD in the child. */ |
| 1826 | pthread_sigmask (SIG_SETMASK, &empty_mask, 0); | 1821 | unblock_child_signal (); |
| 1827 | 1822 | ||
| 1828 | if (pty_flag) | 1823 | if (pty_flag) |
| 1829 | child_setup_tty (xforkout); | 1824 | child_setup_tty (xforkout); |
| @@ -1843,8 +1838,8 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) | |||
| 1843 | if (pid >= 0) | 1838 | if (pid >= 0) |
| 1844 | XPROCESS (process)->alive = 1; | 1839 | XPROCESS (process)->alive = 1; |
| 1845 | 1840 | ||
| 1846 | /* Stop blocking signals in the parent. */ | 1841 | /* Stop blocking in the parent. */ |
| 1847 | pthread_sigmask (SIG_SETMASK, &empty_mask, 0); | 1842 | unblock_child_signal (); |
| 1848 | unblock_input (); | 1843 | unblock_input (); |
| 1849 | 1844 | ||
| 1850 | if (pid < 0) | 1845 | if (pid < 0) |
| @@ -6125,9 +6120,10 @@ process has been transmitted to the serial port. */) | |||
| 6125 | 6120 | ||
| 6126 | /* LIB_CHILD_HANDLER is a SIGCHLD handler that Emacs calls while doing | 6121 | /* LIB_CHILD_HANDLER is a SIGCHLD handler that Emacs calls while doing |
| 6127 | its own SIGCHLD handling. On POSIXish systems, glib needs this to | 6122 | its own SIGCHLD handling. On POSIXish systems, glib needs this to |
| 6128 | keep track of its own children. The default handler does nothing. */ | 6123 | keep track of its own children. GNUstep is similar. */ |
| 6124 | |||
| 6129 | static void dummy_handler (int sig) {} | 6125 | static void dummy_handler (int sig) {} |
| 6130 | static signal_handler_t volatile lib_child_handler = dummy_handler; | 6126 | static signal_handler_t volatile lib_child_handler; |
| 6131 | 6127 | ||
| 6132 | /* Handle a SIGCHLD signal by looking for known child processes of | 6128 | /* Handle a SIGCHLD signal by looking for known child processes of |
| 6133 | Emacs whose status have changed. For each one found, record its | 6129 | Emacs whose status have changed. For each one found, record its |
| @@ -7060,7 +7056,10 @@ integer or floating point values. | |||
| 7060 | return system_process_attributes (pid); | 7056 | return system_process_attributes (pid); |
| 7061 | } | 7057 | } |
| 7062 | 7058 | ||
| 7063 | /* Arrange to catch SIGCHLD if needed. */ | 7059 | /* Arrange to catch SIGCHLD if this hasn't already been arranged. |
| 7060 | Invoke this after init_process_emacs, and after glib and/or GNUstep | ||
| 7061 | futz with the SIGCHLD handler, but before Emacs forks any children. | ||
| 7062 | This function's caller should block SIGCHLD. */ | ||
| 7064 | 7063 | ||
| 7065 | void | 7064 | void |
| 7066 | catch_child_signal (void) | 7065 | catch_child_signal (void) |
| @@ -7072,25 +7071,38 @@ catch_child_signal (void) | |||
| 7072 | return; | 7071 | return; |
| 7073 | #endif | 7072 | #endif |
| 7074 | 7073 | ||
| 7074 | #ifndef NS_IMPL_GNUSTEP | ||
| 7075 | if (lib_child_handler) | ||
| 7076 | return; | ||
| 7077 | #endif | ||
| 7078 | |||
| 7075 | #if defined HAVE_GLIB && !defined WINDOWSNT | 7079 | #if defined HAVE_GLIB && !defined WINDOWSNT |
| 7076 | /* Tickle glib's child-handling code. Ask glib to wait for Emacs itself; | 7080 | /* Tickle glib's child-handling code. Ask glib to wait for Emacs itself; |
| 7077 | this should always fail, but is enough to initialize glib's | 7081 | this should always fail, but is enough to initialize glib's |
| 7078 | private SIGCHLD handler, allowing the code below to copy it into | 7082 | private SIGCHLD handler, allowing the code below to copy it into |
| 7079 | LIB_CHILD_HANDLER. | 7083 | LIB_CHILD_HANDLER. |
| 7080 | 7084 | ||
| 7081 | Do this early in Emacs initialization, before glib creates | 7085 | Do this here, rather than early in Emacs initialization where it |
| 7082 | threads, to avoid race condition bugs in Cygwin glib. */ | 7086 | might make more sense, to try to avoid bugs in Cygwin glib (Bug#14569). */ |
| 7083 | g_source_unref (g_child_watch_source_new (getpid ())); | 7087 | { |
| 7088 | GSource *source = g_child_watch_source_new (getpid ()); | ||
| 7089 | g_source_unref (source); | ||
| 7090 | } | ||
| 7084 | #endif | 7091 | #endif |
| 7085 | 7092 | ||
| 7086 | emacs_sigaction_init (&action, deliver_child_signal); | 7093 | emacs_sigaction_init (&action, deliver_child_signal); |
| 7087 | block_child_signal (); | ||
| 7088 | sigaction (SIGCHLD, &action, &old_action); | 7094 | sigaction (SIGCHLD, &action, &old_action); |
| 7089 | eassert (! (old_action.sa_flags & SA_SIGINFO)); | 7095 | eassert (! (old_action.sa_flags & SA_SIGINFO)); |
| 7090 | if (old_action.sa_handler != SIG_DFL && old_action.sa_handler != SIG_IGN | 7096 | |
| 7091 | && old_action.sa_handler != deliver_child_signal) | 7097 | #ifdef NS_IMPL_GNUSTEP |
| 7092 | lib_child_handler = old_action.sa_handler; | 7098 | if (old_action.sa_handler == deliver_child_signal) |
| 7093 | unblock_child_signal (); | 7099 | return; |
| 7100 | #endif | ||
| 7101 | |||
| 7102 | lib_child_handler | ||
| 7103 | = (old_action.sa_handler == SIG_DFL || old_action.sa_handler == SIG_IGN | ||
| 7104 | ? dummy_handler | ||
| 7105 | : old_action.sa_handler); | ||
| 7094 | } | 7106 | } |
| 7095 | 7107 | ||
| 7096 | 7108 | ||