summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-10-18 16:27:23 +0200
committerBram Moolenaar <Bram@vim.org>2016-10-18 16:27:23 +0200
commitbb09ceb95477ecc271854b3fdd8d2776eca66adf (patch)
treed79b1e387fc36710d17ad3ce6c423a06aa518fa1
parent025e3e0bafbc85cc4e365145af711edf99d0a90d (diff)
downloadvim-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-xsrc/auto/configure2
-rw-r--r--src/config.h.in1
-rw-r--r--src/configure.in2
-rw-r--r--src/os_unix.c56
-rw-r--r--src/testdir/test_channel.vim15
-rw-r--r--src/version.c2
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,