From 7b3ca76a451b10d238ef946f3231762e0bd988e9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 14 Feb 2016 19:13:43 +0100 Subject: [PATCH 1/3] patch 7.4.1318 Problem: Channel with pipes doesn't work in GUI. Solution: Register input handlers for pipes. --- src/channel.c | 442 +++++++++++++++++++++--------------------- src/eval.c | 2 +- src/feature.h | 2 +- src/gui_w48.c | 5 +- src/os_unix.c | 5 + src/os_win32.c | 53 +++-- src/proto/channel.pro | 5 +- src/structs.h | 61 +++--- src/version.c | 2 + 9 files changed, 312 insertions(+), 265 deletions(-) diff --git a/src/channel.c b/src/channel.c index dc05587be5..daf1c34caf 100644 --- a/src/channel.c +++ b/src/channel.c @@ -213,7 +213,8 @@ static int next_ch_id = 0; channel_T * add_channel(void) { - channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T)); + int which; + channel_T *channel = (channel_T *)alloc_clear((int)sizeof(channel_T)); if (channel == NULL) return NULL; @@ -221,21 +222,23 @@ add_channel(void) channel->ch_id = next_ch_id++; ch_log(channel, "Opening channel\n"); - channel->ch_sock = (sock_T)-1; #ifdef CHANNEL_PIPES - channel->ch_in = -1; - channel->ch_out = -1; - channel->ch_err = -1; + for (which = CHAN_SOCK; which <= CHAN_IN; ++which) +#else + which = CHAN_SOCK; #endif + { + channel->ch_pfd[which].ch_fd = (sock_T)-1; #ifdef FEAT_GUI_X11 - channel->ch_inputHandler = (XtInputId)NULL; + channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; #endif #ifdef FEAT_GUI_GTK - channel->ch_inputHandler = 0; + channel->ch_pfd[which].ch_inputHandler = 0; #endif #ifdef FEAT_GUI_W32 - channel->ch_inputHandler = -1; + channel->ch_pfd[which].ch_inputHandler = -1; #endif + } channel->ch_timeout = 2000; @@ -290,7 +293,7 @@ channel_read_netbeans(int id) if (channel == NULL) ch_errorn(NULL, "Channel %d not found", id); else - channel_read(channel, FALSE, "messageFromNetbeans"); + channel_read(channel, -1, "messageFromNetbeans"); } #endif @@ -318,43 +321,54 @@ messageFromNetbeans(gpointer clientData, #endif static void +channel_gui_register_one(channel_T *channel, int which) +{ +# ifdef FEAT_GUI_X11 + /* Tell notifier we are interested in being called + * when there is input on the editor connection socket. */ + if (channel->ch_pfd[which].ch_inputHandler == (XtInputId)NULL) + channel->ch_pfd[which].ch_inputHandler = XtAppAddInput( + (XtAppContext)app_context, + channel->ch_pfd[which].ch_fd, + (XtPointer)(XtInputReadMask + XtInputExceptMask), + messageFromNetbeans, + (XtPointer)(long)channel->ch_id); +# else +# ifdef FEAT_GUI_GTK + /* Tell gdk we are interested in being called when there + * is input on the editor connection socket. */ + if (channel->ch_pfd[which].ch_inputHandler == 0) + channel->ch_pfd[which].ch_inputHandler = gdk_input_add( + (gint)channel->ch_pfd[which].ch_fd, (GdkInputCondition) + ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), + messageFromNetbeans, + (gpointer)(long)channel->ch_id); +# else +# ifdef FEAT_GUI_W32 + /* Tell Windows we are interested in receiving message when there + * is input on the editor connection socket. */ + if (channel->ch_pfd[which].ch_inputHandler == -1) + channel->ch_pfd[which].ch_inputHandler = WSAAsyncSelect( + channel->ch_pfd[which].ch_fd, + s_hwnd, WM_NETBEANS, FD_READ); +# endif +# endif +# endif +} + + void channel_gui_register(channel_T *channel) { if (!CH_HAS_GUI) return; - /* TODO: pipes */ -# ifdef FEAT_GUI_X11 - /* tell notifier we are interested in being called - * when there is input on the editor connection socket - */ - if (channel->ch_inputHandler == (XtInputId)NULL) - channel->ch_inputHandler = - XtAppAddInput((XtAppContext)app_context, channel->ch_sock, - (XtPointer)(XtInputReadMask + XtInputExceptMask), - messageFromNetbeans, (XtPointer)(long)channel->ch_id); -# else -# ifdef FEAT_GUI_GTK - /* - * Tell gdk we are interested in being called when there - * is input on the editor connection socket - */ - if (channel->ch_inputHandler == 0) - channel->ch_inputHandler = - gdk_input_add((gint)channel->ch_sock, (GdkInputCondition) - ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), - messageFromNetbeans, (gpointer)(long)channel->ch_id); -# else -# ifdef FEAT_GUI_W32 - /* - * Tell Windows we are interested in receiving message when there - * is input on the editor connection socket. - */ - if (channel->ch_inputHandler == -1) - channel->ch_inputHandler = - WSAAsyncSelect(channel->ch_sock, s_hwnd, WM_NETBEANS, FD_READ); -# endif -# endif + if (channel->ch_pfd[CHAN_SOCK].ch_fd >= 0) + channel_gui_register_one(channel, CHAN_SOCK); +# ifdef CHANNEL_PIPES + if (channel->ch_pfd[CHAN_OUT].ch_fd >= 0) + channel_gui_register_one(channel, CHAN_OUT); + if (channel->ch_pfd[CHAN_ERR].ch_fd >= 0) + channel_gui_register_one(channel, CHAN_ERR); # endif } @@ -368,37 +382,47 @@ channel_gui_register_all(void) channel_T *channel; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - /* TODO: pipes */ - if (channel->ch_sock >= 0) - channel_gui_register(channel); + channel_gui_register(channel); +} + + static void +channel_gui_unregister_one(channel_T *channel, int which) +{ +# ifdef FEAT_GUI_X11 + if (channel->ch_pfd[which].ch_inputHandler != (XtInputId)NULL) + { + XtRemoveInput(channel->ch_pfd[which].ch_inputHandler); + channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; + } +# else +# ifdef FEAT_GUI_GTK + if (channel->ch_pfd[which].ch_inputHandler != 0) + { + gdk_input_remove(channel->ch_pfd[which].ch_inputHandler); + channel->ch_pfd[which].ch_inputHandler = 0; + } +# else +# ifdef FEAT_GUI_W32 + if (channel->ch_pfd[which].ch_inputHandler == 0) + { + WSAAsyncSelect(channel->ch_pfd[which].ch_fd, s_hwnd, 0, 0); + channel->ch_pfd[which].ch_inputHandler = -1; + } +# endif +# endif +# endif } static void channel_gui_unregister(channel_T *channel) { - /* TODO: pipes */ -# ifdef FEAT_GUI_X11 - if (channel->ch_inputHandler != (XtInputId)NULL) - { - XtRemoveInput(channel->ch_inputHandler); - channel->ch_inputHandler = (XtInputId)NULL; - } -# else -# ifdef FEAT_GUI_GTK - if (channel->ch_inputHandler != 0) - { - gdk_input_remove(channel->ch_inputHandler); - channel->ch_inputHandler = 0; - } -# else -# ifdef FEAT_GUI_W32 - if (channel->ch_inputHandler == 0) - { - WSAAsyncSelect(channel->ch_sock, s_hwnd, 0, 0); - channel->ch_inputHandler = -1; - } -# endif -# endif + if (channel->ch_pfd[CHAN_SOCK].ch_fd >= 0) + channel_gui_unregister_one(channel, CHAN_SOCK); +# ifdef CHANNEL_PIPES + if (channel->ch_pfd[CHAN_OUT].ch_fd >= 0) + channel_gui_unregister_one(channel, CHAN_OUT); + if (channel->ch_pfd[CHAN_ERR].ch_fd >= 0) + channel_gui_unregister_one(channel, CHAN_ERR); # endif } @@ -440,6 +464,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) { ch_error(NULL, "in socket() in channel_open().\n"); PERROR("E898: socket() in channel_open()"); + channel_free(channel); return NULL; } @@ -453,6 +478,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) ch_error(NULL, "in gethostbyname() in channel_open()\n"); PERROR("E901: gethostbyname() in channel_open()"); sock_close(sd); + channel_free(channel); return NULL; } memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); @@ -472,6 +498,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) ch_errorn(NULL, "channel_open: Connect failed with errno %d\n", errno); sock_close(sd); + channel_free(channel); return NULL; } } @@ -492,6 +519,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) errno); PERROR(_("E902: Cannot connect to port")); sock_close(sd); + channel_free(channel); return NULL; } } @@ -513,12 +541,14 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) errno); PERROR(_("E902: Cannot connect to port")); sock_close(sd); + channel_free(channel); return NULL; } if (!FD_ISSET(sd, &wfds)) { /* don't give an error, we just timed out. */ sock_close(sd); + channel_free(channel); return NULL; } } @@ -542,6 +572,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) SOCK_ERRNO; ch_log(NULL, "socket() retry in channel_open()\n"); PERROR("E900: socket() retry in channel_open()"); + channel_free(channel); return NULL; } if (connect(sd, (struct sockaddr *)&server, sizeof(server))) @@ -575,12 +606,13 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) ch_error(NULL, "Cannot connect to port after retry\n"); PERROR(_("E899: Cannot connect to port after retry2")); sock_close(sd); + channel_free(channel); return NULL; } } } - channel->ch_sock = sd; + channel->CH_SOCK = sd; channel->ch_close_cb = close_cb; #ifdef FEAT_GUI @@ -594,9 +626,9 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) void channel_set_pipes(channel_T *channel, int in, int out, int err) { - channel->ch_in = in; - channel->ch_out = out; - channel->ch_err = err; + channel->CH_IN = in; + channel->CH_OUT = out; + channel->CH_ERR = err; } #endif @@ -1115,9 +1147,9 @@ may_invoke_callback(channel_T *channel) int channel_can_write_to(channel_T *channel) { - return channel != NULL && (channel->ch_sock >= 0 + return channel != NULL && (channel->CH_SOCK >= 0 #ifdef CHANNEL_PIPES - || channel->ch_in >= 0 + || channel->CH_IN >= 0 #endif ); } @@ -1129,11 +1161,11 @@ channel_can_write_to(channel_T *channel) int channel_is_open(channel_T *channel) { - return channel != NULL && (channel->ch_sock >= 0 + return channel != NULL && (channel->CH_SOCK >= 0 #ifdef CHANNEL_PIPES - || channel->ch_in >= 0 - || channel->ch_out >= 0 - || channel->ch_err >= 0 + || channel->CH_IN >= 0 + || channel->CH_OUT >= 0 + || channel->CH_ERR >= 0 #endif ); } @@ -1160,10 +1192,10 @@ channel_close(channel_T *channel) { ch_log(channel, "Closing channel"); - if (channel->ch_sock >= 0) + if (channel->CH_SOCK >= 0) { - sock_close(channel->ch_sock); - channel->ch_sock = -1; + sock_close(channel->CH_SOCK); + channel->CH_SOCK = -1; channel->ch_close_cb = NULL; #ifdef FEAT_GUI channel_gui_unregister(channel); @@ -1172,20 +1204,20 @@ channel_close(channel_T *channel) channel->ch_callback = NULL; } #if defined(CHANNEL_PIPES) - if (channel->ch_in >= 0) + if (channel->CH_IN >= 0) { - close(channel->ch_in); - channel->ch_in = -1; + close(channel->CH_IN); + channel->CH_IN = -1; } - if (channel->ch_out >= 0) + if (channel->CH_OUT >= 0) { - close(channel->ch_out); - channel->ch_out = -1; + close(channel->CH_OUT); + channel->CH_OUT = -1; } - if (channel->ch_err >= 0) + if (channel->CH_ERR >= 0) { - close(channel->ch_err); - channel->ch_err = -1; + close(channel->CH_ERR); + channel->CH_ERR = -1; } #endif channel_clear(channel); @@ -1351,17 +1383,16 @@ channel_get_id(void) /* * Get the file descriptor to read from, either the socket or stdout. + * TODO: never gets stderr. */ static int -get_read_fd(channel_T *channel, int use_stderr) +get_read_fd(channel_T *channel) { - if (channel->ch_sock >= 0) - return channel->ch_sock; + if (channel->CH_SOCK >= 0) + return channel->CH_SOCK; #if defined(CHANNEL_PIPES) - if (!use_stderr && channel->ch_out >= 0) - return channel->ch_out; - if (use_stderr && channel->ch_err >= 0) - return channel->ch_err; + if (channel->CH_OUT >= 0) + return channel->CH_OUT; #endif ch_error(channel, "channel_read() called while socket is closed\n"); return -1; @@ -1369,10 +1400,11 @@ get_read_fd(channel_T *channel, int use_stderr) /* * Read from channel "channel" for as long as there is something to read. + * "which" is CHAN_SOCK, CHAN_OUT or CHAN_ERR. When -1 guess. * The data is put in the read queue. */ void -channel_read(channel_T *channel, int use_stderr, char *func) +channel_read(channel_T *channel, int which, char *func) { static char_u *buf = NULL; int len = 0; @@ -1380,10 +1412,13 @@ channel_read(channel_T *channel, int use_stderr, char *func) int fd; int use_socket = FALSE; - fd = get_read_fd(channel, use_stderr); + if (which < 0) + fd = get_read_fd(channel); + else + fd = channel->ch_pfd[which].ch_fd; if (fd < 0) return; - use_socket = channel->ch_sock >= 0; + use_socket = fd == channel->CH_SOCK; /* Allocate a buffer to read into. */ if (buf == NULL) @@ -1450,7 +1485,7 @@ channel_read(channel_T *channel, int use_stderr, char *func) else { close(fd); - channel->ch_out = -1; + channel->CH_OUT = -1; } #endif @@ -1480,13 +1515,14 @@ channel_read_block(channel_T *channel) ch_log(channel, "Reading raw\n"); if (channel_peek(channel) == NULL) { - int fd = get_read_fd(channel, FALSE); + int fd = get_read_fd(channel); + /* TODO: read both out and err if they are different */ ch_log(channel, "No readahead\n"); /* Wait for up to the channel timeout. */ if (fd < 0 || channel_wait(channel, fd, channel->ch_timeout) == FAIL) return NULL; - channel_read(channel, FALSE, "channel_read_block"); + channel_read(channel, -1, "channel_read_block"); } /* TODO: only get the first message */ @@ -1526,11 +1562,11 @@ channel_read_json_block(channel_T *channel, int id, typval_T **rettv) continue; /* Wait for up to the channel timeout. */ - fd = get_read_fd(channel, FALSE); + fd = get_read_fd(channel); if (fd < 0 || channel_wait(channel, fd, channel->ch_timeout) == FAIL) break; - channel_read(channel, FALSE, "channel_read_json_block"); + channel_read(channel, -1, "channel_read_json_block"); } } channel->ch_block_id = 0; @@ -1539,24 +1575,28 @@ channel_read_json_block(channel_T *channel, int id, typval_T **rettv) # if defined(WIN32) || defined(PROTO) /* - * Lookup the channel from the socket. + * Lookup the channel from the socket. Set "which" to the fd index. * Returns NULL when the socket isn't found. */ channel_T * -channel_fd2channel(sock_T fd) +channel_fd2channel(sock_T fd, int *whichp) { - channel_T *channel; + channel_T *channel; + int i; if (fd >= 0) for (channel = first_channel; channel != NULL; channel = channel->ch_next) - if (channel->ch_sock == fd -# if defined(CHANNEL_PIPES) - || channel->ch_out == fd - || channel->ch_err == fd +# ifdef CHANNEL_PIPES + for (i = CHAN_SOCK; i < CHAN_IN; ++i) +# else + i = CHAN_SOCK; # endif - ) - return channel; + if (channel->ch_pfd[i].ch_fd == fd) + { + *whichp = i; + return channel + } return NULL; } # endif @@ -1574,14 +1614,14 @@ channel_send(channel_T *channel, char_u *buf, char *fun) int fd = -1; int use_socket = FALSE; - if (channel->ch_sock >= 0) + if (channel->CH_SOCK >= 0) { - fd = channel->ch_sock; + fd = channel->CH_SOCK; use_socket = TRUE; } #if defined(CHANNEL_PIPES) - else if (channel->ch_in >= 0) - fd = channel->ch_in; + else if (channel->CH_IN >= 0) + fd = channel->CH_IN; #endif if (fd < 0) { @@ -1631,44 +1671,26 @@ channel_send(channel_T *channel, char_u *buf, char *fun) int channel_poll_setup(int nfd_in, void *fds_in) { - int nfd = nfd_in; - channel_T *channel; - struct pollfd *fds = fds_in; + int nfd = nfd_in; + channel_T *channel; + struct pollfd *fds = fds_in; + int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - { - if (channel->ch_sock >= 0) - { - channel->ch_sock_idx = nfd; - fds[nfd].fd = channel->ch_sock; - fds[nfd].events = POLLIN; - nfd++; - } - else - channel->ch_sock_idx = -1; - # ifdef CHANNEL_PIPES - if (channel->ch_out >= 0) - { - channel->ch_out_idx = nfd; - fds[nfd].fd = channel->ch_out; - fds[nfd].events = POLLIN; - nfd++; - } - else - channel->ch_out_idx = -1; - - if (channel->ch_err >= 0) - { - channel->ch_err_idx = nfd; - fds[nfd].fd = channel->ch_err; - fds[nfd].events = POLLIN; - nfd++; - } - else - channel->ch_err_idx = -1; + for (which = CHAN_SOCK; which < CHAN_IN; ++which) +# else + which = CHAN_SOCK; # endif - } + if (channel->ch_pfd[which].ch_fd >= 0) + { + channel->ch_pfd[which].ch_poll_idx = nfd; + fds[nfd].fd = channel->ch_pfd[which].ch_fd; + fds[nfd].events = POLLIN; + nfd++; + } + else + channel->ch_pfd[which].ch_poll_idx = -1; return nfd; } @@ -1679,33 +1701,26 @@ channel_poll_setup(int nfd_in, void *fds_in) int channel_poll_check(int ret_in, void *fds_in) { - int ret = ret_in; - channel_T *channel; - struct pollfd *fds = fds_in; + int ret = ret_in; + channel_T *channel; + struct pollfd *fds = fds_in; + int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - { - if (ret > 0 && channel->ch_sock_idx != -1 - && fds[channel->ch_sock_idx].revents & POLLIN) - { - channel_read(channel, FALSE, "channel_poll_check"); - --ret; - } # ifdef CHANNEL_PIPES - if (ret > 0 && channel->ch_out_idx != -1 - && fds[channel->ch_out_idx].revents & POLLIN) - { - channel_read(channel, FALSE, "channel_poll_check"); - --ret; - } - if (ret > 0 && channel->ch_err_idx != -1 - && fds[channel->ch_err_idx].revents & POLLIN) - { - channel_read(channel, TRUE, "channel_poll_check"); - --ret; - } + for (which = CHAN_SOCK; which < CHAN_IN; ++which) +# else + which = CHAN_SOCK; # endif - } + { + int idx = channel->ch_pfd[which].ch_poll_idx; + + if (ret > 0 && idx != -1 && fds[idx].revents & POLLIN) + { + channel_read(channel, which, "channel_poll_check"); + --ret; + } + } return ret; } @@ -1718,33 +1733,27 @@ channel_poll_check(int ret_in, void *fds_in) int channel_select_setup(int maxfd_in, void *rfds_in) { - int maxfd = maxfd_in; - channel_T *channel; - fd_set *rfds = rfds_in; + int maxfd = maxfd_in; + channel_T *channel; + fd_set *rfds = rfds_in; + int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - { - if (channel->ch_sock >= 0) - { - FD_SET(channel->ch_sock, rfds); - if (maxfd < channel->ch_sock) - maxfd = channel->ch_sock; - } # ifdef CHANNEL_PIPES - if (channel->ch_out >= 0) - { - FD_SET(channel->ch_out, rfds); - if (maxfd < channel->ch_out) - maxfd = channel->ch_out; - } - if (channel->ch_err >= 0) - { - FD_SET(channel->ch_err, rfds); - if (maxfd < channel->ch_err) - maxfd = channel->ch_err; - } + for (which = CHAN_SOCK; which < CHAN_IN; ++which) +# else + which = CHAN_SOCK; # endif - } + { + sock_T fd = channel->ch_pfd[which].ch_fd; + + if (fd >= 0) + { + FD_SET(fd, rfds); + if (maxfd < fd) + maxfd = fd; + } + } return maxfd; } @@ -1755,33 +1764,26 @@ channel_select_setup(int maxfd_in, void *rfds_in) int channel_select_check(int ret_in, void *rfds_in) { - int ret = ret_in; - channel_T *channel; - fd_set *rfds = rfds_in; + int ret = ret_in; + channel_T *channel; + fd_set *rfds = rfds_in; + int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) - { - if (ret > 0 && channel->ch_sock >= 0 - && FD_ISSET(channel->ch_sock, rfds)) - { - channel_read(channel, FALSE, "channel_select_check"); - --ret; - } # ifdef CHANNEL_PIPES - if (ret > 0 && channel->ch_out >= 0 - && FD_ISSET(channel->ch_out, rfds)) - { - channel_read(channel, FALSE, "channel_select_check"); - --ret; - } - if (ret > 0 && channel->ch_err >= 0 - && FD_ISSET(channel->ch_err, rfds)) - { - channel_read(channel, TRUE, "channel_select_check"); - --ret; - } + for (which = CHAN_SOCK; which < CHAN_IN; ++which) +# else + which = CHAN_SOCK; # endif - } + { + sock_T fd = channel->ch_pfd[which].ch_fd; + + if (ret > 0 && fd >= 0 && FD_ISSET(fd, rfds)) + { + channel_read(channel, which, "channel_select_check"); + --ret; + } + } return ret; } diff --git a/src/eval.c b/src/eval.c index 75f5e54b5f..a36f3dd51d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -9970,12 +9970,12 @@ f_ch_open(typval_T *argvars, typval_T *rettv) channel = channel_open((char *)address, port, waittime, NULL); if (channel != NULL) { + rettv->vval.v_channel = channel; channel_set_json_mode(channel, ch_mode); channel_set_timeout(channel, timeout); if (callback != NULL && *callback != NUL) channel_set_callback(channel, callback); } - rettv->vval.v_channel = channel; } /* diff --git a/src/feature.h b/src/feature.h index e1f8e27b78..ca01b064ca 100644 --- a/src/feature.h +++ b/src/feature.h @@ -1262,7 +1262,7 @@ #endif /* - * The +job feature requires +eval and Unix or MS-Widndows. + * The +job feature requires +eval and Unix or MS-Windows. */ #if (defined(UNIX) || defined(WIN32)) && defined(FEAT_EVAL) # define FEAT_JOB diff --git a/src/gui_w48.c b/src/gui_w48.c index 67274ee18c..6bafa8e0e4 100644 --- a/src/gui_w48.c +++ b/src/gui_w48.c @@ -1780,14 +1780,15 @@ process_message(void) #ifdef FEAT_CHANNEL if (msg.message == WM_NETBEANS) { - channel_T *channel = channel_fd2channel((sock_T)msg.wParam); + int what; + channel_T *channel = channel_fd2channel((sock_T)msg.wParam, &what); if (channel != NULL) { /* Disable error messages, they can mess up the display and throw * an exception. */ ++emsg_off; - channel_read(channel, FALSE, "process_message"); + channel_read(channel, what, "process_message"); --emsg_off; } return; diff --git a/src/os_unix.c b/src/os_unix.c index 01b5a93127..65a4b9265d 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5116,10 +5116,15 @@ mch_start_job(char **argv, job_T *job) close(fd_err[1]); channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]); channel_set_job(channel, job); +#ifdef FEAT_GUI + channel_gui_register(channel); +#endif return; failed: + if (channel != NULL) + channel_free(channel); if (fd_in[0] >= 0) { close(fd_in[0]); diff --git a/src/os_win32.c b/src/os_win32.c index cc5fc3dee9..55d8e6ba1d 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5039,12 +5039,19 @@ mch_start_job(char *cmd, job_T *job) STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE jo; +#ifdef FEAT_CHANNEL + channel_T *channel; + + channel = add_channel(); + if (channel == NULL) + return; +#endif jo = CreateJobObject(NULL, NULL); if (jo == NULL) { job->jv_status = JOB_FAILED; - return; + goto failed; } ZeroMemory(&pi, sizeof(pi)); @@ -5062,22 +5069,40 @@ mch_start_job(char *cmd, job_T *job) { CloseHandle(jo); job->jv_status = JOB_FAILED; + goto failed; } - else + + if (!AssignProcessToJobObject(jo, pi.hProcess)) { - 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; + /* 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; + +#ifdef FEAT_CHANNEL +# if 0 + /* TODO: connect stdin/stdout/stderr */ + job->jv_channel = channel; + channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]); + channel_set_job(channel, job); + +# ifdef FEAT_GUI + channel_gui_register(channel); +# endif +# endif +#endif + return; + +failed: +#ifdef FEAT_CHANNEL + channel_free(channel); +#endif } char * diff --git a/src/proto/channel.pro b/src/proto/channel.pro index 56eb887c17..f7480521e2 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -2,6 +2,7 @@ void ch_logfile(FILE *file); channel_T *add_channel(void); 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 (*close_cb)(void)); void channel_set_pipes(channel_T *channel, int in, int out, int err); @@ -21,10 +22,10 @@ char_u *channel_peek(channel_T *channel); void channel_clear(channel_T *channel); void channel_free_all(void); int channel_get_id(void); -void channel_read(channel_T *channel, int use_stderr, char *func); +void channel_read(channel_T *channel, int what, char *func); char_u *channel_read_block(channel_T *channel); int channel_read_json_block(channel_T *channel, int id, typval_T **rettv); -channel_T *channel_fd2channel(sock_T fd); +channel_T *channel_fd2channel(sock_T fd, int *what); int channel_send(channel_T *channel, char_u *buf, char *fun); int channel_poll_setup(int nfd_in, void *fds_in); int channel_poll_check(int ret_in, void *fds_in); diff --git a/src/structs.h b/src/structs.h index c8334cbea9..7dd4b46bdd 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1301,27 +1301,48 @@ typedef enum MODE_JS } ch_mode_T; +/* Ordering matters: IN is last, only SOCK/OUT/ERR are polled */ + +#define CHAN_SOCK 0 +#define CH_SOCK ch_pfd[CHAN_SOCK].ch_fd + +#ifdef UNIX +# define CHANNEL_PIPES + +# define CHAN_OUT 1 +# define CHAN_ERR 2 +# define CHAN_IN 3 +# define CH_OUT ch_pfd[CHAN_OUT].ch_fd +# define CH_ERR ch_pfd[CHAN_ERR].ch_fd +# define CH_IN ch_pfd[CHAN_IN].ch_fd +#endif + +/* The per-fd info for a channel. */ +typedef struct { + sock_T ch_fd; /* socket/stdin/stdout/stderr, -1 if not used */ + +# if defined(UNIX) && !defined(HAVE_SELECT) + int ch_poll_idx; /* used by channel_poll_setup() */ +# endif + +#ifdef FEAT_GUI_X11 + XtInputId ch_inputHandler; /* Cookie for input */ +#endif +#ifdef FEAT_GUI_GTK + gint ch_inputHandler; /* Cookie for input */ +#endif +#ifdef WIN32 + int ch_inputHandler; /* ret.value of WSAAsyncSelect() */ +#endif +} chan_fd_T; + struct channel_S { channel_T *ch_next; channel_T *ch_prev; int ch_id; /* ID of the channel */ - sock_T ch_sock; /* the socket, -1 for a closed channel */ - -#ifdef UNIX -# define CHANNEL_PIPES - int ch_in; /* stdin of the job, -1 if not used */ - int ch_out; /* stdout of the job, -1 if not used */ - int ch_err; /* stderr of the job, -1 if not used */ - -# if defined(UNIX) && !defined(HAVE_SELECT) - int ch_sock_idx; /* used by channel_poll_setup() */ - int ch_in_idx; /* used by channel_poll_setup() */ - int ch_out_idx; /* used by channel_poll_setup() */ - int ch_err_idx; /* used by channel_poll_setup() */ -# endif -#endif + chan_fd_T ch_pfd[4]; /* info for socket, in, out and err */ readq_T ch_head; /* dummy node, header for circular queue */ @@ -1330,16 +1351,6 @@ struct channel_S { * the other side has exited, only mention the * first error until the connection works * again. */ -#ifdef FEAT_GUI_X11 - XtInputId ch_inputHandler; /* Cookie for input */ -#endif -#ifdef FEAT_GUI_GTK - gint ch_inputHandler; /* Cookie for input */ -#endif -#ifdef WIN32 - int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */ -#endif - void (*ch_close_cb)(void); /* callback for when channel is closed */ int ch_block_id; /* ID that channel_read_json_block() is diff --git a/src/version.c b/src/version.c index f1abf12dea..5557b7451e 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1318, /**/ 1317, /**/ From 16eb4f88000cfdba68df6c421fe44e7e029ba53e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 14 Feb 2016 23:02:34 +0100 Subject: [PATCH 2/3] patch 7.4.1319 Problem: Tests fail on MS-Windows and on Unix with GUI. Solution: Fix unregistering. --- src/channel.c | 121 ++++++++++++++++++++++-------------------- src/os_unix.c | 2 +- src/os_win32.c | 18 +++---- src/proto/channel.pro | 4 +- src/structs.h | 7 +-- src/version.c | 2 + 6 files changed, 81 insertions(+), 73 deletions(-) diff --git a/src/channel.c b/src/channel.c index daf1c34caf..a806c5681a 100644 --- a/src/channel.c +++ b/src/channel.c @@ -339,8 +339,9 @@ channel_gui_register_one(channel_T *channel, int which) * is input on the editor connection socket. */ if (channel->ch_pfd[which].ch_inputHandler == 0) channel->ch_pfd[which].ch_inputHandler = gdk_input_add( - (gint)channel->ch_pfd[which].ch_fd, (GdkInputCondition) - ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), + (gint)channel->ch_pfd[which].ch_fd, + (GdkInputCondition) + ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), messageFromNetbeans, (gpointer)(long)channel->ch_id); # else @@ -362,12 +363,12 @@ channel_gui_register(channel_T *channel) if (!CH_HAS_GUI) return; - if (channel->ch_pfd[CHAN_SOCK].ch_fd >= 0) + if (channel->CH_SOCK >= 0) channel_gui_register_one(channel, CHAN_SOCK); # ifdef CHANNEL_PIPES - if (channel->ch_pfd[CHAN_OUT].ch_fd >= 0) + if (channel->CH_OUT >= 0) channel_gui_register_one(channel, CHAN_OUT); - if (channel->ch_pfd[CHAN_ERR].ch_fd >= 0) + if (channel->CH_ERR >= 0) channel_gui_register_one(channel, CHAN_ERR); # endif } @@ -386,44 +387,40 @@ channel_gui_register_all(void) } static void -channel_gui_unregister_one(channel_T *channel, int which) +channel_gui_unregister(channel_T *channel) { -# ifdef FEAT_GUI_X11 - if (channel->ch_pfd[which].ch_inputHandler != (XtInputId)NULL) + int which; + +#ifdef CHANNEL_PIPES + for (which = CHAN_SOCK; which < CHAN_IN; ++which) +#else + which = CHAN_SOCK; +#endif { - XtRemoveInput(channel->ch_pfd[which].ch_inputHandler); - channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; - } +# ifdef FEAT_GUI_X11 + if (channel->ch_pfd[which].ch_inputHandler != (XtInputId)NULL) + { + XtRemoveInput(channel->ch_pfd[which].ch_inputHandler); + channel->ch_pfd[which].ch_inputHandler = (XtInputId)NULL; + } # else # ifdef FEAT_GUI_GTK - if (channel->ch_pfd[which].ch_inputHandler != 0) - { - gdk_input_remove(channel->ch_pfd[which].ch_inputHandler); - channel->ch_pfd[which].ch_inputHandler = 0; - } + if (channel->ch_pfd[which].ch_inputHandler != 0) + { + gdk_input_remove(channel->ch_pfd[which].ch_inputHandler); + channel->ch_pfd[which].ch_inputHandler = 0; + } # else # ifdef FEAT_GUI_W32 - if (channel->ch_pfd[which].ch_inputHandler == 0) - { - WSAAsyncSelect(channel->ch_pfd[which].ch_fd, s_hwnd, 0, 0); - channel->ch_pfd[which].ch_inputHandler = -1; - } + if (channel->ch_pfd[which].ch_inputHandler == 0) + { + WSAAsyncSelect(channel->ch_pfd[which].ch_fd, s_hwnd, 0, 0); + channel->ch_pfd[which].ch_inputHandler = -1; + } # endif # endif # endif -} - - static void -channel_gui_unregister(channel_T *channel) -{ - if (channel->ch_pfd[CHAN_SOCK].ch_fd >= 0) - channel_gui_unregister_one(channel, CHAN_SOCK); -# ifdef CHANNEL_PIPES - if (channel->ch_pfd[CHAN_OUT].ch_fd >= 0) - channel_gui_unregister_one(channel, CHAN_OUT); - if (channel->ch_pfd[CHAN_ERR].ch_fd >= 0) - channel_gui_unregister_one(channel, CHAN_ERR); -# endif + } } #endif @@ -1192,16 +1189,14 @@ channel_close(channel_T *channel) { ch_log(channel, "Closing channel"); +#ifdef FEAT_GUI + channel_gui_unregister(channel); +#endif + if (channel->CH_SOCK >= 0) { sock_close(channel->CH_SOCK); channel->CH_SOCK = -1; - channel->ch_close_cb = NULL; -#ifdef FEAT_GUI - channel_gui_unregister(channel); -#endif - vim_free(channel->ch_callback); - channel->ch_callback = NULL; } #if defined(CHANNEL_PIPES) if (channel->CH_IN >= 0) @@ -1220,6 +1215,10 @@ channel_close(channel_T *channel) channel->CH_ERR = -1; } #endif + + channel->ch_close_cb = NULL; + vim_free(channel->ch_callback); + channel->ch_callback = NULL; channel_clear(channel); } @@ -1383,7 +1382,7 @@ channel_get_id(void) /* * Get the file descriptor to read from, either the socket or stdout. - * TODO: never gets stderr. + * TODO: should have a way to read stderr. */ static int get_read_fd(channel_T *channel) @@ -1400,7 +1399,8 @@ get_read_fd(channel_T *channel) /* * Read from channel "channel" for as long as there is something to read. - * "which" is CHAN_SOCK, CHAN_OUT or CHAN_ERR. When -1 guess. + * "which" is CHAN_SOCK, CHAN_OUT or CHAN_ERR. When -1 use CHAN_SOCK or + * CHAN_OUT, the one that is open. * The data is put in the read queue. */ void @@ -1475,19 +1475,12 @@ channel_read(channel_T *channel, int which, char *func) ch_errors(channel, "%s(): Cannot read\n", func); channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG)); - if (use_socket) - { - channel_close(channel); - if (channel->ch_close_cb != NULL) - (*channel->ch_close_cb)(); - } -#if defined(CHANNEL_PIPES) - else - { - close(fd); - channel->CH_OUT = -1; - } -#endif + /* TODO: When reading from stdout is not possible, should we try to + * keep stdin and stderr open? Probably not, assume the other side + * has died. */ + channel_close(channel); + if (channel->ch_close_cb != NULL) + (*channel->ch_close_cb)(); if (len < 0) { @@ -1587,6 +1580,7 @@ channel_fd2channel(sock_T fd, int *whichp) if (fd >= 0) for (channel = first_channel; channel != NULL; channel = channel->ch_next) + { # ifdef CHANNEL_PIPES for (i = CHAN_SOCK; i < CHAN_IN; ++i) # else @@ -1595,8 +1589,9 @@ channel_fd2channel(sock_T fd, int *whichp) if (channel->ch_pfd[i].ch_fd == fd) { *whichp = i; - return channel + return channel; } + } return NULL; } # endif @@ -1638,7 +1633,7 @@ channel_send(channel_T *channel, char_u *buf, char *fun) { ch_log_lead("SEND ", channel); fprintf(log_fd, "'"); - ignored = fwrite(buf, len, 1, log_fd); + ignored = (int)fwrite(buf, len, 1, log_fd); fprintf(log_fd, "'\n"); fflush(log_fd); } @@ -1677,11 +1672,13 @@ channel_poll_setup(int nfd_in, void *fds_in) int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) + { # ifdef CHANNEL_PIPES for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else which = CHAN_SOCK; # endif + { if (channel->ch_pfd[which].ch_fd >= 0) { channel->ch_pfd[which].ch_poll_idx = nfd; @@ -1691,6 +1688,8 @@ channel_poll_setup(int nfd_in, void *fds_in) } else channel->ch_pfd[which].ch_poll_idx = -1; + } + } return nfd; } @@ -1707,8 +1706,9 @@ channel_poll_check(int ret_in, void *fds_in) int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) + { # ifdef CHANNEL_PIPES - for (which = CHAN_SOCK; which < CHAN_IN; ++which) + for (which = CHAN_SOCK; which < CH_IN; ++which) # else which = CHAN_SOCK; # endif @@ -1721,6 +1721,7 @@ channel_poll_check(int ret_in, void *fds_in) --ret; } } + } return ret; } @@ -1739,6 +1740,7 @@ channel_select_setup(int maxfd_in, void *rfds_in) int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) + { # ifdef CHANNEL_PIPES for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else @@ -1754,6 +1756,7 @@ channel_select_setup(int maxfd_in, void *rfds_in) maxfd = fd; } } + } return maxfd; } @@ -1770,6 +1773,7 @@ channel_select_check(int ret_in, void *rfds_in) int which; for (channel = first_channel; channel != NULL; channel = channel->ch_next) + { # ifdef CHANNEL_PIPES for (which = CHAN_SOCK; which < CHAN_IN; ++which) # else @@ -1784,6 +1788,7 @@ channel_select_check(int ret_in, void *rfds_in) --ret; } } + } return ret; } diff --git a/src/os_unix.c b/src/os_unix.c index 65a4b9265d..ec7d6c19db 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -5043,7 +5043,7 @@ mch_start_job(char **argv, job_T *job) int fd_in[2]; /* for stdin */ int fd_out[2]; /* for stdout */ int fd_err[2]; /* for stderr */ - channel_T *channel; + channel_T *channel = NULL; /* default is to fail */ job->jv_status = JOB_FAILED; diff --git a/src/os_win32.c b/src/os_win32.c index 55d8e6ba1d..cac82230db 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5039,13 +5039,13 @@ mch_start_job(char *cmd, job_T *job) STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE jo; -#ifdef FEAT_CHANNEL - channel_T *channel; +# ifdef FEAT_CHANNEL + channel_T *channel; channel = add_channel(); if (channel == NULL) return; -#endif +# endif jo = CreateJobObject(NULL, NULL); if (jo == NULL) @@ -5085,24 +5085,24 @@ mch_start_job(char *cmd, job_T *job) job->jv_job_object = jo; job->jv_status = JOB_STARTED; -#ifdef FEAT_CHANNEL -# if 0 +# ifdef FEAT_CHANNEL +# if 0 /* TODO: connect stdin/stdout/stderr */ job->jv_channel = channel; channel_set_pipes(channel, fd_in[1], fd_out[0], fd_err[0]); channel_set_job(channel, job); -# ifdef FEAT_GUI +# ifdef FEAT_GUI channel_gui_register(channel); +# endif # endif # endif -#endif return; failed: -#ifdef FEAT_CHANNEL +# ifdef FEAT_CHANNEL channel_free(channel); -#endif +# endif } char * diff --git a/src/proto/channel.pro b/src/proto/channel.pro index f7480521e2..e6e050ce87 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -22,10 +22,10 @@ char_u *channel_peek(channel_T *channel); void channel_clear(channel_T *channel); void channel_free_all(void); int channel_get_id(void); -void channel_read(channel_T *channel, int what, char *func); +void channel_read(channel_T *channel, int which, char *func); char_u *channel_read_block(channel_T *channel); int channel_read_json_block(channel_T *channel, int id, typval_T **rettv); -channel_T *channel_fd2channel(sock_T fd, int *what); +channel_T *channel_fd2channel(sock_T fd, int *whichp); int channel_send(channel_T *channel, char_u *buf, char *fun); int channel_poll_setup(int nfd_in, void *fds_in); int channel_poll_check(int ret_in, void *fds_in); diff --git a/src/structs.h b/src/structs.h index 7dd4b46bdd..7f2f111bcd 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1301,8 +1301,8 @@ typedef enum MODE_JS } ch_mode_T; -/* Ordering matters: IN is last, only SOCK/OUT/ERR are polled */ - +/* Ordering matters, it is used in for loops: IN is last, only SOCK/OUT/ERR + * are polled. */ #define CHAN_SOCK 0 #define CH_SOCK ch_pfd[CHAN_SOCK].ch_fd @@ -1342,7 +1342,7 @@ struct channel_S { int ch_id; /* ID of the channel */ - chan_fd_T ch_pfd[4]; /* info for socket, in, out and err */ + chan_fd_T ch_pfd[4]; /* info for socket, out, err and in */ readq_T ch_head; /* dummy node, header for circular queue */ @@ -1351,6 +1351,7 @@ struct channel_S { * the other side has exited, only mention the * first error until the connection works * again. */ + void (*ch_close_cb)(void); /* callback for when channel is closed */ int ch_block_id; /* ID that channel_read_json_block() is diff --git a/src/version.c b/src/version.c index 5557b7451e..c047848fa8 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1319, /**/ 1318, /**/ From 44d571868f4fcf000e8b03ee0a350f1f8131c9ca Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 14 Feb 2016 23:11:23 +0100 Subject: [PATCH 3/3] patch 7.4.1320 Problem: Building with Cygwin or MingW with channel but without Netbeans doesn't work. Solution: Set NETBEANS to "no" when not used. --- src/Make_cyg_ming.mak | 6 ++++-- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 026c966bfe..28d31d6120 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -679,8 +679,10 @@ ifneq ($(CHANNEL),yes) # Cannot use Netbeans without CHANNEL NETBEANS=no else -# Only allow NETBEANS for a GUI build. -ifeq (yes, $(GUI)) +ifneq (yes, $(GUI)) +# Cannot use Netbeans without GUI. +NETBEANS=no +else OBJ += $(OUTDIR)/netbeans.o LIB += -lwsock32 endif diff --git a/src/version.c b/src/version.c index c047848fa8..a380ed3410 100644 --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1320, /**/ 1319, /**/