[PATCH weston v2] weston-terminal: Fix race at startup
Derek Foreman
derekf at osg.samsung.com
Fri Mar 24 21:29:31 UTC 2017
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 at osg.samsung.com>
Reviewed-by: Quentin Glidic <sardemff7+git at sardemff7.net>
---
Changes from revision 1:
- don't forget to close the other half of the pipe in the child
clients/terminal.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
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,
--
2.11.0
More information about the wayland-devel
mailing list