Skip to content

Commit

Permalink
patch 8.0.1170: using termdebug results in 100% CPU time
Browse files Browse the repository at this point in the history
Problem:    Using termdebug results in 100% CPU time. (tomleb)
Solution:   Use polling instead of select().
  • Loading branch information
brammool committed Oct 1, 2017
1 parent 5ece3e3 commit f336061
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 15 deletions.
64 changes: 55 additions & 9 deletions src/channel.c
Expand Up @@ -3960,14 +3960,16 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval)
free_job_options(&opt); free_job_options(&opt);
} }


# define KEEP_OPEN_TIME 20 /* msec */

# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
/* /*
* Add open channels to the poll struct. * Add open channels to the poll struct.
* Return the adjusted struct index. * Return the adjusted struct index.
* The type of "fds" is hidden to avoid problems with the function proto. * The type of "fds" is hidden to avoid problems with the function proto.
*/ */
int 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; int nfd = nfd_in;
channel_T *channel; channel_T *channel;
Expand All @@ -3982,10 +3984,21 @@ channel_poll_setup(int nfd_in, void *fds_in)


if (ch_part->ch_fd != INVALID_FD) if (ch_part->ch_fd != INVALID_FD)
{ {
ch_part->ch_poll_idx = nfd; if (channel->ch_keep_open)
fds[nfd].fd = ch_part->ch_fd; {
fds[nfd].events = POLLIN; /* For unknown reason poll() returns immediately for a
nfd++; * 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 else
channel->ch_part[part].ch_poll_idx = -1; channel->ch_part[part].ch_poll_idx = -1;
Expand Down Expand Up @@ -4021,6 +4034,12 @@ channel_poll_check(int ret_in, void *fds_in)
channel_read(channel, part, "channel_poll_check"); channel_read(channel, part, "channel_poll_check");
--ret; --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]; in_part = &channel->ch_part[PART_IN];
Expand All @@ -4037,11 +4056,17 @@ channel_poll_check(int ret_in, void *fds_in)
# endif /* UNIX && !HAVE_SELECT */ # endif /* UNIX && !HAVE_SELECT */


# if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO) # if (!defined(WIN32) && defined(HAVE_SELECT)) || defined(PROTO)

/* /*
* The "fd_set" type is hidden to avoid problems with the function proto. * The "fd_set" type is hidden to avoid problems with the function proto.
*/ */
int 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; int maxfd = maxfd_in;
channel_T *channel; channel_T *channel;
Expand All @@ -4057,9 +4082,25 @@ channel_select_setup(int maxfd_in, void *rfds_in, void *wfds_in)


if (fd != INVALID_FD) if (fd != INVALID_FD)
{ {
FD_SET((int)fd, rfds); if (channel->ch_keep_open)
if (maxfd < (int)fd) {
maxfd = (int)fd; /* 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;
}
} }
} }
} }
Expand Down Expand Up @@ -4094,6 +4135,11 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
FD_CLR(fd, rfds); FD_CLR(fd, rfds);
--ret; --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]; in_part = &channel->ch_part[PART_IN];
Expand Down
16 changes: 12 additions & 4 deletions src/os_unix.c
Expand Up @@ -5330,6 +5330,9 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
channel = add_channel(); channel = add_channel();
if (channel == NULL) if (channel == NULL)
goto failed; 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); BLOCK_SIGNALS(&curset);
Expand Down Expand Up @@ -5702,6 +5705,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options)
close(pty_master_fd); close(pty_master_fd);
return FAIL; 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() */ job->jv_channel = channel; /* ch_refcount was set by add_channel() */
channel->ch_keep_open = TRUE; channel->ch_keep_open = TRUE;


Expand Down Expand Up @@ -5969,7 +5975,7 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
} }
# endif # endif
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
nfd = channel_poll_setup(nfd, &fds); nfd = channel_poll_setup(nfd, &fds, &towait);
#endif #endif
if (interrupted != NULL) if (interrupted != NULL)
*interrupted = FALSE; *interrupted = FALSE;
Expand Down Expand Up @@ -6021,7 +6027,8 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
} }
# endif # endif
#ifdef FEAT_JOB_CHANNEL #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); ret = channel_poll_check(ret, &fds);
#endif #endif


Expand Down Expand Up @@ -6097,7 +6104,7 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
} }
# endif # endif
# ifdef FEAT_JOB_CHANNEL # ifdef FEAT_JOB_CHANNEL
maxfd = channel_select_setup(maxfd, &rfds, &wfds); maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
# endif # endif
if (interrupted != NULL) if (interrupted != NULL)
*interrupted = FALSE; *interrupted = FALSE;
Expand Down Expand Up @@ -6183,7 +6190,8 @@ RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
} }
# endif # endif
#ifdef FEAT_JOB_CHANNEL #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); ret = channel_select_check(ret, &rfds, &wfds);
#endif #endif


Expand Down
4 changes: 2 additions & 2 deletions src/proto/channel.pro
Expand Up @@ -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); 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_expr_common(typval_T *argvars, typval_T *rettv, int eval);
void ch_raw_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_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_select_check(int ret_in, void *rfds_in, void *wfds_in);
int channel_parse_messages(void); int channel_parse_messages(void);
int channel_any_readahead(void); int channel_any_readahead(void);
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -761,6 +761,8 @@ static char *(features[]) =


static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1170,
/**/ /**/
1169, 1169,
/**/ /**/
Expand Down

0 comments on commit f336061

Please sign in to comment.