mirror of
https://github.com/tmux/tmux.git
synced 2026-07-14 13:10:39 +00:00
Do not make pty fds blocking again until all the data has been consumed
or control mode clients can get stuck, GitHub issue 5356 from Ben Maurer.
This commit is contained in:
27
client.c
27
client.c
@@ -240,9 +240,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
pid_t ppid;
|
||||
enum msgtype msg;
|
||||
struct termios tio, saved_tio;
|
||||
size_t size, linesize = 0;
|
||||
ssize_t linelen;
|
||||
char *line = NULL, **caps = NULL, *cause;
|
||||
size_t size;
|
||||
char **caps = NULL, *cause;
|
||||
u_int ncaps = 0;
|
||||
struct args_value *values;
|
||||
|
||||
@@ -400,11 +399,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
client_exec(client_execshell, client_execcmd);
|
||||
}
|
||||
|
||||
/* Restore streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
/* Print the exit message, if any, and exit. */
|
||||
if (client_attached) {
|
||||
if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
@@ -419,15 +413,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
else
|
||||
printf("%%exit\n");
|
||||
fflush(stdout);
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT) {
|
||||
setvbuf(stdin, NULL, _IOLBF, 0);
|
||||
for (;;) {
|
||||
linelen = getline(&line, &linesize, stdin);
|
||||
if (linelen <= 1)
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
if (client_flags & CLIENT_CONTROL_WAITEXIT)
|
||||
control_wait_exit(STDIN_FILENO);
|
||||
if (client_flags & CLIENT_CONTROLCONTROL) {
|
||||
printf("\033\\");
|
||||
fflush(stdout);
|
||||
@@ -435,6 +422,12 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
}
|
||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
fprintf(stderr, "%s\n", client_exit_message());
|
||||
|
||||
/* Restore the streams to blocking. */
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
setblocking(STDOUT_FILENO, 1);
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
|
||||
return (client_exitval);
|
||||
}
|
||||
|
||||
|
||||
49
control.c
49
control.c
@@ -19,7 +19,9 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -486,6 +488,53 @@ control_all_done(struct client *c)
|
||||
return (EVBUFFER_LENGTH(cs->write_event->output) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the terminal to send an empty line or close, used by a control
|
||||
* client after printing %exit so a wrapping terminal (such as iTerm2) can
|
||||
* finish reading.
|
||||
*/
|
||||
void
|
||||
control_wait_exit(int fd)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
struct evbuffer *evb;
|
||||
char *line;
|
||||
int n;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
|
||||
for (;;) {
|
||||
line = evbuffer_readln(evb, NULL, EVBUFFER_EOL_LF);
|
||||
if (line != NULL) {
|
||||
if (*line == '\0') { /* empty line, stop */
|
||||
free(line);
|
||||
break;
|
||||
}
|
||||
free(line);
|
||||
continue; /* drain buffered lines first */
|
||||
}
|
||||
|
||||
memset(&pfd, 0, sizeof pfd);
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
if (poll(&pfd, 1, INFTIM) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
n = evbuffer_read(evb, fd, -1);
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n == -1 && errno != EAGAIN && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
|
||||
evbuffer_free(evb);
|
||||
}
|
||||
|
||||
/* Flush all blocks until output. */
|
||||
static void
|
||||
control_flush_all_blocks(struct client *c)
|
||||
|
||||
1
tmux.h
1
tmux.h
@@ -3917,6 +3917,7 @@ void control_discard(struct client *);
|
||||
void control_start(struct client *);
|
||||
void control_ready(struct client *);
|
||||
void control_stop(struct client *);
|
||||
void control_wait_exit(int);
|
||||
void control_set_pane_on(struct client *, struct window_pane *);
|
||||
void control_set_pane_off(struct client *, struct window_pane *);
|
||||
void control_continue_pane(struct client *, struct window_pane *);
|
||||
|
||||
Reference in New Issue
Block a user