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>
This commit is contained in:
parent
091c801705
commit
88353ddad7
@ -38,6 +38,7 @@
|
|||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
@ -481,6 +482,7 @@ struct terminal {
|
|||||||
int selection_start_row, selection_start_col;
|
int selection_start_row, selection_start_col;
|
||||||
int selection_end_row, selection_end_col;
|
int selection_end_row, selection_end_col;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
int pace_pipe;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create default tab stops, every 8 characters */
|
/* Create default tab stops, every 8 characters */
|
||||||
@ -860,6 +862,10 @@ resize_handler(struct widget *widget,
|
|||||||
struct terminal *terminal = data;
|
struct terminal *terminal = data;
|
||||||
int32_t columns, rows, m;
|
int32_t columns, rows, m;
|
||||||
|
|
||||||
|
if (terminal->pace_pipe >= 0) {
|
||||||
|
close(terminal->pace_pipe);
|
||||||
|
terminal->pace_pipe = -1;
|
||||||
|
}
|
||||||
m = 2 * terminal->margin;
|
m = 2 * terminal->margin;
|
||||||
columns = (width - m) / (int32_t) terminal->average_width;
|
columns = (width - m) / (int32_t) terminal->average_width;
|
||||||
rows = (height - m) / (int32_t) terminal->extents.height;
|
rows = (height - m) / (int32_t) terminal->extents.height;
|
||||||
@ -3027,9 +3033,34 @@ terminal_run(struct terminal *terminal, const char *path)
|
|||||||
{
|
{
|
||||||
int master;
|
int master;
|
||||||
pid_t pid;
|
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);
|
pid = forkpty(&master, NULL, NULL, NULL);
|
||||||
if (pid == 0) {
|
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("TERM", option_term, 1);
|
||||||
setenv("COLORTERM", option_term, 1);
|
setenv("COLORTERM", option_term, 1);
|
||||||
if (execl(path, path, NULL)) {
|
if (execl(path, path, NULL)) {
|
||||||
@ -3041,7 +3072,9 @@ terminal_run(struct terminal *terminal, const char *path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(pipes[0]);
|
||||||
terminal->master = master;
|
terminal->master = master;
|
||||||
|
terminal->pace_pipe = pipes[1];
|
||||||
fcntl(master, F_SETFL, O_NONBLOCK);
|
fcntl(master, F_SETFL, O_NONBLOCK);
|
||||||
terminal->io_task.run = io_handler;
|
terminal->io_task.run = io_handler;
|
||||||
display_watch_fd(terminal->display, terminal->master,
|
display_watch_fd(terminal->display, terminal->master,
|
||||||
|
Loading…
Reference in New Issue
Block a user