Patch 7.4.1351
Problem:    When the port isn't opened yet when ch_open() is called it may
            fail instead of waiting for the specified time.
Solution:   Loop when select() succeeds but when connect() failed. Also use
            channel logging for jobs.  Add ch_log().
Files:      src/channel.c, src/eval.c, src/netbeans.c, src/proto/channel.pro,
            src/testdir/test_channel.vim, src/testdir/test_channel.py


*** ../vim-7.4.1350/src/channel.c       2016-02-16 22:01:23.822490218 +0100
--- src/channel.c       2016-02-18 22:14:01.995469291 +0100
***************
*** 90,95 ****
--- 90,98 ----
  
  /* Log file opened with ch_logfile(). */
  static FILE *log_fd = NULL;
+ #ifdef FEAT_RELTIME
+ static proftime_T log_start;
+ #endif
  
      void
  ch_logfile(FILE *file)
***************
*** 98,104 ****
--- 101,118 ----
        fclose(log_fd);
      log_fd = file;
      if (log_fd != NULL)
+     {
        fprintf(log_fd, "==== start log session ====\n");
+ #ifdef FEAT_RELTIME
+       profile_start(&log_start);
+ #endif
+     }
+ }
+ 
+     int
+ ch_log_active()
+ {
+     return log_fd != NULL;
  }
  
      static void
***************
*** 106,111 ****
--- 120,132 ----
  {
      if (log_fd != NULL)
      {
+ #ifdef FEAT_RELTIME
+       proftime_T log_now;
+ 
+       profile_start(&log_now);
+       profile_sub(&log_now, &log_start);
+       fprintf(log_fd, "%s ", profile_msg(&log_now));
+ #endif
        if (ch != NULL)
            fprintf(log_fd, "%son %d: ", what, ch->ch_id);
        else
***************
*** 113,125 ****
      }
  }
  
!     static void
  ch_log(channel_T *ch, char *msg)
  {
      if (log_fd != NULL)
      {
        ch_log_lead("", ch);
        fputs(msg, log_fd);
        fflush(log_fd);
      }
  }
--- 134,147 ----
      }
  }
  
