summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-03-11 22:19:44 +0100
committerBram Moolenaar <Bram@vim.org>2016-03-11 22:19:44 +0100
commitde27989157f35172b25f9e01e0c147ed8f6ae3ce (patch)
treeac52ee2ae7bf82a4cc85f31b1c7b6f2993348c81 /src
parent9e496854a9fe56699687a4f86003fad115b3b375 (diff)
patch 7.4.1536v7.4.1536
Problem: Cannot re-use a channel for another job. Solution: Add the "channel" option to job_start().
Diffstat (limited to 'src')
-rw-r--r--src/channel.c112
-rw-r--r--src/eval.c12
-rw-r--r--src/os_unix.c17
-rw-r--r--src/os_win32.c14
-rw-r--r--src/proto/channel.pro1
-rw-r--r--src/structs.h2
-rw-r--r--src/testdir/test_channel.vim27
-rw-r--r--src/version.c2
8 files changed, 132 insertions, 55 deletions
diff --git a/src/channel.c b/src/channel.c
index d77a4b7d1b..f65b31fb14 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -459,6 +459,9 @@ messageFromNetbeans(gpointer clientData,
static void
channel_gui_register_one(channel_T *channel, int part)
{
+ if (!CH_HAS_GUI)
+ return;
+
# ifdef FEAT_GUI_X11
/* Tell notifier we are interested in being called
* when there is input on the editor connection socket. */
@@ -499,12 +502,9 @@ channel_gui_register_one(channel_T *channel, int part)
# endif
}
- void
+ static void
channel_gui_register(channel_T *channel)
{
- if (!CH_HAS_GUI)
- return;
-
if (channel->CH_SOCK_FD != INVALID_FD)
channel_gui_register_one(channel, PART_SOCK);
# ifdef CHANNEL_PIPES
@@ -529,6 +529,30 @@ channel_gui_register_all(void)
}
static void
+channel_gui_unregister_one(channel_T *channel, int part)
+{
+# ifdef FEAT_GUI_X11
+ if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL)
+ {
+ XtRemoveInput(channel->ch_part[part].ch_inputHandler);
+ channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
+ }
+# else
+# ifdef FEAT_GUI_GTK
+ if (channel->ch_part[part].ch_inputHandler != 0)
+ {
+# if GTK_CHECK_VERSION(3,0,0)
+ g_source_remove(channel->ch_part[part].ch_inputHandler);
+# else
+ gdk_input_remove(channel->ch_part[part].ch_inputHandler);
+# endif
+ channel->ch_part[part].ch_inputHandler = 0;
+ }
+# endif
+# endif
+}
+
+ static void
channel_gui_unregister(channel_T *channel)
{
int part;
@@ -539,25 +563,7 @@ channel_gui_unregister(channel_T *channel)
part = PART_SOCK;
#endif
{
-# ifdef FEAT_GUI_X11
- if (channel->ch_part[part].ch_inputHandler != (XtInputId)NULL)
- {
- XtRemoveInput(channel->ch_part[part].ch_inputHandler);
- channel->ch_part[part].ch_inputHandler = (XtInputId)NULL;
- }
-# else
-# ifdef FEAT_GUI_GTK
- if (channel->ch_part[part].ch_inputHandler != 0)
- {
-# if GTK_CHECK_VERSION(3,0,0)
- g_source_remove(channel->ch_part[part].ch_inputHandler);
-# else
- gdk_input_remove(channel->ch_part[part].ch_inputHandler);
-# endif
- channel->ch_part[part].ch_inputHandler = 0;
- }
-# endif
-# endif
+ channel_gui_unregister_one(channel, part);
}
}
@@ -830,19 +836,53 @@ channel_open(
channel->ch_nb_close_cb = nb_close_cb;
#ifdef FEAT_GUI
- channel_gui_register(channel);
+ channel_gui_register_one(channel, PART_SOCK);
#endif
return channel;
}
#if defined(CHANNEL_PIPES) || defined(PROTO)
+ static void
+may_close_part(sock_T *fd)
+{
+ if (*fd != INVALID_FD)
+ {
+ fd_close(*fd);
+ *fd = INVALID_FD;
+ }
+}
+
void
channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err)
{
- channel->CH_IN_FD = in;
- channel->CH_OUT_FD = out;
- channel->CH_ERR_FD = err;
+ if (in != INVALID_FD)
+ {
+ may_close_part(&channel->CH_IN_FD);
+ channel->CH_IN_FD = in;
+ }
+ if (out != INVALID_FD)
+ {
+# if defined(FEAT_GUI)
+ channel_gui_unregister_one(channel, PART_OUT);
+# endif
+ may_close_part(&channel->CH_OUT_FD);
+ channel->CH_OUT_FD = out;
+# if defined(FEAT_GUI)
+ channel_gui_register_one(channel, PART_OUT);
+# endif
+ }
+ if (err != INVALID_FD)
+ {
+# if defined(FEAT_GUI)
+ channel_gui_unregister_one(channel, PART_ERR);
+# endif
+ may_close_part(&channel->CH_ERR_FD);
+ channel->CH_ERR_FD = err;
+# if defined(FEAT_GUI)
+ channel_gui_register_one(channel, PART_ERR);
+# endif
+ }
}
#endif
@@ -1912,21 +1952,9 @@ channel_close(channel_T *channel, int invoke_close_cb)
channel->CH_SOCK_FD = INVALID_FD;
}
#if defined(CHANNEL_PIPES)
- if (channel->CH_IN_FD != INVALID_FD)
- {
- fd_close(channel->CH_IN_FD);
- channel->CH_IN_FD = INVALID_FD;
- }
- if (channel->CH_OUT_FD != INVALID_FD)
- {
- fd_close(channel->CH_OUT_FD);
- channel->CH_OUT_FD = INVALID_FD;
- }
- if (channel->CH_ERR_FD != INVALID_FD)
- {
- fd_close(channel->CH_ERR_FD);
- channel->CH_ERR_FD = INVALID_FD;
- }
+ may_close_part(&channel->CH_IN_FD);
+ may_close_part(&channel->CH_OUT_FD);
+ may_close_part(&channel->CH_ERR_FD);
#endif
if (invoke_close_cb && channel->ch_close_cb != NULL)
diff --git a/src/eval.c b/src/eval.c
index 9f56126f6b..f3ebaa5e05 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -10164,6 +10164,18 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
return FAIL;
}
}
+ else if (STRCMP(hi->hi_key, "channel") == 0)
+ {
+ if (!(supported & JO_OUT_IO))
+ break;
+ opt->jo_set |= JO_CHANNEL;
+ if (item->v_type != VAR_CHANNEL)
+ {
+ EMSG2(_(e_invarg2), "channel");
+ return FAIL;
+ }
+ opt->jo_channel = item->vval.v_channel;
+ }
else if (STRCMP(hi->hi_key, "callback") == 0)
{
if (!(supported & JO_CALLBACK))
diff --git a/src/os_unix.c b/src/os_unix.c
index 7eb4e710c9..8a611666fc 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -5111,7 +5111,14 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
{
- channel = add_channel();
+ if (options->jo_set & JO_CHANNEL)
+ {
+ channel = options->jo_channel;
+ if (channel != NULL)
+ ++channel->ch_refcount;
+ }
+ else
+ channel = add_channel();
if (channel == NULL)
goto failed;
}
@@ -5211,7 +5218,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
job->jv_pid = pid;
job->jv_status = JOB_STARTED;
# ifdef FEAT_CHANNEL
- job->jv_channel = channel;
+ job->jv_channel = channel; /* ch_refcount was set above */
# endif
# ifdef FEAT_CHANNEL
@@ -5232,9 +5239,6 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
use_out_for_err || use_file_for_err || use_null_for_err
? INVALID_FD : fd_err[0]);
channel_set_job(channel, job, options);
-# ifdef FEAT_GUI
- channel_gui_register(channel);
-# endif
}
# endif
@@ -5243,8 +5247,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
failed: ;
# ifdef FEAT_CHANNEL
- if (channel != NULL)
- channel_free(channel);
+ channel_unref(channel);
if (fd_in[0] >= 0)
close(fd_in[0]);
if (fd_in[1] >= 0)
diff --git a/src/os_win32.c b/src/os_win32.c
index c4dc349a3b..49fd0f7031 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5138,7 +5138,14 @@ mch_start_job(char *cmd, job_T *job, jobopt_T *options)
if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
{
- channel = add_channel();
+ if (options->jo_set & JO_CHANNEL)
+ {
+ channel = options->jo_channel;
+ if (channel != NULL)
+ ++channel->ch_refcount;
+ }
+ else
+ channel = add_channel();
if (channel == NULL)
goto failed;
}
@@ -5188,9 +5195,6 @@ mch_start_job(char *cmd, job_T *job, jobopt_T *options)
use_out_for_err || use_file_for_err || use_null_for_err
? INVALID_FD : (sock_T)efd[0]);
channel_set_job(channel, job, options);
-# ifdef FEAT_GUI
- channel_gui_register(channel);
-# endif
}
# endif
return;
@@ -5203,7 +5207,7 @@ failed:
CloseHandle(ifd[1]);
CloseHandle(ofd[1]);
CloseHandle(efd[1]);
- channel_free(channel);
+ channel_unref(channel);
# else
; /* make compiler happy */
# endif
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index 18dceb521a..bb7bab31c0 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -6,7 +6,6 @@ void ch_logs(channel_T *ch, char *msg, char *name);
channel_T *add_channel(void);
int channel_may_free(channel_T *channel);
void channel_free(channel_T *channel);
-void channel_gui_register(channel_T *channel);
void channel_gui_register_all(void);
channel_T *channel_open(char *hostname, int port_in, int waittime, void (*nb_close_cb)(void));
void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
diff --git a/src/structs.h b/src/structs.h
index 373405ce0e..9ccc09a121 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1412,6 +1412,7 @@ struct channel_S {
#define JO_OUT_BUF 0x1000000 /* "out-buf" */
#define JO_ERR_BUF 0x2000000 /* "err-buf" (JO_OUT_BUF << 1) */
#define JO_IN_BUF 0x4000000 /* "in-buf" (JO_OUT_BUF << 2) */
+#define JO_CHANNEL 0x8000000 /* "channel" */
#define JO_ALL 0xfffffff
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
@@ -1443,6 +1444,7 @@ typedef struct
char_u jo_io_name_buf[4][NUMBUFLEN];
char_u *jo_io_name[4]; /* not allocated! */
int jo_io_buf[4];
+ channel_T *jo_channel;
linenr_T jo_in_top;
linenr_T jo_in_bot;
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 909afea8a3..5f2b97f70f 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -917,6 +917,33 @@ func Test_pipe_null()
call job_stop(job)
endfunc
+func Test_reuse_channel()
+ if !has('job')
+ return
+ endif
+ call ch_log('Test_reuse_channel()')
+
+ let job = job_start(s:python . " test_channel_pipe.py")
+ call assert_equal("run", job_status(job))
+ let handle = job_getchannel(job)
+ try
+ call ch_sendraw(handle, "echo something\n")
+ call assert_equal("something", ch_readraw(handle))
+ finally
+ call job_stop(job)
+ endtry
+
+ let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle})
+ call assert_equal("run", job_status(job))
+ let handle = job_getchannel(job)
+ try
+ call ch_sendraw(handle, "echo again\n")
+ call assert_equal("again", ch_readraw(handle))
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
""""""""""
let s:unletResponse = ''
diff --git a/src/version.c b/src/version.c
index d138eb844e..4f6c51d60f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -744,6 +744,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1536,
+/**/
1535,
/**/
1534,