summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-12 19:30:26 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-12 19:30:26 +0100
commit76467dfcafcf295fd987f712730774c6f55317d3 (patch)
tree9a841fa293b8dd6ee0c8170451f45c4d1ab13abb
parent7c29f387819b5817b003d2ba73e2b5cf3cb3d0dd (diff)
downloadvim-git-76467dfcafcf295fd987f712730774c6f55317d3.tar.gz
patch 7.4.1306v7.4.1306
Problem: Job control doesn't work well on MS-Windows. Solution: Various fixes. (Ken Takata, Ozaki Kiichi , Yukihiro Nakadaira, Yasuhiro Matsumoto)
-rw-r--r--src/Make_mvc.mak5
-rw-r--r--src/eval.c12
-rw-r--r--src/os_unix.c29
-rw-r--r--src/os_win32.c76
-rw-r--r--src/proto/os_unix.pro1
-rw-r--r--src/proto/os_win32.pro1
-rw-r--r--src/structs.h3
-rw-r--r--src/version.c2
8 files changed, 105 insertions, 24 deletions
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index 11d562959..6cada6560 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -113,7 +113,7 @@
# Processor Version: CPUNR=[i386, i486, i586, i686, pentium4] (default is
# i386)
#
-# Version Support: WINVER=[0x0400, 0x0500] (default is 0x0400)
+# Version Support: WINVER=[0x0400, 0x0500] (default is 0x0500)
#
# Debug version: DEBUG=yes
# Mapfile: MAP=[no, yes or lines] (default is yes)
@@ -370,9 +370,8 @@ CON_LIB = $(CON_LIB) /DELAYLOAD:comdlg32.dll /DELAYLOAD:ole32.dll DelayImp.lib
!endif
### Set the default $(WINVER) to make it work with VC++7.0 (VS.NET)
-# When set to 0x0500 ":browse" stops working.
!ifndef WINVER
-WINVER = 0x0400
+WINVER = 0x0500
!endif
# If you have a fixed directory for $VIM or $VIMRUNTIME, other than the normal
diff --git a/src/eval.c b/src/eval.c
index 30d5684bf..ece87def4 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -7720,8 +7720,7 @@ failret:
static void
job_free(job_T *job)
{
- /* TODO: free any handles */
-
+ mch_clear_job(job);
vim_free(job);
}
@@ -14369,9 +14368,11 @@ f_job_start(typval_T *argvars UNUSED, typval_T *rettv)
s = vim_strsave_shellescape(s, FALSE, TRUE);
if (s == NULL)
goto theend;
+ ga_concat(&ga, s);
+ vim_free(s);
}
- ga_concat(&ga, s);
- vim_free(s);
+ else
+ ga_concat(&ga, s);
if (li->li_next != NULL)
ga_append(&ga, ' ');
#endif
@@ -21623,7 +21624,8 @@ get_tv_string_buf_chk(typval_T *varp, char_u *buf)
"process %ld %s", (long)job->jv_pid, status);
# elif defined(WIN32)
vim_snprintf((char *)buf, NUMBUFLEN,
- "process %ld %s", (long)job->jv_pi.dwProcessId,
+ "process %ld %s",
+ (long)job->jv_proc_info.dwProcessId,
status);
# else
/* fall-back */
diff --git a/src/os_unix.c b/src/os_unix.c
index 17bb32268..83ae75f79 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5092,6 +5092,12 @@ mch_job_status(job_T *job)
job->jv_status = JOB_ENDED;
return "dead";
}
+ if (WIFSIGNALED(status))
+ {
+ job->jv_exitval = -1;
+ job->jv_status = JOB_ENDED;
+ return "dead";
+ }
return "run";
}
@@ -5099,6 +5105,7 @@ mch_job_status(job_T *job)
mch_stop_job(job_T *job, char_u *how)
{
int sig = -1;
+ pid_t job_pid;
if (STRCMP(how, "hup") == 0)
sig = SIGHUP;
@@ -5112,10 +5119,30 @@ mch_stop_job(job_T *job, char_u *how)
sig = atoi((char *)how);
else
return FAIL;
+
/* TODO: have an option to only kill the process, not the group? */
- kill(-job->jv_pid, sig);
+ job_pid = job->jv_pid;
+ if (job_pid == getpgid(job_pid))
+ job_pid = -job_pid;
+
+ kill(job_pid, sig);
+
return OK;
}
+
+/*
+ * Clear the data related to "job".
+ */
+ void
+mch_clear_job(job_T *job)
+{
+ /* call waitpid because child process may become zombie */
+# ifdef __NeXT__
+ wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
+# else
+ waitpid(job->jv_pid, NULL, WNOHANG);
+# endif
+}
#endif
/*
diff --git a/src/os_win32.c b/src/os_win32.c
index 5841d135d..cc5fc3dee 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5038,19 +5038,44 @@ mch_start_job(char *cmd, job_T *job)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
+ HANDLE jo;
+ jo = CreateJobObject(NULL, NULL);
+ if (jo == NULL)
+ {
+ job->jv_status = JOB_FAILED;
+ return;
+ }
+
+ ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
if (!vim_create_process(cmd, FALSE,
+ CREATE_SUSPENDED |
CREATE_DEFAULT_ERROR_MODE |
CREATE_NEW_PROCESS_GROUP |
- CREATE_NO_WINDOW,
+ CREATE_NEW_CONSOLE,
&si, &pi))
+ {
+ CloseHandle(jo);
job->jv_status = JOB_FAILED;
+ }
else
{
- job->jv_pi = pi;
+ if (!AssignProcessToJobObject(jo, pi.hProcess))
+ {
+ /* if failing, switch the way to terminate
+ * process with TerminateProcess. */
+ CloseHandle(jo);
+ jo = NULL;
+ }
+ ResumeThread(pi.hThread);
+ CloseHandle(job->jv_proc_info.hThread);
+ job->jv_proc_info = pi;
+ job->jv_job_object = jo;
job->jv_status = JOB_STARTED;
}
}
@@ -5060,12 +5085,10 @@ mch_job_status(job_T *job)
{
DWORD dwExitCode = 0;
- if (!GetExitCodeProcess(job->jv_pi.hProcess, &dwExitCode))
- return "dead";
- if (dwExitCode != STILL_ACTIVE)
+ if (!GetExitCodeProcess(job->jv_proc_info.hProcess, &dwExitCode)
+ || dwExitCode != STILL_ACTIVE)
{
- CloseHandle(job->jv_pi.hProcess);
- CloseHandle(job->jv_pi.hThread);
+ job->jv_status = JOB_ENDED;
return "dead";
}
return "run";
@@ -5074,14 +5097,39 @@ mch_job_status(job_T *job)
int
mch_stop_job(job_T *job, char_u *how)
{
+ int ret = 0;
+ int ctrl_c = STRCMP(how, "int") == 0;
+
if (STRCMP(how, "kill") == 0)
- TerminateProcess(job->jv_pi.hProcess, 0);
- else
- return GenerateConsoleCtrlEvent(
- STRCMP(how, "hup") == 0 ?
- CTRL_BREAK_EVENT : CTRL_C_EVENT,
- job->jv_pi.dwProcessId) ? OK : FAIL;
- return OK;
+ {
+ if (job->jv_job_object != NULL)
+ return TerminateJobObject(job->jv_job_object, 0) ? OK : FAIL;
+ else
+ return TerminateProcess(job->jv_proc_info.hProcess, 0) ? OK : FAIL;
+ }
+
+ if (!AttachConsole(job->jv_proc_info.dwProcessId))
+ return FAIL;
+ ret = GenerateConsoleCtrlEvent(
+ ctrl_c ? CTRL_C_EVENT : CTRL_BREAK_EVENT,
+ job->jv_proc_info.dwProcessId)
+ ? OK : FAIL;
+ FreeConsole();
+ return ret;
+}
+
+/*
+ * Clear the data related to "job".
+ */
+ void
+mch_clear_job(job_T *job)
+{
+ if (job->jv_status != JOB_FAILED)
+ {
+ if (job->jv_job_object != NULL)
+ CloseHandle(job->jv_job_object);
+ CloseHandle(job->jv_proc_info.hProcess);
+ }
}
#endif
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
index bc250c87e..c97f7fecf 100644
--- a/src/proto/os_unix.pro
+++ b/src/proto/os_unix.pro
@@ -60,6 +60,7 @@ int mch_call_shell(char_u *cmd, int options);
void mch_start_job(char **argv, job_T *job);
char *mch_job_status(job_T *job);
int mch_stop_job(job_T *job, char_u *how);
+void mch_clear_job(job_T *job);
void mch_breakcheck(void);
int mch_expandpath(garray_T *gap, char_u *path, int flags);
int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags);
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
index 2128807ce..2fa6e1024 100644
--- a/src/proto/os_win32.pro
+++ b/src/proto/os_win32.pro
@@ -43,6 +43,7 @@ int mch_call_shell(char_u *cmd, int options);
void mch_start_job(char *cmd, job_T *job);
char *mch_job_status(job_T *job);
int mch_stop_job(job_T *job, char_u *how);
+void mch_clear_job(job_T *job);
void mch_set_normal_colors(void);
void mch_write(char_u *s, int len);
void mch_delay(long msec, int ignoreinput);
diff --git a/src/structs.h b/src/structs.h
index 1ce98d025..8ea43d307 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1249,7 +1249,8 @@ struct jobvar_S
int jv_exitval;
#endif
#ifdef WIN32
- PROCESS_INFORMATION jv_pi;
+ PROCESS_INFORMATION jv_proc_info;
+ HANDLE jv_job_object;
#endif
jobstatus_T jv_status;
diff --git a/src/version.c b/src/version.c
index b73ad024c..7a99caa10 100644
--- a/src/version.c
+++ b/src/version.c
@@ -748,6 +748,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1306,
+/**/
1305,
/**/
1304,