!     void
  ch_log(channel_T *ch, char *msg)
  {
      if (log_fd != NULL)
      {
        ch_log_lead("", ch);
        fputs(msg, log_fd);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 131,147 ****
      {
        ch_log_lead("", ch);
        fprintf(log_fd, msg, nr);
        fflush(log_fd);
      }
  }
  
!     static void
  ch_logs(channel_T *ch, char *msg, char *name)
  {
      if (log_fd != NULL)
      {
        ch_log_lead("", ch);
        fprintf(log_fd, msg, name);
        fflush(log_fd);
      }
  }
--- 153,171 ----
      {
        ch_log_lead("", ch);
        fprintf(log_fd, msg, nr);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
  
!     void
  ch_logs(channel_T *ch, char *msg, char *name)
  {
      if (log_fd != NULL)
      {
        ch_log_lead("", ch);
        fprintf(log_fd, msg, name);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 153,158 ****
--- 177,183 ----
      {
        ch_log_lead("", ch);
        fprintf(log_fd, msg, name, nr);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 164,169 ****
--- 189,195 ----
      {
        ch_log_lead("ERR ", ch);
        fputs(msg, log_fd);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 175,180 ****
--- 201,207 ----
      {
        ch_log_lead("ERR ", ch);
        fprintf(log_fd, msg, nr);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 186,191 ****
--- 213,219 ----
      {
        ch_log_lead("ERR ", ch);
        fprintf(log_fd, msg, arg);
+       fputc('\n', log_fd);
        fflush(log_fd);
      }
  }
***************
*** 253,259 ****
        return NULL;
  
      channel->ch_id = next_ch_id++;
!     ch_log(channel, "Created channel\n");
  
  #ifdef CHANNEL_PIPES
      for (which = CHAN_SOCK; which <= CHAN_IN; ++which)
--- 281,287 ----
        return NULL;
  
      channel->ch_id = next_ch_id++;
!     ch_log(channel, "Created channel");
  
  #ifdef CHANNEL_PIPES
      for (which = CHAN_SOCK; which <= CHAN_IN; ++which)
***************
*** 470,483 ****
      channel_T *
  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
      channel_T         *channel;
      int                       ret;
--- 498,514 ----
      channel_T *
  channel_open(char *hostname, int port_in, int waittime, void 
(*close_cb)(void))
  {
!     int                       sd = -1;
      struct sockaddr_in        server;
!     struct hostent    *host;
  #ifdef WIN32
      u_short           port = port_in;
      u_long            val = 1;
  #else
      int                       port = port_in;
+     struct timeval    start_tv;
+     int                       so_error;
+     socklen_t         so_error_len = sizeof(so_error);
  #endif
      channel_T         *channel;
      int                       ret;
***************
*** 489,504 ****
      channel = add_channel();
      if (channel == NULL)
      {
!       ch_error(NULL, "Cannot allocate channel.\n");
!       EMSG(_("E897: All channels are in use"));
!       return NULL;
!     }
! 
!     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
!     {
!       ch_error(channel, "in socket() in channel_open().\n");
!       PERROR("E898: socket() in channel_open()");
!       channel_free(channel);
        return NULL;
      }
  
--- 520,526 ----
      channel = add_channel();
      if (channel == NULL)
      {
!       ch_error(NULL, "Cannot allocate channel.");
        return NULL;
      }
  
***************
*** 509,623 ****
      server.sin_port = htons(port);
      if ((host = gethostbyname(hostname)) == NULL)
      {
!       ch_error(channel, "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);
  
!     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;
!           ch_errorn(channel, "channel_open: Connect failed with errno %d\n",
!                                                                      errno);
            sock_close(sd);
            channel_free(channel);
            return NULL;
        }
-     }
  
!     /* Try connecting to the server. */
!     ch_logsn(channel, "Connecting to %s port %d\n", hostname, port);
!     ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
!     SOCK_ERRNO;
!     if (ret < 0)
!     {
!       if (errno != EWOULDBLOCK
  #ifdef EINPROGRESS
                    && errno != EINPROGRESS
  #endif
!               )
!       {
!           ch_errorn(channel, "channel_open: Connect failed with errno %d\n",
!                                                                      errno);
!           PERROR(_(e_cannot_connect));
!           sock_close(sd);
!           channel_free(channel);
!           return NULL;
        }
-     }
  
!     if (waittime >= 0 && ret < 0)
!     {
!       struct timeval  tv;
!       fd_set          wfds;
  #if defined(__APPLE__) && __APPLE__ == 1
  # define PASS_RFDS
!       fd_set          rfds;
  
!       FD_ZERO(&rfds);
!       FD_SET(sd, &rfds);
!       /* On Mac a zero timeout almost never works.  At least wait one
!        * millisecond. */
!       if (waittime == 0)
!           waittime = 1;
! #endif
!       FD_ZERO(&wfds);
!       FD_SET(sd, &wfds);
!       tv.tv_sec = waittime / 1000;
!       tv.tv_usec = (waittime % 1000) * 1000;
! 
!       ch_logn(channel, "Waiting for connection (timeout %d msec)...\n",
!                                                                   waittime);
!       ret = select((int)sd + 1,
  #ifdef PASS_RFDS
!               &rfds,
  #else
!               NULL,
  #endif
!               &wfds, NULL, &tv);
  
!       if (ret < 0)
!       {
!           SOCK_ERRNO;
!           ch_errorn(channel, "channel_open: Connect failed with errno %d\n",
!                                                                      errno);
!           PERROR(_(e_cannot_connect));
!           sock_close(sd);
!           channel_free(channel);
!           return NULL;
!       }
  #ifdef PASS_RFDS
!       if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
!       {
!           /* For OS X, this implies error. See tcp(4). */
!           ch_error(channel, "channel_open: Connect failed\n");
!           EMSG(_(e_cannot_connect));
!           sock_close(sd);
!           channel_free(channel);
!           return NULL;
!       }
  #endif
!       if (!FD_ISSET(sd, &wfds))
!       {
!           /* don't give an error, we just timed out. */
!           ch_error(channel, "Connection timed out\n");
!           sock_close(sd);
!           channel_free(channel);
!           return NULL;
        }
-       ch_log(channel, "Connection made\n");
      }
  
      if (waittime >= 0)
--- 531,715 ----
      server.sin_port = htons(port);
      if ((host = gethostbyname(hostname)) == NULL)
      {
!       ch_error(channel, "in gethostbyname() in channel_open()");
        PERROR("E901: gethostbyname() in channel_open()");
        channel_free(channel);
        return NULL;
      }
      memcpy((char *)&server.sin_addr, host->h_addr, host->h_length);
  
! #if defined(__APPLE__) && __APPLE__ == 1
!     /* On Mac a zero timeout almost never works.  At least wait one
!      * millisecond. */
!     if (waittime == 0)
!       waittime = 1;
  #endif
! 
!     /*
!      * For Unix we need to call connect() again after connect() failed.
!      * On Win32 one time is sufficient.
!      */
!     while (TRUE)
!     {
!       if (sd >= 0)
            sock_close(sd);
+       sd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sd == -1)
+       {
+           ch_error(channel, "in socket() in channel_open().");
+           PERROR("E898: socket() in channel_open()");
            channel_free(channel);
            return NULL;
        }
  
!       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;
!               ch_errorn(channel,
!                        "channel_open: Connect failed with errno %d", errno);
!               sock_close(sd);
!               channel_free(channel);
!               return NULL;
!           }
!       }
! 
!       /* Try connecting to the server. */
!       ch_logsn(channel, "Connecting to %s port %d", hostname, port);
!       ret = connect(sd, (struct sockaddr *)&server, sizeof(server));
! 
!       SOCK_ERRNO;
!       if (ret < 0)
!       {
!           if (errno != EWOULDBLOCK
!                   && errno != ECONNREFUSED
! 
  #ifdef EINPROGRESS
                    && errno != EINPROGRESS
  #endif
!                   )
!           {
!               ch_errorn(channel,
!                       "channel_open: Connect failed with errno %d", errno);
!               PERROR(_(e_cannot_connect));
!               sock_close(sd);
!               channel_free(channel);
!               return NULL;
!           }
        }
  
!       /* If we don't block and connect() failed then try using select() to
!        * wait for the connection to be made. */
!       if (waittime >= 0 && ret < 0)
!       {
!           struct timeval      tv;
!           fd_set              wfds;
  #if defined(__APPLE__) && __APPLE__ == 1
  # define PASS_RFDS
!           fd_set          rfds;
  
!           FD_ZERO(&rfds);
!           FD_SET(sd, &rfds);
! #endif
!           FD_ZERO(&wfds);
!           FD_SET(sd, &wfds);
! 
!           tv.tv_sec = waittime / 1000;
!           tv.tv_usec = (waittime % 1000) * 1000;
! #ifndef WIN32
!           gettimeofday(&start_tv, NULL);
! #endif
!           ch_logn(channel,
!                   "Waiting for connection (waittime %d msec)...", waittime);
!           ret = select((int)sd + 1,
  #ifdef PASS_RFDS
!                   &rfds,
  #else
!                   NULL,
  #endif
!                   &wfds, NULL, &tv);
  
!           if (ret < 0)
!           {
!               SOCK_ERRNO;
!               ch_errorn(channel,
!                       "channel_open: Connect failed with errno %d", errno);
!               PERROR(_(e_cannot_connect));
!               sock_close(sd);
!               channel_free(channel);
!               return NULL;
!           }
  #ifdef PASS_RFDS
!           if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
!           {
!               /* For OS X, this implies error. See tcp(4). */
!               ch_error(channel, "channel_open: Connect failed");
!               EMSG(_(e_cannot_connect));
!               sock_close(sd);
!               channel_free(channel);
!               return NULL;
!           }
  #endif
! #ifdef WIN32
!           /* On Win32 select() is expected to work and wait for up to the
!            * waittime for the socket to be open. */
!           if (!FD_ISSET(sd, &wfds) || ret == 0)
! #else
!           /* See socket(7) for the behavior on Linux-like systems:
!            * After putting the socket in non-blocking mode, connect() will
!            * return EINPROGRESS, select() will not wait (as if writing is
!            * possible), need to use getsockopt() to check if the socket is
!            * actually open. */
!           getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
!           if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0)
! #endif
!           {
! #ifndef WIN32
!               struct  timeval end_tv;
!               long    elapsed_msec;
! 
!               gettimeofday(&end_tv, NULL);
!               elapsed_msec = (end_tv.tv_sec - start_tv.tv_sec) * 1000
!                                + (end_tv.tv_usec - start_tv.tv_usec) / 1000;
!               if (waittime > 1 && elapsed_msec < waittime)
!               {
!                   /* The port isn't ready but we also didn't get an error.
!                    * This happens when the server didn't open the socket
!                    * yet.  Wait a bit and try again. */
!                   mch_delay(waittime < 50 ? (long)waittime : 50L, TRUE);
!                   ui_breakcheck();
!                   if (!got_int)
!                   {
!                       /* reduce the waittime by the elapsed time and the 50
!                        * msec delay (or a bit more) */
!                       waittime -= elapsed_msec;
!                       if (waittime > 50)
!                           waittime -= 50;
!                       else
!                           waittime = 1;
!                       continue;
!                   }
!                   /* we were interrupted, behave as if timed out */
!               }
! #endif
!               /* We timed out. */
!               ch_error(channel, "Connection timed out");
!               sock_close(sd);
!               channel_free(channel);
!               return NULL;
!           }
! 
!           ch_log(channel, "Connection made");
!           break;
        }
      }
  
      if (waittime >= 0)
***************
*** 630,684 ****
  #endif
      }
  
-     /* Only retry for netbeans.  TODO: can we use a waittime instead? */
-     if (errno == ECONNREFUSED && close_cb != NULL)
-     {
-       sock_close(sd);
-       if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
-       {
-           SOCK_ERRNO;
-           ch_log(channel, "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)))
-       {
-           int retries = 36;
-           int success = FALSE;
- 
-           SOCK_ERRNO;
-           while (retries-- && ((errno == ECONNREFUSED)
-                                                    || (errno == EINTR)))
-           {
-               ch_log(channel, "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. */
-               ch_error(channel, "Cannot connect to port after retry\n");
-               PERROR(_("E899: Cannot connect to port after retry"));
-               sock_close(sd);
-               channel_free(channel);
-               return NULL;
-           }
-       }
-     }
- 
      channel->CH_SOCK = (sock_T)sd;
      channel->ch_close_cb = close_cb;
  
--- 722,727 ----
***************
*** 1155,1161 ****
        if (typetv->v_type != VAR_NUMBER)
        {
            ch_error(channel,
!                     "Dropping message with invalid sequence number type\n");
            free_tv(listtv);
            return FALSE;
        }
--- 1198,1204 ----
        if (typetv->v_type != VAR_NUMBER)
        {
            ch_error(channel,
!                     "Dropping message with invalid sequence number type");
            free_tv(listtv);
            return FALSE;
        }
***************
*** 1223,1229 ****
        {
            if (item->cq_seq_nr == seq_nr)
            {
!               ch_log(channel, "Invoking one-time callback\n");
                /* Remove the item from the list first, if the callback
                 * invokes ch_close() the list will be cleared. */
                remove_cb_node(head, item);
--- 1266,1272 ----
        {
            if (item->cq_seq_nr == seq_nr)
            {
!               ch_log(channel, "Invoking one-time callback");
                /* Remove the item from the list first, if the callback
                 * invokes ch_close() the list will be cleared. */
                remove_cb_node(head, item);
***************
*** 1236,1251 ****
            item = item->cq_next;
        }
        if (!done)
!           ch_log(channel, "Dropping message without callback\n");
      }
      else if (channel->ch_callback != NULL)
      {
        /* invoke the channel callback */
!       ch_log(channel, "Invoking channel callback\n");
        invoke_callback(channel, channel->ch_callback, argv);
      }
      else
!       ch_log(channel, "Dropping message\n");
  
      if (listtv != NULL)
        free_tv(listtv);
--- 1279,1294 ----
            item = item->cq_next;
        }
        if (!done)
!           ch_log(channel, "Dropping message without callback");
      }
      else if (channel->ch_callback != NULL)
      {
        /* invoke the channel callback */
!       ch_log(channel, "Invoking channel callback");
        invoke_callback(channel, channel->ch_callback, argv);
      }
      else
!       ch_log(channel, "Dropping message");
  
      if (listtv != NULL)
        free_tv(listtv);
***************
*** 1304,1310 ****
      void
  channel_close(channel_T *channel)
  {
!     ch_log(channel, "Closing channel\n");
  
  #ifdef FEAT_GUI
      channel_gui_unregister(channel);
--- 1347,1353 ----
      void
  channel_close(channel_T *channel)
  {
!     ch_log(channel, "Closing channel");
  
  #ifdef FEAT_GUI
      channel_gui_unregister(channel);
***************
*** 1471,1477 ****
      int                       ret;
  
      if (timeout > 0)
!       ch_logn(channel, "Waiting for up to %d msec\n", timeout);
  
  
  # ifdef WIN32
--- 1514,1520 ----
      int                       ret;
  
      if (timeout > 0)
!       ch_logn(channel, "Waiting for up to %d msec", timeout);
  
  
  # ifdef WIN32
***************
*** 1511,1517 ****
  # endif
        if (ret <= 0)
        {
!           ch_log(channel, "Nothing to read\n");
            return FAIL;
        }
        break;
--- 1554,1560 ----
  # endif
        if (ret <= 0)
        {
!           ch_log(channel, "Nothing to read");
            return FAIL;
        }
        break;
***************
*** 1521,1532 ****
      struct pollfd     fds;
  
      if (timeout > 0)
!       ch_logn(channel, "Waiting for %d msec\n", timeout);
      fds.fd = fd;
      fds.events = POLLIN;
      if (poll(&fds, 1, timeout) <= 0)
      {
!       ch_log(channel, "Nothing to read\n");
        return FAIL;
      }
  # endif
--- 1564,1575 ----
      struct pollfd     fds;
  
      if (timeout > 0)
!       ch_logn(channel, "Waiting for %d msec", timeout);
      fds.fd = fd;
      fds.events = POLLIN;
      if (poll(&fds, 1, timeout) <= 0)
      {
!       ch_log(channel, "Nothing to read");
        return FAIL;
      }
  # endif
***************
*** 1558,1564 ****
      if (channel->CH_OUT != CHAN_FD_INVALID)
        return channel->CH_OUT;
  #endif
!     ch_error(channel, "channel_read() called while socket is closed\n");
      return CHAN_FD_INVALID;
  }
  
--- 1601,1607 ----
      if (channel->CH_OUT != CHAN_FD_INVALID)
        return channel->CH_OUT;
  #endif
!     ch_error(channel, "channel_read() called while socket is closed");
      return CHAN_FD_INVALID;
  }
  
***************
*** 1637,1643 ****
         *                  -> gui event loop or select loop
         *                      -> channel_read()
         */
!       ch_errors(channel, "%s(): Cannot read\n", func);
        channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
  
        /* TODO: When reading from stdout is not possible, should we try to
--- 1680,1686 ----
         *                  -> gui event loop or select loop
         *                      -> channel_read()
         */
!       ch_errors(channel, "%s(): Cannot read", func);
        channel_save(channel, (char_u *)DETACH_MSG, (int)STRLEN(DETACH_MSG));
  
        /* TODO: When reading from stdout is not possible, should we try to
***************
*** 1649,1655 ****
  
        if (len < 0)
        {
!           ch_error(channel, "channel_read(): cannot read from channel\n");
            PERROR(_("E896: read from channel"));
        }
      }
--- 1692,1698 ----
  
        if (len < 0)
        {
!           ch_error(channel, "channel_read(): cannot read from channel");
            PERROR(_("E896: read from channel"));
        }
      }
***************
*** 1677,1683 ****
      sock_T    fd = get_read_fd(channel);
      char_u    *nl;
  
!     ch_logsn(channel, "Blocking %s read, timeout: %d msec\n",
                        mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout);
  
      while (TRUE)
--- 1720,1726 ----
      sock_T    fd = get_read_fd(channel);
      char_u    *nl;
  
!     ch_logsn(channel, "Blocking %s read, timeout: %d msec",
                        mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout);
  
      while (TRUE)
***************
*** 1718,1724 ****
        }
      }
      if (log_fd != NULL)
!       ch_logn(channel, "Returning %d bytes\n", (int)STRLEN(msg));
      return msg;
  }
  
--- 1761,1767 ----
        }
      }
      if (log_fd != NULL)
!       ch_logn(channel, "Returning %d bytes", (int)STRLEN(msg));
      return msg;
  }
  
***************
*** 1733,1739 ****
      int               more;
      sock_T    fd;
  
!     ch_log(channel, "Reading JSON\n");
      channel->ch_block_id = id;
      for (;;)
      {
--- 1776,1782 ----
      int               more;
      sock_T    fd;
  
!     ch_log(channel, "Reading JSON");
      channel->ch_block_id = id;
      for (;;)
      {
***************
*** 1821,1827 ****
      {
        if (!channel->ch_error && fun != NULL)
        {
!           ch_errors(channel, "%s(): write while not connected\n", fun);
            EMSG2("E630: %s(): write while not connected", fun);
        }
        channel->ch_error = TRUE;
--- 1864,1870 ----
      {
        if (!channel->ch_error && fun != NULL)
        {
!           ch_errors(channel, "%s(): write while not connected", fun);
            EMSG2("E630: %s(): write while not connected", fun);
        }
        channel->ch_error = TRUE;
***************
*** 1845,1851 ****
      {
        if (!channel->ch_error && fun != NULL)
        {
!           ch_errors(channel, "%s(): write failed\n", fun);
            EMSG2("E631: %s(): write failed", fun);
        }
        channel->ch_error = TRUE;
--- 1888,1894 ----
      {
        if (!channel->ch_error && fun != NULL)
        {
!           ch_errors(channel, "%s(): write failed", fun);
            EMSG2("E631: %s(): write failed", fun);
        }
        channel->ch_error = TRUE;
*** ../vim-7.4.1350/src/eval.c  2016-02-18 20:18:04.974654638 +0100
--- src/eval.c  2016-02-18 22:03:30.838031691 +0100
***************
*** 504,509 ****
--- 504,510 ----
  #endif
  #ifdef FEAT_CHANNEL
  static void f_ch_close(typval_T *argvars, typval_T *rettv);
+ static void f_ch_log(typval_T *argvars, typval_T *rettv);
  static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
  static void f_ch_open(typval_T *argvars, typval_T *rettv);
  static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
***************
*** 8124,8129 ****
--- 8125,8131 ----
  #endif
  #ifdef FEAT_CHANNEL
      {"ch_close",      1, 1, f_ch_close},
+     {"ch_log",                1, 2, f_ch_log},
      {"ch_logfile",    1, 2, f_ch_logfile},
      {"ch_open",               1, 2, f_ch_open},
      {"ch_readraw",    1, 2, f_ch_readraw},
***************
*** 9950,9955 ****
--- 9952,9972 ----
  }
  
  /*
+  * "ch_log()" function
+  */
+     static void
+ f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
+ {
+     char_u    *msg = get_tv_string(&argvars[0]);
+     channel_T *channel = NULL;
+ 
+     if (argvars[1].v_type != VAR_UNKNOWN)
+       channel = get_channel_arg(&argvars[1]);
+ 
+     ch_log(channel, (char *)msg);
+ }
+ 
+ /*
   * "ch_logfile()" function
   */
      static void
***************
*** 14603,14611 ****
--- 14620,14649 ----
        cmd = ga.ga_data;
  #endif
      }
+ 
  #ifdef USE_ARGV
+ # ifdef FEAT_CHANNEL
+     if (ch_log_active())
+     {
+       garray_T    ga;
+       int         i;
+ 
+       ga_init2(&ga, (int)sizeof(char), 200);
+       for (i = 0; i < argc; ++i)
+       {
+           if (i > 0)
+               ga_concat(&ga, (char_u *)"  ");
+           ga_concat(&ga, (char_u *)argv[i]);
+       }
+       ch_logs(NULL, "Starting job: %s", ga.ga_data);
+       ga_clear(&ga);
+     }
+ # endif
      mch_start_job(argv, job, &options);
  #else
+ # ifdef FEAT_CHANNEL
+     ch_logs(NULL, "Starting job: %s", cmd);
+ # endif
      mch_start_job((char *)cmd, job, &options);
  #endif
  
*** ../vim-7.4.1350/src/netbeans.c      2016-02-13 23:22:35.093363549 +0100
--- src/netbeans.c      2016-02-18 21:41:43.583567462 +0100
***************
*** 213,219 ****
      if (hostname != NULL && address != NULL && password != NULL)
      {
        port = atoi(address);
!       nb_channel = channel_open(hostname, port, 0, nb_channel_closed);
        if (nb_channel != NULL)
        {
            /* success */
--- 213,219 ----
      if (hostname != NULL && address != NULL && password != NULL)
      {
        port = atoi(address);
!       nb_channel = channel_open(hostname, port, 3000, nb_channel_closed);
        if (nb_channel != NULL)
        {
            /* success */
*** ../vim-7.4.1350/src/proto/channel.pro       2016-02-16 21:02:17.603873545 
+0100
--- src/proto/channel.pro       2016-02-18 21:51:40.593424945 +0100
***************
*** 1,5 ****
--- 1,8 ----
  /* channel.c */
  void ch_logfile(FILE *file);
+ int ch_log_active(void);
+ void ch_log(channel_T *ch, char *msg);
+ void ch_logs(channel_T *ch, char *msg, char *name);
  channel_T *add_channel(void);
  void channel_free(channel_T *channel);
  void channel_gui_register(channel_T *channel);
*** ../vim-7.4.1350/src/testdir/test_channel.vim        2016-02-16 
22:01:23.822490218 +0100
--- src/testdir/test_channel.vim        2016-02-18 22:05:24.856845698 +0100
***************
*** 31,47 ****
  let s:chopt = {}
  
  " Run "testfunc" after sarting the server and stop the server afterwards.
! func s:run_server(testfunc)
    " The Python program writes the port number in Xportnr.
    call delete("Xportnr")
  
    try
      if has('job')
!       let s:job = job_start(s:python . " test_channel.py")
      elseif has('win32')
!       exe 'silent !start cmd /c start "test_channel" ' . s:python . ' 
test_channel.py'
      else
!       exe 'silent !' . s:python . ' test_channel.py&'
      endif
  
      " Wait for up to 2 seconds for the port number to be there.
--- 31,54 ----
  let s:chopt = {}
  
  " Run "testfunc" after sarting the server and stop the server afterwards.
! func s:run_server(testfunc, ...)
    " The Python program writes the port number in Xportnr.
    call delete("Xportnr")
  
+   if a:0 == 1
+     let arg = ' ' . a:1
+   else
+     let arg = ''
+   endif
+   let cmd = s:python . " test_channel.py" . arg
+ 
    try
      if has('job')
!       let s:job = job_start(cmd)
      elseif has('win32')
!       exe 'silent !start cmd /c start "test_channel" ' . cmd
      else
!       exe 'silent !' . cmd . '&'
      endif
  
      " Wait for up to 2 seconds for the port number to be there.
***************
*** 175,180 ****
--- 182,188 ----
  endfunc
  
  func Test_communicate()
+   call ch_log('Test_communicate()')
    call s:run_server('s:communicate')
  endfunc
  
***************
*** 203,208 ****
--- 211,217 ----
  endfunc
  
  func Test_two_channels()
+   call ch_log('Test_two_channels()')
    call s:run_server('s:two_channels')
  endfunc
  
***************
*** 220,225 ****
--- 229,235 ----
  endfunc
  
  func Test_server_crash()
+   call ch_log('Test_server_crash()')
    call s:run_server('s:server_crash')
  endfunc
  
***************
*** 248,253 ****
--- 258,264 ----
  endfunc
  
  func Test_channel_handler()
+   call ch_log('Test_channel_handler()')
    let s:chopt.callback = 's:Handler'
    call s:run_server('s:channel_handler')
    let s:chopt.callback = function('s:Handler')
***************
*** 261,269 ****
      " TODO: Make this work again for MS-Windows.
      return
    endif
    let start = reltime()
    let handle = ch_open('localhost:9876', s:chopt)
!   if ch_status(handle) == "fail"
      " Oops, port does exists.
      call ch_close(handle)
    else
--- 272,281 ----
      " TODO: Make this work again for MS-Windows.
      return
    endif
+   call ch_log('Test_connect_waittime()')
    let start = reltime()
    let handle = ch_open('localhost:9876', s:chopt)
!   if ch_status(handle) != "fail"
      " Oops, port does exists.
      call ch_close(handle)
    else
***************
*** 272,278 ****
    endif
  
    let start = reltime()
!   let handle = ch_open('localhost:9867', {'waittime': 2000})
    if ch_status(handle) != "fail"
      " Oops, port does exists.
      call ch_close(handle)
--- 284,290 ----
    endif
  
    let start = reltime()
!   let handle = ch_open('localhost:9867', {'waittime': 500})
    if ch_status(handle) != "fail"
      " Oops, port does exists.
      call ch_close(handle)
***************
*** 280,286 ****
      " Failed connection doesn't wait the full time on Unix.
      " TODO: why is MS-Windows different?
      let elapsed = reltime(start)
!     call assert_true(reltimefloat(elapsed) < (has('unix') ? 1.0 : 3.0))
    endif
  endfunc
  
--- 292,298 ----
      " Failed connection doesn't wait the full time on Unix.
      " TODO: why is MS-Windows different?
      let elapsed = reltime(start)
!     call assert_true(reltimefloat(elapsed) < 1.0)
    endif
  endfunc
  
***************
*** 288,293 ****
--- 300,306 ----
    if !has('job')
      return
    endif
+   call ch_log('Test_raw_pipe()')
    let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'})
    call assert_equal("run", job_status(job))
    try
***************
*** 311,316 ****
--- 324,330 ----
    if !has('job')
      return
    endif
+   call ch_log('Test_nl_pipe()')
    let job = job_start(s:python . " test_channel_pipe.py")
    call assert_equal("run", job_status(job))
    try
***************
*** 346,351 ****
--- 360,366 ----
  endfunc
  
  func Test_unlet_handle()
+   call ch_log('Test_unlet_handle()')
    call s:run_server('s:unlet_handle')
  endfunc
  
***************
*** 366,378 ****
--- 381,416 ----
  endfunc
  
  func Test_close_handle()
+   call ch_log('Test_close_handle()')
    call s:run_server('s:close_handle')
  endfunc
  
  """"""""""
  
  func Test_open_fail()
+   call ch_log('Test_open_fail()')
    silent! let ch = ch_open("noserver")
    echo ch
    let d = ch
  endfunc
+ 
+ """"""""""
+ 
+ func s:open_delay(port)
+   " Wait up to a second for the port to open.
+   let s:chopt.waittime = 1000
+   let channel = ch_open('localhost:' . a:port, s:chopt)
+   unlet s:chopt.waittime
+   if ch_status(channel) == "fail"
+     call assert_false(1, "Can't open channel")
+     return
+   endif
+   call assert_equal('got it', ch_sendexpr(channel, 'hello!'))
+   call ch_close(channel)
+ endfunc
+ 
+ func Test_open_delay()
+   call ch_log('Test_open_delay()')
+   " The server will wait half a second before creating the port.
+   call s:run_server('s:open_delay', 'delay')
+ endfunc
*** ../vim-7.4.1350/src/testdir/test_channel.py 2016-02-13 23:28:17.637753771 
+0100
--- src/testdir/test_channel.py 2016-02-17 22:54:02.749262439 +0100
***************
*** 9,14 ****
--- 9,15 ----
  import json
  import socket
  import sys
+ import time
  import threading
  
  try:
***************
*** 158,166 ****
--- 159,183 ----
  class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
      pass
  
+ def writePortInFile(port):
+     # Write the port number in Xportnr, so that the test knows it.
+     f = open("Xportnr", "w")
+     f.write("{}".format(port))
+     f.close()
+ 
  if __name__ == "__main__":
      HOST, PORT = "localhost", 0
  
+     # Wait half a second before opening the port to test waittime in 
ch_open().
+     # We do want to get the port number, get that first.  We cannot open the
+     # socket, guess a port is free.
+     if len(sys.argv) >= 2 and sys.argv[1] == 'delay':
+         PORT = 13684
+         writePortInFile(PORT)
+ 
+         print("Wait for it...")
+         time.sleep(0.5)
+ 
      server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
      ip, port = server.server_address
  
***************
*** 169,178 ****
      server_thread = threading.Thread(target=server.serve_forever)
      server_thread.start()
  
!     # Write the port number in Xportnr, so that the test knows it.
!     f = open("Xportnr", "w")
!     f.write("{}".format(port))
!     f.close()
  
      print("Listening on port {}".format(port))
  
--- 186,192 ----
      server_thread = threading.Thread(target=server.serve_forever)
      server_thread.start()
  
!     writePortInFile(port)
  
      print("Listening on port {}".format(port))
  
*** ../vim-7.4.1350/src/version.c       2016-02-18 22:17:36.105244535 +0100
--- src/version.c       2016-02-18 22:20:29.131447154 +0100
***************
*** 749,750 ****
--- 749,752 ----
  {   /* Add new patch number below this line */
+ /**/
+     1351,
  /**/

-- 
"Never be afraid to tell the world who you are."
                                        -- Anonymous

 /// 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    ///

-- 
-- 
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