diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-10-18 16:27:23 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-10-18 16:27:23 +0200 |
commit | bb09ceb95477ecc271854b3fdd8d2776eca66adf (patch) | |
tree | d79b1e387fc36710d17ad3ce6c423a06aa518fa1 | |
parent | 025e3e0bafbc85cc4e365145af711edf99d0a90d (diff) | |
download | vim-git-bb09ceb95477ecc271854b3fdd8d2776eca66adf.tar.gz |
patch 8.0.0045v8.0.0045
Problem: Calling job_stop() right after job_start() does not work.
Solution: Block signals while fork is still busy. (Ozaki Kiichi, closes
#1155)
-rwxr-xr-x | src/auto/configure | 2 | ||||
-rw-r--r-- | src/config.h.in | 1 | ||||
-rw-r--r-- | src/configure.in | 2 | ||||
-rw-r--r-- | src/os_unix.c | 56 | ||||
-rw-r--r-- | src/testdir/test_channel.vim | 15 | ||||
-rw-r--r-- | src/version.c | 2 |
6 files changed, 72 insertions, 6 deletions
diff --git a/src/auto/configure b/src/auto/configure index b42f601db..27aea9c98 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -12004,7 +12004,7 @@ for ac_func in bcmp fchdir fchown fsync getcwd getpseudotty \ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ - sigvec strcasecmp strerror strftime stricmp strncasecmp \ + sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ strnicmp strpbrk strtol tgetent towlower towupper iswupper \ usleep utime utimes do : diff --git a/src/config.h.in b/src/config.h.in index 9d35e48fa..62427e28e 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -190,6 +190,7 @@ #undef HAVE_SIGSET #undef HAVE_SIGSETJMP #undef HAVE_SIGSTACK +#undef HAVE_SIGPROCMASK #undef HAVE_SIGVEC #undef HAVE_SMACK #undef HAVE_STRCASECMP diff --git a/src/configure.in b/src/configure.in index c0a60b227..43bf9ad17 100644 --- a/src/configure.in +++ b/src/configure.in @@ -3598,7 +3598,7 @@ AC_CHECK_FUNCS(bcmp fchdir fchown fsync getcwd getpseudotty \ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ - sigvec strcasecmp strerror strftime stricmp strncasecmp \ + sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ strnicmp strpbrk strtol tgetent towlower towupper iswupper \ usleep utime utimes) AC_FUNC_FSEEKO diff --git a/src/os_unix.c b/src/os_unix.c index bc9acd4f7..056918413 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -211,6 +211,15 @@ static RETSIGTYPE deathtrap SIGPROTOARG; static void catch_int_signal(void); static void set_signals(void); static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()); +#ifdef HAVE_SIGPROCMASK +# define SIGSET_DECL(set) sigset_t set; +# define BLOCK_SIGNALS(set) block_signals(set) +# define UNBLOCK_SIGNALS(set) unblock_signals(set) +#else +# define SIGSET_DECL(set) +# define BLOCK_SIGNALS(set) do { /**/ } while (0) +# define UNBLOCK_SIGNALS(set) do { /**/ } while (0) +#endif static int have_wildcard(int, char_u **); static int have_dollars(int, char_u **); @@ -1468,6 +1477,33 @@ catch_signals( signal(signal_info[i].sig, func_other); } +#ifdef HAVE_SIGPROCMASK + static void +block_signals(sigset_t *set) +{ + sigset_t newset; + int i; + + sigemptyset(&newset); + + for (i = 0; signal_info[i].sig != -1; i++) + sigaddset(&newset, signal_info[i].sig); + +# if defined(_REENTRANT) && defined(SIGCONT) + /* SIGCONT isn't in the list, because its default action is ignore */ + sigaddset(&newset, SIGCONT); +# endif + + sigprocmask(SIG_BLOCK, &newset, set); +} + + static void +unblock_signals(sigset_t *set) +{ + sigprocmask(SIG_SETMASK, set, NULL); +} +#endif + /* * Handling of SIGHUP, SIGQUIT and SIGTERM: * "when" == a signal: when busy, postpone and return FALSE, otherwise @@ -4283,12 +4319,18 @@ mch_call_shell( if (!pipe_error) /* pty or pipe opened or not used */ { + SIGSET_DECL(curset) + # ifdef __BEOS__ beos_cleanup_read_thread(); # endif - if ((pid = fork()) == -1) /* maybe we should use vfork() */ + BLOCK_SIGNALS(&curset); + pid = fork(); /* maybe we should use vfork() */ + if (pid == -1) { + UNBLOCK_SIGNALS(&curset); + MSG_PUTS(_("\nCannot fork\n")); if ((options & (SHELL_READ|SHELL_WRITE)) # ifdef FEAT_GUI @@ -4315,6 +4357,7 @@ mch_call_shell( else if (pid == 0) /* child */ { reset_signals(); /* handle signals normally */ + UNBLOCK_SIGNALS(&curset); if (!show_shell_mess || (options & SHELL_EXPAND)) { @@ -4458,6 +4501,7 @@ mch_call_shell( */ catch_signals(SIG_IGN, SIG_ERR); catch_int_signal(); + UNBLOCK_SIGNALS(&curset); /* * For the GUI we redirect stdin, stdout and stderr to our window. @@ -5069,6 +5113,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE; int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE; int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT; + SIGSET_DECL(curset) if (use_out_for_err && use_null_for_out) use_null_for_err = TRUE; @@ -5140,13 +5185,14 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) goto failed; } + BLOCK_SIGNALS(&curset); pid = fork(); /* maybe we should use vfork() */ - if (pid == -1) + if (pid == -1) { /* failed to fork */ + UNBLOCK_SIGNALS(&curset); goto failed; } - if (pid == 0) { int null_fd = -1; @@ -5154,6 +5200,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) /* child */ reset_signals(); /* handle signals normally */ + UNBLOCK_SIGNALS(&curset); # ifdef HAVE_SETSID /* Create our own process group, so that the child and all its @@ -5234,6 +5281,8 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) } /* parent */ + UNBLOCK_SIGNALS(&curset); + job->jv_pid = pid; job->jv_status = JOB_STARTED; job->jv_channel = channel; /* ch_refcount was set above */ @@ -5357,7 +5406,6 @@ mch_detect_ended_job(job_T *job_list) } } return NULL; - } int diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index e7ba66768..0a50ed47e 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1433,6 +1433,21 @@ func Test_job_start_invalid() call assert_fails('call job_start("")', 'E474:') endfunc +func Test_job_stop_immediately() + if !has('job') + return + endif + + let job = job_start([s:python, '-c', 'import time;time.sleep(10)']) + try + call job_stop(job) + call WaitFor('"dead" == job_status(job)') + call assert_equal('dead', job_status(job)) + finally + call job_stop(job, 'kill') + endtry +endfunc + " This was leaking memory. func Test_partial_in_channel_cycle() let d = {} diff --git a/src/version.c b/src/version.c index 80a837a38..b15752024 100644 --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 45, +/**/ 44, /**/ 43, |