On Friday, 5 February 2016 13:37:07 UTC-8, Bram Moolenaar  wrote:
> Patch 7.4.1263
> Problem:    ch_open() hangs when the server isn't running.
> Solution:   Add a timeout. Use a dict to pass arguments. (Yasuhiro Matsumoto)
> Files:      runtime/doc/eval.txt, runtime/doc/channel.txt, src/channel.c,
>             src/eval.c, src/netbeans.c, src/os_win32.c, src/proto/channel.pro,
>             src/testdir/test_channel.vim
> 
> 
> *** ../vim-7.4.1262/runtime/doc/eval.txt      2016-02-02 20:46:29.715412004 
> +0100
> --- runtime/doc/eval.txt      2016-02-05 21:53:15.728780022 +0100
> ***************
> *** 1786,1793 ****
>                               any     call {func} with arguments {arglist}
>   ceil( {expr})                       Float   round {expr} up
>   ch_close( {handle})         none    close a channel
> ! ch_open( {address}, {mode} [, {callback}])
> !                             Number  open a channel
>   ch_sendexpr( {handle}, {expr} [, {callback}])
>                               any     send {expr} over JSON channel {handle}
>   ch_sendraw( {handle}, {string} [, {callback}])
> --- 1811,1817 ----
>                               any     call {func} with arguments {arglist}
>   ceil( {expr})                       Float   round {expr} up
>   ch_close( {handle})         none    close a channel
> ! ch_open( {address} [, {argdict})] Number open a channel to {address}
>   ch_sendexpr( {handle}, {expr} [, {callback}])
>                               any     send {expr} over JSON channel {handle}
>   ch_sendraw( {handle}, {string} [, {callback}])
> ***************
> *** 2641,2647 ****
>   ch_close({handle})                                  *ch_close()*
>               Close channel {handle}.  See |channel|.
>   
> ! ch_open({address}, {mode} [, {callback}])           *ch_open()*
>               Open a channel to {address}.  See |channel|.
>               Returns the channel handle on success.  Returns a negative
>               number for failure.
> --- 2669,2675 ----
>   ch_close({handle})                                  *ch_close()*
>               Close channel {handle}.  See |channel|.
>   
> ! ch_open({address} [, {argdict}])                            *ch_open()*
>               Open a channel to {address}.  See |channel|.
>               Returns the channel handle on success.  Returns a negative
>               number for failure.
> ***************
> *** 2649,2661 ****
>               {address} has the form "hostname:port", e.g.,
>               "localhost:8765".
>   
> !             {mode} is either "json" or "raw".  See |channel-mode| for the
> !             meaning.
> ! 
> !             {callback} is a function that handles received messages on the
> !             channel.  See |channel-callback|.
>   
> ! ch_sendexpr({handle}, {expr} [, {callback}])                ch_*sendexpr()*
>               Send {expr} over JSON channel {handle}.  See |channel-use|.
>   
>               When {callback} is given returns immediately.  Without
> --- 2677,2697 ----
>               {address} has the form "hostname:port", e.g.,
>               "localhost:8765".
>   
> !             If {argdict} is given it must be a |Directory|.  The optional
> !             items are:
> !                     mode        "raw" or "json".
> !                                 Default "json".
> !                     callback    function to call for requests with a zero
> !                                 sequence number.  See |channel-callback|.
> !                                 Default: none.
> !                     waittime    Specify connect timeout as milliseconds.
> !                                 Negative means forever.
> !                                 Default: 0.
> !                     timeout     Specify response read timeout value as
> !                                 milliseconds. 
> !                                 Default: 2000.
>   
> ! ch_sendexpr({handle}, {expr} [, {callback}])                *ch_sendexpr()*
>               Send {expr} over JSON channel {handle}.  See |channel-use|.
>   
>               When {callback} is given returns immediately.  Without
> *** ../vim-7.4.1262/runtime/doc/channel.txt   2016-01-31 20:24:09.970066843 
> +0100
> --- runtime/doc/channel.txt   2016-02-05 22:13:51.287732962 +0100
> ***************
> *** 1,4 ****
> ! *channel.txt*      For Vim version 7.4.  Last change: 2016 Jan 31
>   
>   
>                 VIM REFERENCE MANUAL    by Bram Moolenaar
> --- 1,4 ----
> ! *channel.txt*      For Vim version 7.4.  Last change: 2016 Feb 05
>   
>   
>                 VIM REFERENCE MANUAL    by Bram Moolenaar
> ***************
> *** 11,17 ****
>   Vim uses channels to communicate with other processes.
>   A channel uses a socket.                            *socket-interface*
>   
> ! Vim current supports up to 10 simultanious channels.
>   The Netbeans interface also uses a channel. |netbeans|
>   
>   1. Demo                                     |channel-demo|
> --- 11,17 ----
>   Vim uses channels to communicate with other processes.
>   A channel uses a socket.                            *socket-interface*
>   
> ! Vim current supports up to 10 simultaneous channels.
>   The Netbeans interface also uses a channel. |netbeans|
>   
>   1. Demo                                     |channel-demo|
> ***************
> *** 32,44 ****
>   Run it in one terminal.  We will call this T1.
>   
>   Run Vim in another terminal.  Connect to the demo server with: >
> !     let handle = connect('localhost:8765', 'json')
>   
>   In T1 you should see:
>       === socket opened === ~
>   
>   You can now send a message to the server: >
> !     echo sendexpr(handle, 'hello!')
>   
>   The message is received in T1 and a response is sent back to Vim.
>   You can see the raw messages in T1.  What Vim sends is:
> --- 32,44 ----
>   Run it in one terminal.  We will call this T1.
>   
>   Run Vim in another terminal.  Connect to the demo server with: >
> !     let handle = ch_open('localhost:8765')
>   
>   In T1 you should see:
>       === socket opened === ~
>   
>   You can now send a message to the server: >
> !     echo ch_sendexpr(handle, 'hello!')
>   
>   The message is received in T1 and a response is sent back to Vim.
>   You can see the raw messages in T1.  What Vim sends is:
> ***************
> *** 57,104 ****
>       func MyHandler(handle, msg)
>         echo "from the handler: " . a:msg
>       endfunc
> !     call sendexpr(handle, 'hello!', "MyHandler")
>   
>   Instead of giving a callback with every send call, it can also be specified
>   when opening the channel: >
> !     call disconnect(handle)
> !     let handle = connect('localhost:8765', 'json', "MyHandler")
> !     call sendexpr(handle, 'hello!', 0)
>   
>   
> ==============================================================================
>   2. Opening a channel                                        *channel-open*
>   
> ! To open a channel:
> !     let handle = connect({address}, {mode}, {callback})
>   
>   {address} has the form "hostname:port".  E.g., "localhost:8765".
>   
> ! {mode} can be:                                              *channel-mode*
> !     "json" - Use JSON, see below; most convenient way
>       "raw"  - Use raw messages
>   
>                                                       *channel-callback*
> ! {callback} is a function that is called when a message is received that is 
> not
>   handled otherwise.  It gets two arguments: the channel handle and the 
> received
>   message. Example: >
>       func Handle(handle, msg)
>         echo 'Received: ' . a:msg
>       endfunc
> !     let handle = connect("localhost:8765", 'json', "Handle")
>   
> ! When {mode} is "json" the "msg" argument is the body of the received 
> message,
>   converted to Vim types.
> ! When {mode} is "raw" the "msg" argument is the whole message as a string.
>   
> ! When {mode} is "json" the {callback} is optional.  When omitted it is only
>   possible to receive a message after sending one.
>   
>   The handler can be added or changed later: >
> !     call sethandler(handle, {callback})
> ! When {callback} is empty (zero or an empty string) the handler is removed.
>   
>   Once done with the channel, disconnect it like this: >
> !     call disconnect(handle)
>   
>   Currently up to 10 channels can be in use at the same time. *E897*
>   
> --- 57,118 ----
>       func MyHandler(handle, msg)
>         echo "from the handler: " . a:msg
>       endfunc
> !     call ch_sendexpr(handle, 'hello!', "MyHandler")
>   
>   Instead of giving a callback with every send call, it can also be specified
>   when opening the channel: >
> !     call ch_close(handle)
> !     let handle = ch_open('localhost:8765', {'callback': "MyHandler"})
> !     call ch_sendexpr(handle, 'hello!', 0)
>   
>   
> ==============================================================================
>   2. Opening a channel                                        *channel-open*
>   
> ! To open a channel: >
> !     let handle = ch_open({address} [, {argdict}])
>   
>   {address} has the form "hostname:port".  E.g., "localhost:8765".
>   
> ! {argdict} is a dictionary with optional entries:
> ! 
> ! "mode" can be:                                              *channel-mode*
> !     "json" - Use JSON, see below; most convenient way. Default.
>       "raw"  - Use raw messages
>   
>                                                       *channel-callback*
> ! "callback" is a function that is called when a message is received that is 
> not
>   handled otherwise.  It gets two arguments: the channel handle and the 
> received
>   message. Example: >
>       func Handle(handle, msg)
>         echo 'Received: ' . a:msg
>       endfunc
> !     let handle = ch_open("localhost:8765", 'json', "Handle")
> ! 
> ! "waittime" is the time to wait for the connection to be made in 
> milliseconds.
> ! The default is zero, don't wait, which is useful if the server is supposed 
> to
> ! be running already.  A negative number waits forever.
> ! 
> ! "timeout" is the time to wait for a request when blocking, using
> ! ch_sendexpr().  Again in millisecons.  The default si 2000 (2 seconds).
>   
> ! When "mode" is "json" the "msg" argument is the body of the received 
> message,
>   converted to Vim types.
> ! When "mode" is "raw" the "msg" argument is the whole message as a string.
>   
> ! When "mode" is "json" the "callback" is optional.  When omitted it is only
>   possible to receive a message after sending one.
>   
>   The handler can be added or changed later: >
> !     call ch_setcallback(handle, {callback})
> ! When "callback is empty (zero or an empty string) the handler is removed.
> ! NOT IMPLEMENTED YET
> ! 
> ! The timeout can be changed later: >
> !     call ch_settimeout(handle, {msec})
> ! NOT IMPLEMENTED YET
>   
>   Once done with the channel, disconnect it like this: >
> !     call ch_close(handle)
>   
>   Currently up to 10 channels can be in use at the same time. *E897*
>   
> ***************
> *** 112,126 ****
>   3. Using a JSON channel                                     *channel-use*
>   
>   If {mode} is "json" then a message can be sent synchronously like this: >
> !     let response = sendexpr(handle, {expr})
>   This awaits a response from the other side.
>   
>   To send a message, without handling a response: >
> !     call sendexpr(handle, {expr}, 0)
>   
>   To send a message and letting the response handled by a specific function,
>   asynchronously: >
> !     call sendexpr(handle, {expr}, {callback})
>   
>   The {expr} is converted to JSON and wrapped in an array.  An example of the
>   message that the receiver will get when {expr} is the string "hello":
> --- 126,140 ----
>   3. Using a JSON channel                                     *channel-use*
>   
>   If {mode} is "json" then a message can be sent synchronously like this: >
> !     let response = ch_sendexpr(handle, {expr})
>   This awaits a response from the other side.
>   
>   To send a message, without handling a response: >
> !     call ch_sendexpr(handle, {expr}, 0)
>   
>   To send a message and letting the response handled by a specific function,
>   asynchronously: >
> !     call ch_sendexpr(handle, {expr}, {callback})
>   
>   The {expr} is converted to JSON and wrapped in an array.  An example of the
>   message that the receiver will get when {expr} is the string "hello":
> ***************
> *** 148,154 ****
>   Then channel handler will then get {response} converted to Vim types.  If 
> the
>   channel does not have a handler the message is dropped.
>   
> ! On read error or disconnect() the string "DETACH" is sent, if still 
> possible.
>   The channel will then be inactive.
>   
>   
> ==============================================================================
> --- 162,168 ----
>   Then channel handler will then get {response} converted to Vim types.  If 
> the
>   channel does not have a handler the message is dropped.
>   
> ! On read error or ch_close() the string "DETACH" is sent, if still possible.
>   The channel will then be inactive.
>   
>   
> ==============================================================================
> ***************
> *** 200,206 ****
>   
>   Command "normal" ~
>   
> ! The "normal" command is executed like with |:normal!|, commands are not
>   mapped.  Example to open the folds under the cursor:
>       ["normal" "zO"]
>   
> --- 214,220 ----
>   
>   Command "normal" ~
>   
> ! The "normal" command is executed like with ":normal!", commands are not
>   mapped.  Example to open the folds under the cursor:
>       ["normal" "zO"]
>   
> ***************
> *** 230,248 ****
>   5. Using a raw channel                                      *channel-raw*
>   
>   If {mode} is "raw" then a message can be send like this: >
> !     let response = sendraw(handle, {string})
>   The {string} is sent as-is.  The response will be what can be read from the
>   channel right away.  Since Vim doesn't know how to recognize the end of the
>   message you need to take care of it yourself.
>   
>   To send a message, without expecting a response: >
> !     call sendraw(handle, {string}, 0)
>   The process can send back a response, the channel handler will be called 
> with
>   it.
>   
>   To send a message and letting the response handled by a specific function,
>   asynchronously: >
> !     call sendraw(handle, {string}, {callback})
>   
>   This {string} can also be JSON, use |jsonencode()| to create it and
>   |jsondecode()| to handle a received JSON message.
> --- 244,262 ----
>   5. Using a raw channel                                      *channel-raw*
>   
>   If {mode} is "raw" then a message can be send like this: >
> !     let response = ch_sendraw(handle, {string})
>   The {string} is sent as-is.  The response will be what can be read from the
>   channel right away.  Since Vim doesn't know how to recognize the end of the
>   message you need to take care of it yourself.
>   
>   To send a message, without expecting a response: >
> !     call ch_sendraw(handle, {string}, 0)
>   The process can send back a response, the channel handler will be called 
> with
>   it.
>   
>   To send a message and letting the response handled by a specific function,
>   asynchronously: >
> !     call ch_sendraw(handle, {string}, {callback})
>   
>   This {string} can also be JSON, use |jsonencode()| to create it and
>   |jsondecode()| to handle a received JSON message.
> *** ../vim-7.4.1262/src/channel.c     2016-02-05 21:04:02.820081559 +0100
> --- src/channel.c     2016-02-05 22:30:40.557174945 +0100
> ***************
> *** 42,47 ****
> --- 42,49 ----
>   # define SOCK_ERRNO errno = WSAGetLastError()
>   # undef ECONNREFUSED
>   # define ECONNREFUSED WSAECONNREFUSED
> + # undef EWOULDBLOCK
> + # define EWOULDBLOCK WSAEWOULDBLOCK
>   # ifdef EINTR
>   #  undef EINTR
>   # endif
> ***************
> *** 119,124 ****
> --- 121,128 ----
>   
>       int           ch_json_mode;     /* TRUE for a json channel */
>       jsonq_T   ch_json_head; /* dummy node, header for circular queue */
> + 
> +     int       ch_timeout;   /* request timeout in msec */
>   } channel_T;
>   
>   /*
> ***************
> *** 133,138 ****
> --- 137,184 ----
>    */
>   FILE *debugfd = NULL;
>   
> + #ifdef _WIN32
> + # undef PERROR
> + # define PERROR(msg) (void)emsg3((char_u *)"%s: %s", \
> +     (char_u *)msg, (char_u *)strerror_win32(errno))
> + 
> +     static char *
> + strerror_win32(int eno)
> + {
> +     static LPVOID msgbuf = NULL;
> +     char_u *ptr;
> + 
> +     if (msgbuf)
> +     LocalFree(msgbuf);
> +     FormatMessage(
> +     FORMAT_MESSAGE_ALLOCATE_BUFFER |
> +     FORMAT_MESSAGE_FROM_SYSTEM |
> +     FORMAT_MESSAGE_IGNORE_INSERTS,
> +     NULL,
> +     eno,
> +     MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
> +     (LPTSTR) &msgbuf,
> +     0,
> +     NULL);
> +     /* chomp \r or \n */
> +     for (ptr = (char_u *)msgbuf; *ptr; ptr++)
> +     switch (*ptr)
> +     {
> +         case '\r':
> +             STRMOVE(ptr, ptr + 1);
> +             ptr--;
> +             break;
> +         case '\n':
> +             if (*(ptr + 1) == '\0')
> +                 *ptr = '\0';
> +             else
> +                 *ptr = ' ';
> +             break;
> +     }
> +     return msgbuf;
> + }
> + #endif
> + 
>   /*
>    * Add a new channel slot, return the index.
>    * The channel isn't actually used into ch_fd is set >= 0;
> ***************
> *** 182,187 ****
> --- 228,235 ----
>       ch->ch_json_head.next = &ch->ch_json_head;
>       ch->ch_json_head.prev = &ch->ch_json_head;
>   
> +     ch->ch_timeout = 2000;
> + 
>       return channel_count++;
>   }
>   
> ***************
> *** 303,319 ****
>    * Returns a negative number for failure.
>    */
>       int
> ! channel_open(char *hostname, int port_in, void (*close_cb)(void))
>   {
>       int                     sd;
>       struct sockaddr_in      server;
>       struct hostent *        host;
>   #ifdef WIN32
>       u_short         port = port_in;
>   #else
>       int                     port = port_in;
>   #endif
>       int                     idx;
>   
>   #ifdef WIN32
>       channel_init_winsock();
> --- 351,369 ----
>    * Returns a negative number for failure.
>    */
>       int
> ! channel_open(char *hostname, int port_in, int waittime, void 
> (*close_cb)(void))
>   {
>       int                     sd;
>       struct sockaddr_in      server;
>       struct hostent *        host;
>   #ifdef WIN32
>       u_short         port = port_in;
> +     u_long          val = 1;
>   #else
>       int                     port = port_in;
>   #endif
>       int                     idx;
> +     int                     ret;
>   
>   #ifdef WIN32
>       channel_init_winsock();
> ***************
> *** 348,410 ****
>       }
>       memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
>   
> !     /* Connect to server */
> !     if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
>       {
> !     SOCK_ERRNO;
> !     CHERROR("channel_open: Connect failed with errno %d\n", errno);
> !     if (errno == ECONNREFUSED)
>       {
>           sock_close(sd);
> !         if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
> !         {
> !             SOCK_ERRNO;
> !             CHERROR("socket() retry in channel_open()\n", "");
> !             PERROR("E900: socket() retry in channel_open()");
> !             return -1;
> !         }
> !         if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
> !         {
> !             int retries = 36;
> !             int success = FALSE;
>   
> !             SOCK_ERRNO;
> !             while (retries-- && ((errno == ECONNREFUSED)
> !                                                      || (errno == EINTR)))
> !             {
> !                 CHERROR("retrying...\n", "");
> !                 mch_delay(3000L, TRUE);
> !                 ui_breakcheck();
> !                 if (got_int)
> !                 {
> !                     errno = EINTR;
> !                     break;
> !                 }
> !                 if (connect(sd, (struct sockaddr *)&server,
> !                                                      sizeof(server)) == 0)
> !                 {
> !                     success = TRUE;
> !                     break;
> !                 }
> !                 SOCK_ERRNO;
> !             }
> !             if (!success)
> !             {
> !                 /* Get here when the server can't be found. */
> !                 CHERROR("Cannot connect to port after retry\n", "");
> !                 PERROR(_("E899: Cannot connect to port after retry2"));
> !                 sock_close(sd);
> !                 return -1;
> !             }
> !         }
>       }
> !     else
>       {
>           CHERROR("Cannot connect to port\n", "");
>           PERROR(_("E902: Cannot connect to port"));
>           sock_close(sd);
>           return -1;
>       }
>       }
>   
>       channels[idx].ch_fd = sd;
> --- 398,518 ----
>       }
>       memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
>   
> !     if (waittime >= 0)
>       {
> !     /* Make connect non-blocking. */
> !     if (
> ! #ifdef _WIN32
> !         ioctlsocket(sd, FIONBIO, &val) < 0
> ! #else
> !         fcntl(sd, F_SETFL, O_NONBLOCK) < 0
> ! #endif
> !        )
>       {
> +         SOCK_ERRNO;
> +         CHERROR("channel_open: Connect failed with errno %d\n", errno);
>           sock_close(sd);
> !         return -1;
> !     }
> !     }
>   
> !     /* Try connecting to the server. */
> !     ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
> !     SOCK_ERRNO;
> !     if (ret < 0)
> !     {
> !     if (errno != EWOULDBLOCK && errno != EINPROGRESS)
> !     {
> !         CHERROR("channel_open: Connect failed with errno %d\n", errno);
> !         CHERROR("Cannot connect to port\n", "");
> !         PERROR(_("E902: Cannot connect to port"));
> !         sock_close(sd);
> !         return -1;
>       }
> !     }
> ! 
> !     if (waittime >= 0)
> !     {
> !     struct timeval  tv;
> !     fd_set          rfds, wfds;
> ! 
> !     FD_ZERO(&rfds);
> !     FD_ZERO(&wfds);
> !     FD_SET(sd, &rfds);
> !     FD_SET(sd, &wfds);
> !     tv.tv_sec = waittime;
> !     tv.tv_usec = 0;
> !     ret = select((int)sd+1, &rfds, &wfds, NULL, &tv);
> !     if (ret < 0)
>       {
> +         SOCK_ERRNO;
> +         CHERROR("channel_open: Connect failed with errno %d\n", errno);
>           CHERROR("Cannot connect to port\n", "");
>           PERROR(_("E902: Cannot connect to port"));
>           sock_close(sd);
>           return -1;
>       }
> +     if (!FD_ISSET(sd, &rfds) && !FD_ISSET(sd, &wfds))
> +     {
> +         errno = ECONNREFUSED;
> +         CHERROR("Cannot connect to port\n", "");
> +         PERROR(_("E902: Cannot connect to port"));
> +         sock_close(sd);
> +         return -1;
> +     }
> + 
> + #ifdef _WIN32
> +     val = 0;
> +     ioctlsocket(sd, FIONBIO, &val);
> + #else
> +     fcntl(sd, F_SETFL, 0);
> + #endif
> +     }
> + 
> +     if (errno == ECONNREFUSED)
> +     {
> +     sock_close(sd);
> +     if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1)
> +     {
> +         SOCK_ERRNO;
> +         CHERROR("socket() retry in channel_open()\n", "");
> +         PERROR("E900: socket() retry in channel_open()");
> +         return -1;
> +     }
> +     if (connect(sd, (struct sockaddr *)&server, sizeof(server)))
> +     {
> +         int retries = 36;
> +         int success = FALSE;
> + 
> +         SOCK_ERRNO;
> +         while (retries-- && ((errno == ECONNREFUSED)
> +                                                  || (errno == EINTR)))
> +         {
> +             CHERROR("retrying...\n", "");
> +             mch_delay(3000L, TRUE);
> +             ui_breakcheck();
> +             if (got_int)
> +             {
> +                 errno = EINTR;
> +                 break;
> +             }
> +             if (connect(sd, (struct sockaddr *)&server,
> +                                                  sizeof(server)) == 0)
> +             {
> +                 success = TRUE;
> +                 break;
> +             }
> +             SOCK_ERRNO;
> +         }
> +         if (!success)
> +         {
> +             /* Get here when the server can't be found. */
> +             CHERROR("Cannot connect to port after retry\n", "");
> +             PERROR(_("E899: Cannot connect to port after retry2"));
> +             sock_close(sd);
> +             return -1;
> +         }
> +     }
>       }
>   
>       channels[idx].ch_fd = sd;
> ***************
> *** 427,432 ****
> --- 535,549 ----
>   }
>   
>   /*
> +  * Set the read timeout of channel "idx".
> +  */
> +     void
> + channel_set_timeout(int idx, int timeout)
> + {
> +     channels[idx].ch_timeout = timeout;
> + }
> + 
> + /*
>    * Set the callback for channel "idx".
>    */
>       void
> ***************
> *** 898,903 ****
> --- 1015,1021 ----
>   #endif
>       vim_free(channel->ch_callback);
>       channel->ch_callback = NULL;
> +     channel->ch_timeout = 2000;
>   
>       while (channel_peek(idx) != NULL)
>           vim_free(channel_get(idx));
> ***************
> *** 1148,1156 ****
>   {
>       if (channel_peek(idx) == NULL)
>       {
> !     /* Wait for up to 2 seconds.
> !      * TODO: use timeout set on the channel. */
> !     if (channel_wait(channels[idx].ch_fd, 2000) == FAIL)
>           return NULL;
>       channel_read(idx);
>       }
> --- 1266,1273 ----
>   {
>       if (channel_peek(idx) == NULL)
>       {
> !     /* Wait for up to the channel timeout. */
> !     if (channel_wait(channels[idx].ch_fd, channels[idx].ch_timeout) == FAIL)
>           return NULL;
>       channel_read(idx);
>       }
> ***************
> *** 1161,1167 ****
>   /*
>    * Read one JSON message from channel "ch_idx" with ID "id" and store the
>    * result in "rettv".
> !  * Blocks until the message is received.
>    */
>       int
>   channel_read_json_block(int ch_idx, int id, typval_T **rettv)
> --- 1278,1284 ----
>   /*
>    * Read one JSON message from channel "ch_idx" with ID "id" and store the
>    * result in "rettv".
> !  * Blocks until the message is received or the timeout is reached.
>    */
>       int
>   channel_read_json_block(int ch_idx, int id, typval_T **rettv)
> ***************
> *** 1183,1192 ****
>           if (channel_parse_messages())
>               continue;
>   
> !         /* Wait for up to 2 seconds.
> !          * TODO: use timeout set on the channel. */
>           if (channels[ch_idx].ch_fd < 0
> !                     || channel_wait(channels[ch_idx].ch_fd, 2000) == FAIL)
>               break;
>           channel_read(ch_idx);
>       }
> --- 1300,1309 ----
>           if (channel_parse_messages())
>               continue;
>   
> !         /* Wait for up to the channel timeout. */
>           if (channels[ch_idx].ch_fd < 0
> !                     || channel_wait(channels[ch_idx].ch_fd,
> !                                      channels[ch_idx].ch_timeout) == FAIL)
>               break;
>           channel_read(ch_idx);
>       }
> *** ../vim-7.4.1262/src/eval.c        2016-02-05 21:04:02.816081601 +0100
> --- src/eval.c        2016-02-05 22:16:43.797919909 +0100
> ***************
> *** 8005,8011 ****
>   #endif
>   #ifdef FEAT_CHANNEL
>       {"ch_close",    1, 1, f_ch_close},
> !     {"ch_open",             2, 3, f_ch_open},
>       {"ch_sendexpr", 2, 3, f_ch_sendexpr},
>       {"ch_sendraw",  2, 3, f_ch_sendraw},
>   #endif
> --- 8005,8011 ----
>   #endif
>   #ifdef FEAT_CHANNEL
>       {"ch_close",    1, 1, f_ch_close},
> !     {"ch_open",             1, 2, f_ch_open},
>       {"ch_sendexpr", 2, 3, f_ch_sendexpr},
>       {"ch_sendraw",  2, 3, f_ch_sendraw},
>   #endif
> ***************
> *** 9743,9763 ****
>       char_u  *address;
>       char_u  *mode;
>       char_u  *callback = NULL;
> -     char_u  buf1[NUMBUFLEN];
>       char_u  *p;
>       int             port;
> !     int             json_mode = FALSE;
>   
>       /* default: fail */
>       rettv->vval.v_number = -1;
>   
>       address = get_tv_string(&argvars[0]);
> !     mode = get_tv_string_buf(&argvars[1], buf1);
> !     if (argvars[2].v_type != VAR_UNKNOWN)
>       {
> !     callback = get_callback(&argvars[2]);
> !     if (callback == NULL)
> !         return;
>       }
>   
>       /* parse address */
> --- 9743,9765 ----
>       char_u  *address;
>       char_u  *mode;
>       char_u  *callback = NULL;
>       char_u  *p;
> +     char    *rest;
>       int             port;
> !     int             waittime = 0;
> !     int             timeout = 2000;
> !     int             json_mode = TRUE;
> !     int             ch_idx;
>   
>       /* default: fail */
>       rettv->vval.v_number = -1;
>   
>       address = get_tv_string(&argvars[0]);
> !     if (argvars[1].v_type != VAR_UNKNOWN
> !      && (argvars[1].v_type != VAR_DICT || argvars[1].vval.v_dict == NULL))
>       {
> !     EMSG(_(e_invarg));
> !     return;
>       }
>   
>       /* parse address */
> ***************
> *** 9768,9797 ****
>       return;
>       }
>       *p++ = NUL;
> !     port = atoi((char *)p);
> !     if (*address == NUL || port <= 0)
>       {
>       p[-1] = ':';
>       EMSG2(_(e_invarg2), address);
>       return;
>       }
>   
> !     /* parse mode */
> !     if (STRCMP(mode, "json") == 0)
> !     json_mode = TRUE;
> !     else if (STRCMP(mode, "raw") != 0)
>       {
> !     EMSG2(_(e_invarg2), mode);
>       return;
>       }
>   
> !     rettv->vval.v_number = channel_open((char *)address, port, NULL);
> !     if (rettv->vval.v_number >= 0)
>       {
> !     channel_set_json_mode(rettv->vval.v_number, json_mode);
>       if (callback != NULL && *callback != NUL)
> !         channel_set_callback(rettv->vval.v_number, callback);
>       }
>   }
>   
>   /*
> --- 9770,9821 ----
>       return;
>       }
>       *p++ = NUL;
> !     port = strtol((char *)p, &rest, 10);
> !     if (*address == NUL || port <= 0 || *rest != NUL)
>       {
>       p[-1] = ':';
>       EMSG2(_(e_invarg2), address);
>       return;
>       }
>   
> !     if (argvars[1].v_type == VAR_DICT)
> !     {
> !     /* parse argdict */
> !     dict_T  *dict = argvars[1].vval.v_dict;
> ! 
> !     if (dict_find(dict, (char_u *)"mode", -1) != NULL)
> !     {
> !         mode = get_dict_string(dict, (char_u *)"mode", FALSE);
> !         if (STRCMP(mode, "raw") == 0)
> !             json_mode = FALSE;
> !         else if (STRCMP(mode, "json") != 0)
> !         {
> !             EMSG2(_(e_invarg2), mode);
> !             return;
> !         }
> !     }
> !     if (dict_find(dict, (char_u *)"waittime", -1) != NULL)
> !         waittime = get_dict_number(dict, (char_u *)"waittime");
> !     if (dict_find(dict, (char_u *)"timeout", -1) != NULL)
> !         timeout = get_dict_number(dict, (char_u *)"timeout");
> !     if (dict_find(dict, (char_u *)"callback", -1) != NULL)
> !         callback = get_dict_string(dict, (char_u *)"callback", FALSE);
> !     }
> !     if (waittime < 0 || timeout < 0)
>       {
> !     EMSG(_(e_invarg));
>       return;
>       }
>   
> !     ch_idx = channel_open((char *)address, port, waittime, NULL);
> !     if (ch_idx >= 0)
>       {
> !     channel_set_json_mode(ch_idx, json_mode);
> !     channel_set_timeout(ch_idx, timeout);
>       if (callback != NULL && *callback != NUL)
> !         channel_set_callback(ch_idx, callback);
>       }
> +     rettv->vval.v_number = ch_idx;
>   }
>   
>   /*
> *** ../vim-7.4.1262/src/netbeans.c    2016-01-30 19:39:45.277838615 +0100
> --- src/netbeans.c    2016-02-05 21:33:03.745601600 +0100
> ***************
> *** 213,219 ****
>       if (hostname != NULL && address != NULL && password != NULL)
>       {
>       port = atoi(address);
> !     nb_channel_idx = channel_open(hostname, port, nb_channel_closed);
>       if (nb_channel_idx >= 0)
>       {
>           /* success */
> --- 213,219 ----
>       if (hostname != NULL && address != NULL && password != NULL)
>       {
>       port = atoi(address);
> !     nb_channel_idx = channel_open(hostname, port, 0, nb_channel_closed);
>       if (nb_channel_idx >= 0)
>       {
>           /* success */
> *** ../vim-7.4.1262/src/os_win32.c    2016-02-01 21:32:51.622375175 +0100
> --- src/os_win32.c    2016-02-05 22:06:02.832675296 +0100
> ***************
> *** 1123,1128 ****
> --- 1123,1151 ----
>       SetConsoleMode(g_hConIn, cmodein);
>   }
>   
> + #ifdef FEAT_CHANNEL
> +     static int
> + handle_channel_event(void)
> + {
> +     int                 ret;
> +     fd_set      rfds;
> +     int                 maxfd;
> + 
> +     FD_ZERO(&rfds);
> +     maxfd = channel_select_setup(-1, &rfds);
> +     if (maxfd >= 0)
> +     {
> +     struct timeval  tv;
> + 
> +     tv.tv_sec = 0;
> +     tv.tv_usec = 0;
> +     ret = select(maxfd + 1, &rfds, NULL, NULL, &tv);
> +     if (ret > 0 && channel_select_check(ret, &rfds) > 0)
> +         return TRUE;
> +     }
> +     return FALSE;
> + }
> + #endif
>   
>   /*
>    * Decode a MOUSE_EVENT.  If it's a valid event, return MOUSE_LEFT,
> ***************
> *** 1443,1453 ****
>       INPUT_RECORD    ir;
>       DWORD       cRecords;
>       WCHAR       ch, ch2;
> - #ifdef FEAT_CHANNEL
> -     int                 ret;
> -     fd_set      rfds;
> -     int                 maxfd;
> - #endif
>   
>       if (msec > 0)
>       /* Wait until the specified time has elapsed. */
> --- 1466,1471 ----
> ***************
> *** 1472,1489 ****
>   #endif
>   
>   #ifdef FEAT_CHANNEL
> !     FD_ZERO(&rfds);
> !     maxfd = channel_select_setup(-1, &rfds);
> !     if (maxfd >= 0)
> !     {
> !         struct timeval  tv;
> ! 
> !         tv.tv_sec = 0;
> !         tv.tv_usec = 0;
> !         ret = select(maxfd + 1, &rfds, NULL, NULL, &tv);
> !         if (ret > 0 && channel_select_check(ret, &rfds) > 0)
> !             return TRUE;
> !     }
>   #endif
>   
>       if (0
> --- 1490,1497 ----
>   #endif
>   
>   #ifdef FEAT_CHANNEL
> !     if (handle_channel_event())
> !         return TRUE;
>   #endif
>   
>       if (0
> *** ../vim-7.4.1262/src/proto/channel.pro     2016-02-05 21:04:02.820081559 
> +0100
> --- src/proto/channel.pro     2016-02-05 22:06:28.492404449 +0100
> ***************
> *** 1,7 ****
>   /* channel.c */
>   void channel_gui_register_all(void);
> ! int channel_open(char *hostname, int port_in, void (*close_cb)(void));
>   void channel_set_json_mode(int idx, int json_mode);
>   void channel_set_callback(int idx, char_u *callback);
>   void channel_set_req_callback(int idx, char_u *callback, int id);
>   char_u *channel_get(int idx);
> --- 1,8 ----
>   /* channel.c */
>   void channel_gui_register_all(void);
> ! int channel_open(char *hostname, int port_in, int waittime, void 
> (*close_cb)(void));
>   void channel_set_json_mode(int idx, int json_mode);
> + void channel_set_timeout(int idx, int timeout);
>   void channel_set_callback(int idx, char_u *callback);
>   void channel_set_req_callback(int idx, char_u *callback, int id);
>   char_u *channel_get(int idx);
> *** ../vim-7.4.1262/src/testdir/test_channel.vim      2016-02-05 
> 21:04:02.820081559 +0100
> --- src/testdir/test_channel.vim      2016-02-05 22:14:30.227322354 +0100
> ***************
> *** 57,63 ****
>     endif
>     let s:port = l[0]
>   
> !   let handle = ch_open('localhost:' . s:port, 'json')
>     return handle
>   endfunc
>   
> --- 57,63 ----
>     endif
>     let s:port = l[0]
>   
> !   let handle = ch_open('localhost:' . s:port)
>     return handle
>   endfunc
>   
> ***************
> *** 128,134 ****
>     endif
>     call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>   
> !   let newhandle = ch_open('localhost:' . s:port, 'json')
>     call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
>     call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>   
> --- 128,134 ----
>     endif
>     call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>   
> !   let newhandle = ch_open('localhost:' . s:port)
>     call assert_equal('got it', ch_sendexpr(newhandle, 'hello!'))
>     call assert_equal('got it', ch_sendexpr(handle, 'hello!'))
>   
> *** ../vim-7.4.1262/src/version.c     2016-02-05 21:04:02.820081559 +0100
> --- src/version.c     2016-02-05 21:34:01.308992175 +0100
> ***************
> *** 744,745 ****
> --- 744,747 ----
>   {   /* Add new patch number below this line */
> + /**/
> +     1263,
>   /**/
> 
> -- 
> hundred-and-one symptoms of being an internet addict:
> 145. You e-mail your boss, informing him you'll be late.
> 
>  /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
> ///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
> \\\  an exciting new programming language -- http://www.Zimbu.org        ///
>  \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

I got error when I built gvim.exe:
channel.c: In function ‘channel_open’:
channel.c:424:39: error: ‘EINPROGRESS’ undeclared (first use in this function)
channel.c:424:39: note: each undeclared identifier is reported only once for 
each function it appears in
Make_cyg_ming.mak:890: recipe for target 'gobji386/channel.o' failed
make: *** [gobji386/channel.o] Error 1


The command I'm using the following command as the command:
  make -B -f Make_cyg.mak PYTHON=/cygdrive/c/Marslo/MyProgramFiles/Python27 
DYNAMIC_PYTHON=yes PYTHON_VER=27 
PYTHON3=/cygdrive/c/Marslo/MyProgramFiles/Python35 DYNAMIC_PYTHON3=yes 
PYTHON3_VER=35 FEATURES=huge IME=yes GIME=yes MBYTE=yes CSCOPE=yes 
USERNAME=Marslo.Jiao USERDOMAIN=China GUI=yes 

Is there anything I should install in my cygwin?
Thanks in advance.

- marslo

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui