summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-14 19:13:43 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-14 19:13:43 +0100
commit7b3ca76a451b10d238ef946f3231762e0bd988e9 (patch)
treed05c9be4dafb1e5ae77eb76325df7cc40fda2e52
parent0727d362b4dad83d9fdf1caba074213e77e0aa49 (diff)
downloadvim-git-7b3ca76a451b10d238ef946f3231762e0bd988e9.tar.gz
patch 7.4.1318v7.4.1318
Problem: Channel with pipes doesn't work in GUI. Solution: Register input handlers for pipes.
-rw-r--r--src/channel.c406
-rw-r--r--src/eval.c2
-rw-r--r--src/feature.h2
-rw-r--r--src/gui_w48.c5
-rw-r--r--src/os_unix.c5
-rw-r--r--src/os_win32.c53
-rw-r--r--src/proto/channel.pro5
-rw-r--r--src/structs.h55
-rw-r--r--src/version.c2
9 files changed, 291 insertions, 244 deletions
diff --git a/src/channel.c b/src/channel.c
index dc05587be..daf1c34ca 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,46 +321,57 @@ messageFromNetbeans(gpointer clientData,
#endif
static void
-channel_gui_register(channel_T *channel)
+channel_gui_register_one(channel_T *channel, int which)
{
- 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);
+ /* 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_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);
+ /* 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_inputHandler == -1)
- channel->ch_inputHandler =
- WSAAsyncSelect(channel->ch_sock, s_hwnd, WM_NETBEANS, FD_READ);
+ /* 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;
+
+ 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
+}
+
/*
* Register any of our file descriptors with the GUI event handling system.
* Called when the GUI has started.
@@ -368,40 +382,50 @@ 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(channel_T *channel)
+channel_gui_unregister_one(channel_T *channel, int which)
{
- /* TODO: pipes */
# ifdef FEAT_GUI_X11
- if (channel->ch_inputHandler != (XtInputId)NULL)
+ if (channel->ch_pfd[which].ch_inputHandler != (XtInputId)NULL)
{
- XtRemoveInput(channel->ch_inputHandler);
- channel->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_inputHandler != 0)
+ if (channel->ch_pfd[which].ch_inputHandler != 0)
{
- gdk_input_remove(channel->ch_inputHandler);
- channel->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_inputHandler == 0)
+ if (channel->ch_pfd[which].ch_inputHandler == 0)
{
- WSAAsyncSelect(channel->ch_sock, s_hwnd, 0, 0);
- channel->ch_inputHandler = -1;
+ 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
/*
@@ -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)
+ for (which = CHAN_SOCK; which < CHAN_IN; ++which)
+# else
+ which = CHAN_SOCK;
+# endif
{
- channel_read(channel, TRUE, "channel_poll_check");
- --ret;
+ 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;
+ }
}
-# endif
- }
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)
+ for (which = CHAN_SOCK; which < CHAN_IN; ++which)
+# else
+ which = CHAN_SOCK;
+# endif
{
- FD_SET(channel->ch_err, rfds);
- if (maxfd < channel->ch_err)
- maxfd = channel->ch_err;
+ sock_T fd = channel->ch_pfd[which].ch_fd;
+
+ if (fd >= 0)
+ {
+ FD_SET(fd, rfds);
+ if (maxfd < fd)
+ maxfd = fd;
+ }
}
-# endif
- }
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))
+ for (which = CHAN_SOCK; which < CHAN_IN; ++which)
+# else
+ which = CHAN_SOCK;
+# endif
{
- channel_read(channel, TRUE, "channel_select_check");
- --ret;
+ 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;
+ }
}
-# endif
- }
return ret;
}
diff --git a/src/eval.c b/src/eval.c
index 75f5e54b5..a36f3dd51 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 e1f8e27b7..ca01b064c 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 67274ee18..6bafa8e0e 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 01b5a9312..65a4b9265 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 cc5fc3dee..55d8e6ba1 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 56eb887c1..f7480521e 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 c8334cbea..7dd4b46bd 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1301,35 +1301,30 @@ typedef enum
MODE_JS
} ch_mode_T;
-struct channel_S {
- channel_T *ch_next;
- channel_T *ch_prev;
-
- int ch_id; /* ID of the channel */
+/* Ordering matters: IN is last, only SOCK/OUT/ERR are polled */
- sock_T ch_sock; /* the socket, -1 for a closed channel */
+#define CHAN_SOCK 0
+#define CH_SOCK ch_pfd[CHAN_SOCK].ch_fd
#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
+# 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
- readq_T ch_head; /* dummy node, header for circular queue */
+/* 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
- int ch_error; /* When TRUE an error was reported. Avoids
- * giving pages full of error messages when
- * 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
@@ -1337,9 +1332,25 @@ struct channel_S {
gint ch_inputHandler; /* Cookie for input */
#endif
#ifdef WIN32
- int ch_inputHandler; /* simply ret.value of WSAAsyncSelect() */
+ 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 */
+
+ chan_fd_T ch_pfd[4]; /* info for socket, in, out and err */
+ readq_T ch_head; /* dummy node, header for circular queue */
+
+ int ch_error; /* When TRUE an error was reported. Avoids
+ * giving pages full of error messages when
+ * 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 f1abf12de..5557b7451 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 */
/**/
+ 1318,
+/**/
1317,
/**/
1316,