diff options
author | Derek Foreman <derekf@osg.samsung.com> | 2017-03-24 16:29:31 -0500 |
---|---|---|
committer | Quentin Glidic <sardemff7+git@sardemff7.net> | 2017-03-24 22:43:20 +0100 |
commit | 88353ddad7980420017ce65e37cc2eed0c6126d2 (patch) | |
tree | 9ce672928ec8f67a25dfd3271dacac934a04f542 /clients | |
parent | 091c8017057099dd34bbd5c8421fd0a42ac4ee8a (diff) |
weston-terminal: Fix race at startup
If anything is printed for the terminal window to display before the
window has been initially sized we end up with a segfault.
This defers the exec() of the shell child process until after the
window is sized so this can't happen anymore.
Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Diffstat (limited to 'clients')
-rw-r--r-- | clients/terminal.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/clients/terminal.c b/clients/terminal.c index c5531790..274ced09 100644 --- a/clients/terminal.c +++ b/clients/terminal.c @@ -38,6 +38,7 @@ #include <sys/epoll.h> #include <wchar.h> #include <locale.h> +#include <errno.h> #include <linux/input.h> @@ -481,6 +482,7 @@ struct terminal { int selection_start_row, selection_start_col; int selection_end_row, selection_end_col; struct wl_list link; + int pace_pipe; }; /* Create default tab stops, every 8 characters */ @@ -860,6 +862,10 @@ resize_handler(struct widget *widget, struct terminal *terminal = data; int32_t columns, rows, m; + if (terminal->pace_pipe >= 0) { + close(terminal->pace_pipe); + terminal->pace_pipe = -1; + } m = 2 * terminal->margin; columns = (width - m) / (int32_t) terminal->average_width; rows = (height - m) / (int32_t) terminal->extents.height; @@ -3027,9 +3033,34 @@ terminal_run(struct terminal *terminal, const char *path) { int master; pid_t pid; + int pipes[2]; + + /* Awkwardness: There's a sticky race condition here. If + * anything prints after the forkpty() but before the window has + * a size then we'll segfault. So we make a pipe and wait on + * it before actually exec()ing the terminal. The resize + * handler closes it in the parent process and the child continues + * on to launch a shell. + * + * The reason we don't just do terminal_run() after the window + * has a size is that we'd prefer to perform the fork() before + * the process opens a wayland connection. + */ + if (pipe(pipes) == -1) { + fprintf(stderr, "Can't create pipe for pacing.\n"); + exit(EXIT_FAILURE); + } pid = forkpty(&master, NULL, NULL, NULL); if (pid == 0) { + int ret; + + close(pipes[1]); + do { + char tmp; + ret = read(pipes[0], &tmp, 1); + } while (ret == -1 && errno == EINTR); + close(pipes[0]); setenv("TERM", option_term, 1); setenv("COLORTERM", option_term, 1); if (execl(path, path, NULL)) { @@ -3041,7 +3072,9 @@ terminal_run(struct terminal *terminal, const char *path) return -1; } + close(pipes[0]); terminal->master = master; + terminal->pace_pipe = pipes[1]; fcntl(master, F_SETFL, O_NONBLOCK); terminal->io_task.run = io_handler; display_watch_fd(terminal->display, terminal->master, |