[PATCH weston v2] weston-terminal: Fix race at startup

Quentin Glidic sardemff7+wayland at sardemff7.net
Fri Mar 24 21:45:38 UTC 2017


On 3/24/17 10:29 PM, Derek Foreman wrote:
> 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

Nice, pushed:
091c8017..88353dda  master -> master

Thanks,


>   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,
> 


-- 

Quentin “Sardem FF7” Glidic


More information about the wayland-devel mailing list