Fix SIGWINCH never followed

Close #786
This commit is contained in:
topjohnwu 2018-11-20 04:40:42 -05:00
parent baae1fc84f
commit de0064af47
3 changed files with 32 additions and 67 deletions

View File

@ -41,7 +41,7 @@ static int write_blocking(int fd, char *buf, ssize_t bufsz) {
* Pump data from input FD to output FD. If close_output is * Pump data from input FD to output FD. If close_output is
* true, then close the output FD when we're done. * true, then close the output FD when we're done.
*/ */
static void pump_ex(int input, int output, int close_output) { static void pump(int input, int output, bool close_output = true) {
char buf[4096]; char buf[4096];
int len; int len;
while ((len = read(input, buf, 4096)) > 0) { while ((len = read(input, buf, 4096)) > 0) {
@ -51,32 +51,19 @@ static void pump_ex(int input, int output, int close_output) {
if (close_output) close(output); if (close_output) close(output);
} }
/**
* Pump data from input FD to output FD. Will close the
* output FD when done.
*/
static void pump(int input, int output) {
pump_ex(input, output, 1);
}
static void* pump_thread(void* data) { static void* pump_thread(void* data) {
int* files = (int*)data; int *fds = (int*) data;
int input = files[0]; pump(fds[0], fds[1]);
int output = files[1]; delete[] fds;
pump(input, output); return nullptr;
free(data);
return NULL;
} }
static void pump_async(int input, int output) { static void pump_async(int input, int output) {
pthread_t writer; pthread_t writer;
int* files = (int*)malloc(sizeof(int) * 2); int *fds = new int[2];
if (files == NULL) { fds[0] = input;
exit(-1); fds[1] = output;
} pthread_create(&writer, nullptr, pump_thread, fds);
files[0] = input;
files[1] = output;
pthread_create(&writer, NULL, pump_thread, files);
} }
@ -190,7 +177,7 @@ int restore_stdin(void) {
} }
// Flag indicating whether the sigwinch watcher should terminate. // Flag indicating whether the sigwinch watcher should terminate.
static volatile int closing_time = 0; static volatile bool close_sigwinch_watcher = false;
/** /**
* Thread process. Wait for a SIGWINCH to be received, then update * Thread process. Wait for a SIGWINCH to be received, then update
@ -198,29 +185,29 @@ static volatile int closing_time = 0;
*/ */
static void *watch_sigwinch(void *data) { static void *watch_sigwinch(void *data) {
sigset_t winch; sigset_t winch;
int *fds = (int *)data;
int sig; int sig;
int master = ((int *)data)[0];
int slave = ((int *)data)[1];
sigemptyset(&winch); sigemptyset(&winch);
sigaddset(&winch, SIGWINCH); sigaddset(&winch, SIGWINCH);
pthread_sigmask(SIG_UNBLOCK, &winch, nullptr);
do { do {
if (closing_time) break; if (close_sigwinch_watcher)
break;
// Get the new terminal size // Get the new terminal size
struct winsize w; struct winsize w;
if (ioctl(master, TIOCGWINSZ, &w) == -1) { if (ioctl(fds[0], TIOCGWINSZ, &w) == -1)
continue; continue;
}
// Set the new terminal size // Set the new terminal size
ioctl(slave, TIOCSWINSZ, &w); ioctl(fds[1], TIOCSWINSZ, &w);
} while (sigwait(&winch, &sig) == 0); } while (sigwait(&winch, &sig) == 0);
delete[] fds;
free(data); return nullptr;
return NULL;
} }
/** /**
@ -247,27 +234,24 @@ static void *watch_sigwinch(void *data) {
*/ */
int watch_sigwinch_async(int master, int slave) { int watch_sigwinch_async(int master, int slave) {
pthread_t watcher; pthread_t watcher;
int *files = (int *) malloc(sizeof(int) * 2); int *fds = new int[2];
if (files == NULL) {
return -1;
}
// Block SIGWINCH so sigwait can later receive it // Block SIGWINCH so sigwait can later receive it
sigset_t winch; sigset_t winch;
sigemptyset(&winch); sigemptyset(&winch);
sigaddset(&winch, SIGWINCH); sigaddset(&winch, SIGWINCH);
if (sigprocmask(SIG_BLOCK, &winch, NULL) == -1) { if (pthread_sigmask(SIG_BLOCK, &winch, nullptr) == -1) {
free(files); delete[] fds;
return -1; return -1;
} }
// Initialize some variables, then start the thread // Initialize some variables, then start the thread
closing_time = 0; close_sigwinch_watcher = 0;
files[0] = master; fds[0] = master;
files[1] = slave; fds[1] = slave;
int ret = pthread_create(&watcher, NULL, &watch_sigwinch, files); int ret = pthread_create(&watcher, nullptr, &watch_sigwinch, fds);
if (ret != 0) { if (ret != 0) {
free(files); delete[] fds;
errno = ret; errno = ret;
return -1; return -1;
} }
@ -275,16 +259,6 @@ int watch_sigwinch_async(int master, int slave) {
return 0; return 0;
} }
/**
* watch_sigwinch_cleanup
*
* Cause the SIGWINCH watcher thread to terminate
*/
void watch_sigwinch_cleanup(void) {
closing_time = 1;
raise(SIGWINCH);
}
/** /**
* pump_stdin_async * pump_stdin_async
* *
@ -309,9 +283,10 @@ void pump_stdin_async(int outfd) {
*/ */
void pump_stdout_blocking(int infd) { void pump_stdout_blocking(int infd) {
// Pump data from stdout to PTY // Pump data from stdout to PTY
pump_ex(infd, STDOUT_FILENO, 0 /* Don't close output when done */); pump(infd, STDOUT_FILENO, false /* Don't close output when done */);
// Cleanup // Cleanup
restore_stdin(); restore_stdin();
watch_sigwinch_cleanup(); close_sigwinch_watcher = true;
raise(SIGWINCH);
} }

View File

@ -78,13 +78,6 @@ int restore_stdin(void);
*/ */
int watch_sigwinch_async(int master, int slave); int watch_sigwinch_async(int master, int slave);
/**
* watch_sigwinch_cleanup
*
* Cause the SIGWINCH watcher thread to terminate
*/
void watch_sigwinch_cleanup(void);
/** /**
* pump_stdin_async * pump_stdin_async
* *

View File

@ -28,7 +28,7 @@
#include "pts.h" #include "pts.h"
#include "flags.h" #include "flags.h"
#define quit_signals ((int []) { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 }) int quit_signals[] = { SIGALRM, SIGABRT, SIGHUP, SIGPIPE, SIGQUIT, SIGTERM, SIGINT, 0 };
static void usage(int status) { static void usage(int status) {
FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr; FILE *stream = (status == EXIT_SUCCESS) ? stdout : stderr;
@ -224,13 +224,10 @@ int su_client_main(int argc, char *argv[]) {
// Send stderr // Send stderr
send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO); send_fd(fd, (atty & ATTY_ERR) ? -1 : STDERR_FILENO);
if (atty & ATTY_IN) { if (atty) {
setup_sighandlers(sighandler); setup_sighandlers(sighandler);
pump_stdin_async(ptmx);
}
if (atty & ATTY_OUT) {
// Forward SIGWINCH
watch_sigwinch_async(STDOUT_FILENO, ptmx); watch_sigwinch_async(STDOUT_FILENO, ptmx);
pump_stdin_async(ptmx);
pump_stdout_blocking(ptmx); pump_stdout_blocking(ptmx);
} }