]> granicus.if.org Git - vim/commitdiff
patch 8.0.1170: using termdebug results in 100% CPU time v8.0.1170
authorBram Moolenaar <Bram@vim.org>
Sun, 1 Oct 2017 14:21:31 +0000 (16:21 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 1 Oct 2017 14:21:31 +0000 (16:21 +0200)
Problem:    Using termdebug results in 100% CPU time. (tomleb)
Solution:   Use polling instead of select().

src/channel.c
src/os_unix.c
src/proto/channel.pro
src/version.c

index 49bab16d116a7135c67bb53f6f90efdcde3585e0..606c66a869de4fb6c5105c60fd405b400a0ab363 100644 (file)
@@ -3960,6 +3960,8 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
     free_job_options(&opt);
 }
 
+# define KEEP_OPEN_TIME 20  /* msec */
+
 # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
 /*
  * Add open channels to the poll struct.
@@ -3967,7 +3969,7 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
  * The type of "fds" is hidden to avoid problems with the function proto.
  */
     int
-channel_poll_setup(int nfd_in, void *fds_in)
+channel_poll_setup(int nfd_in, void *fds_in, int *towait)
 {
     int                nfd = nfd_in;
     channel_T  *channel;
@@ -3982,10 +3984,21 @@ channel_poll_setup(int nfd_in, void *fds_in)
 
            if (ch_part->ch_fd != INVALID_FD)
            {
-               ch_part->ch_poll_idx = nfd;
-               fds[nfd].fd = ch_part->ch_fd;
-               fds[nfd].events = POLLIN;
-               nfd++;
+               if (channel->ch_keep_open)
+               {
+                   /* For unknown reason poll() returns immediately for a
+                    * keep-open channel.  Instead of adding it to the fds add
+                    * a short timeout and check, like polling. */
+                   if (*towait < 0 || *towait > KEEP_OPEN_TIME)
+                       *towait = KEEP_OPEN_TIME;
+               }
+               else
+               {
+                   ch_part->ch_poll_idx = nfd;
+                   fds[nfd].fd = ch_part->ch_fd;
+                   fds[nfd].events = POLLIN;
+                   nfd++;
+               }
            }
            else
                channel->ch_part[part].ch_poll_idx = -1;
@@ -4021,6 +4034,12 @@ channel_poll_check(int ret_in, void *fds_in)
                channel_read(channel, part, "channel_poll_check");
                --ret;
            }
+           else if (channel->ch_part[part].ch_fd != INVALID_FD
+                                                     && channel->ch_keep_open)
+           {
+               /* polling a keep-open channel */
+               channel_read(channel, part, "channel_poll_check_keep_open");
+           }
        }
 
        in_part = &channel->ch_part[PART_IN];
@@ -4037,11 +4056,17 @@ channel_poll_check(int ret_in, void *fds_in)
 # endif /* UNIX && !HAVE_SELECT */
 
 # if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO)
+
 /*
  * The "fd_set" type is hidden to avoid problems with the function proto.
  */
     int
-channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in)
+channel_select_setup(
+       int maxfd_in,
+       void *rfds_in,
+       void *wfds_in,
+       struct timeval *tv,
+       struct timeval **tvp)
 {
     int                maxfd = maxfd_in;
     channel_T  *channel;
@@ -4057,9 +4082,25 @@ channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in)
 
            if (fd != INVALID_FD)
            {
-               FD_SET((int)fd, rfds);
-               if (maxfd < (int)fd)
-                   maxfd = (int)fd;
+               if (channel->ch_keep_open)
+               {
+                   /* For unknown reason select() returns immediately for a
+                    * keep-open channel.  Instead of adding it to the rfds add
+                    * a short timeout and check, like polling. */
+                   if (*tvp == NULL || tv->tv_sec > 0
+                                       || tv->tv_usec > KEEP_OPEN_TIME * 1000)
+                   {
+                       *tvp = tv;
+                       tv->tv_sec = 0;
+                       tv->tv_usec = KEEP_OPEN_TIME * 1000;
+                   }
+               }
+               else
+               {
+                   FD_SET((int)fd, rfds);
+                   if (maxfd < (int)fd)
+                       maxfd = (int)fd;
+               }
            }
        }
     }
