diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2016-08-29 13:39:32 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-29 13:39:32 -0400 |
commit | 10a54ad12e2d78c629220c4266066cf9b997d684 (patch) | |
tree | 0b1399b30db822d37b1180452d16bfb3db6ddf66 /src/nvim/os/signal.c | |
parent | 0b5a7e4ad5eee229c7aca70b99f8b6f189d289d1 (diff) | |
download | rneovim-10a54ad12e2d78c629220c4266066cf9b997d684.tar.gz rneovim-10a54ad12e2d78c629220c4266066cf9b997d684.tar.bz2 rneovim-10a54ad12e2d78c629220c4266066cf9b997d684.zip |
signal_init: Always unblock SIGCHLD. (#5243)
Inherited signal mask may block SIGCHLD, which causes libuv to hang at
epoll_wait.
Closes #5230
Helped-by: Nicolas Hillegeer <nicolas@hillegeer.com>
Helped-by: John Szakmeister <john@szakmeister.net>
Note: the #pragma gymnastics are a workaround for broken system headers on
macOS.
signal.h:
int sigaddset(sigset_t *, int);
#define sigaddset(set, signo) (*(set) |= __sigbits(signo), 0)
sys/_types/_sigset.h:
typedef __darwin_sigset_t sigset_t;
sys/_types.h:
typedef __uint32_t __darwin_sigset_t; /* [???] signal set */
sigset_t is defined as unsigned int, but the sigaddset() ORs it with an int,
mixing the types. So GCC generates a sign-conversion warning:
sig.c:9:13: warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion]
(*(&s) |= __sigbits((sigset_t) 20), 0);
~~ ^~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
System headers are normally ignored when the compiler generates warnings:
https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
> GCC gives code found in system headers special treatment. All warnings,
> other than those generated by ‘#warning’ (see Diagnostics), are suppressed
> while GCC is processing a system header. Macros defined in a system header
> are immune to a few warnings wherever they are expanded. This immunity is
> granted on an ad-hoc basis, when we find that a warning generates lots of
> false positives because of code in macros defined in system headers.
Instead of the #pragma workaround, we could cast the sigset_t pointer:
# if defined(__APPLE__)
sigaddset((int *)&mask, SIGCHLD);
# else
sigaddset(&mask, SIGCHLD);
# endif
but that could break if the headers are later fixed.
Diffstat (limited to 'src/nvim/os/signal.c')
-rw-r--r-- | src/nvim/os/signal.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 4abc9cfc36..5295fc03a1 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -2,6 +2,9 @@ #include <stdbool.h> #include <uv.h> +#ifndef WIN32 +# include <signal.h> // for sigset_t +#endif #include "nvim/ascii.h" #include "nvim/vim.h" @@ -29,6 +32,9 @@ static bool rejecting_deadly; void signal_init(void) { + // Ensure that SIGCHLD is unblocked, else libuv (epoll_wait) may hang. + signal_unblock_SIGCHLD(); + signal_watcher_init(&main_loop, &spipe, NULL); signal_watcher_init(&main_loop, &shup, NULL); signal_watcher_init(&main_loop, &squit, NULL); @@ -151,3 +157,27 @@ static void on_signal(SignalWatcher *handle, int signum, void *data) break; } } + +static void signal_unblock_SIGCHLD(void) +{ +#ifndef WIN32 + sigset_t mask; + sigemptyset(&mask); + + // Work around broken macOS headers. #5243 +# if defined(__APPLE__) && !defined(__clang__) && !defined(__INTEL_COMPILER) \ + && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsign-conversion" +# endif + + sigaddset(&mask, SIGCHLD); + +# if defined(__APPLE__) && !defined(__clang__) && !defined(__INTEL_COMPILER) \ + && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic pop +# endif + + pthread_sigmask(SIG_UNBLOCK, &mask, NULL); +#endif +} |