Tmux is hanging on aix, and the problem appears to be a race condition
in the implementation of forkpty.

Aix has the behavior that, if data has been written to the slave side
of a pty but has not been read yet by the master side, then the last
close of the slave pty will hang until the data is read, or the master
is closed.

I'm able to trigger the hang by calling splitw with a bad shell
command.  What's happening is that  after the call to fork in forkpty,
the child process continues and the spawned shell writes a "command
not found" message and then exits.  It is able to do this before the
parent process calls close(slave) at the end of its part of forkpty.
By the time the parent calls close(slave), some data has been written
to the slave, and the parent has the last open reference to the slave
pty.  So, the parent hangs in the close.

Some type of coordination has to be done so that the parent (the tmux
server process) can't end up with the last open reference to the
slave.  I've attached a patch that provides a possible solution.
diff --git a/compat/forkpty-aix.c b/compat/forkpty-aix.c
index db9c2e7..06f4706 100644
--- a/compat/forkpty-aix.c
+++ b/compat/forkpty-aix.c
@@ -29,10 +29,13 @@
 pid_t
 forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws)
 {
-	int	slave, fd;
-	char   *path;
+	int	slave, fd, pipe_fd[2];
+	char   *path, dummy_buf;
 	pid_t	pid;
 
+	if (pipe(pipe_fd) == -1)
+		return (-1);
+
 	if ((*master = open("/dev/ptc", O_RDWR|O_NOCTTY)) == -1)
 		return (-1);
 
@@ -46,6 +49,10 @@ forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws)
 		goto out;
 	case 0:
 		close(*master);
+		close(pipe_fd[1]);
+
+		read(pipe_fd[0], &dummy_buf, 1);
+		close(pipe_fd[0]);
 
 		fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
 		if (fd >= 0) {
@@ -80,13 +87,18 @@ forkpty(int *master, unused char *name, struct termios *tio, struct winsize *ws)
 		dup2(slave, 2);
 		if (slave > 2)
 			close(slave);
+
 		return (0);
 	}
 
 	close(slave);
+	close(pipe_fd[0]);
+	close(pipe_fd[1]);
 	return (pid);
 
 out:
+	close(pipe_fd[0]);
+	close(pipe_fd[1]);
 	if (*master != -1)
 		close(*master);
 	if (slave != -1)
------------------------------------------------------------------------------
Slashdot TV.  Video for Nerds.  Stuff that Matters.
http://pubads.g.doubleclick.net/gampad/clk?id=160591471&iu=/4140/ostg.clktrk
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to