# HG changeset patch # User Christian Brabandt # Date 1457731804 -3600 # Node ID daebcbd87bd3f1bfc9edb398d757d1f588a5b776 # Parent eceb3c28e17978d0053a27e55478fdd8d7fc7735 commit https://github.com/vim/vim/commit/de27989157f35172b25f9e01e0c147ed8f6ae3ce Author: Bram Moolenaar Date: Fri Mar 11 22:19:44 2016 +0100 patch 7.4.1536 Problem: Cannot re-use a channel for another job. Solution: Add the "channel" option to job_start(). diff --git a/src/channel.c b/src/channel.c --- 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 *chan # 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 *channe 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 in 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 --- a/src/eval.c +++ b/src/eval.c @@ -10164,6 +10164,18 @@ get_job_options(typval_T *tv, jobopt_T * 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 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5111,7 +5111,14 @@ mch_start_job(char **argv, job_T *job, j 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, j 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, j 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, j 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 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5138,7 +5138,14 @@ mch_start_job(char *cmd, job_T *job, job 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, job 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 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -6,7 +6,6 @@ void ch_logs(channel_T *ch, char *msg, c 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 --- 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 --- 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 --- 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,