@@ -4094,6 +4135,11 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
                FD_CLR(fd, rfds);
                --ret;
            }
+           else if (fd != INVALID_FD && channel->ch_keep_open)
+           {
+               /* polling a keep-open channel */
+               channel_read(channel, part, "channel_select_check_keep_open");
+           }
        }
 
        in_part = &channel->ch_part[PART_IN];
index 3366efd1da8bc85f78e33d5585455315beb24492..2a8e6ee43b41727d92815672bfc5ae96b2404917 100644 (file)
@@ -5330,6 +5330,9 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
            channel = add_channel();
        if (channel == NULL)
            goto failed;
+       if (job->jv_tty_out != NULL)
+           ch_log(channel, "using pty %s on fd %d",
+                                              job->jv_tty_out, pty_master_fd);
     }
 
     BLOCK_SIGNALS(&curset);
@@ -5702,6 +5705,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options)
        close(pty_master_fd);
        return FAIL;
     }
+    if (job->jv_tty_out != NULL)
+       ch_log(channel, "using pty %s on fd %d",
+                                              job->jv_tty_out, pty_master_fd);
     job->jv_channel = channel;  /* ch_refcount was set by add_channel() */
     channel->ch_keep_open = TRUE;
 
@@ -5969,7 +5975,7 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
        }
 # endif
 #ifdef FEAT_JOB_CHANNEL
-       nfd = channel_poll_setup(nfd, &fds);
+       nfd = channel_poll_setup(nfd, &fds, &towait);
 #endif
        if (interrupted != NULL)
            *interrupted = FALSE;
@@ -6021,7 +6027,8 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
        }
 # endif
 #ifdef FEAT_JOB_CHANNEL
-       if (ret > 0)
+       /* also call when ret == 0, we may be polling a keep-open channel */
+       if (ret >= 0)
            ret = channel_poll_check(ret, &fds);
 #endif
 
@@ -6097,7 +6104,7 @@ select_eintr:
        }
 # endif
 # ifdef FEAT_JOB_CHANNEL
-       maxfd = channel_select_setup(maxfd, &rfds, &wfds);
+       maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
 # endif
        if (interrupted != NULL)
            *interrupted = FALSE;
@@ -6183,7 +6190,8 @@ select_eintr:
        }
 # endif
 #ifdef FEAT_JOB_CHANNEL
-       if (ret > 0)
+       /* also call when ret == 0, we may be polling a keep-open channel */
+       if (ret >= 0)
            ret = channel_select_check(ret, &rfds, &wfds);
 #endif
 
index a3a4dc701238923afd3778c56fdebb99e02bfeab..40742adad380949ed3f1aadfec378a304175b963 100644 (file)
@@ -40,9 +40,9 @@ void channel_set_nonblock(channel_T *channel, ch_part_T part);
 int channel_send(channel_T *channel, ch_part_T part, char_u *buf_arg, int len_arg, char *fun);
 void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval);
 void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval);
-int channel_poll_setup(int nfd_in, void *fds_in);
+int channel_poll_setup(int nfd_in, void *fds_in, int *towait);
 int channel_poll_check(int ret_in, void *fds_in);
-int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in);
+int channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in, struct timeval *tv, struct timeval **tvp);
 int channel_select_check(int ret_in, void *rfds_in, void *wfds_in);
 int channel_parse_messages(void);
 int channel_any_readahead(void);
index 23859a11764d98f7d55b1c4a5fe58bb3a62c69b6..d809ba978031a86a5367733d4259643993a32925 100644 (file)
@@ -761,6 +761,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1170,
 /**/
     1169,
 /**/