Bruno Haible <br...@clisp.org> writes: o> Hi Simon, > >> Now the test-openpty self-test hangs on my Mac OS X machine, and the >> process doesn't even go away from the process table after a 'kill -9'. >> Here is a gdb session, which suggests it hangs when shutting down the >> process: > > Strange. This program now uses the MacOS built-in openpty function. > I see no problem on MacOS X 10.5. > > You could try to isolate the problem by adding explicit > printf ("%d\n", close (master)); > printf ("%d\n", close (slave)); > statements before the "return 0;". Other than that, it looks like the simple > test program is triggering a bug in MacOS X?
Yes. The stand-alone program below reproduces the Mac OS X bug: espresso:~ jas$ cc -Wall -o test-openpty test-openpty.c espresso:~ jas$ ./test-openpty master Closing master: 0 espresso:~ jas$ ./test-openpty slave ^C espresso:~ jas$ ./test-openpty ^C^Z^C^Z^C^Z^C^Z I have to close the SSH connection to resume control, and logging in back in, the process is stuck and 'kill -9' doesn't kill it. This is on a fully updated Mac OS X 10.4.11 (PPC) PowerBook G4 laptop. If anyone else has access to an Intel 10.4.x Mac machine, it would be interesting to attempt to reproduce this. Bruno, can you confirm that this program works fine on your 10.5 machine? How about this patch: diff --git a/doc/glibc-functions/openpty.texi b/doc/glibc-functions/openpty.texi index 31fdca0..f345f7d 100644 --- a/doc/glibc-functions/openpty.texi +++ b/doc/glibc-functions/openpty.texi @@ -30,4 +30,8 @@ Portability problems not fixed by Gnulib: @item This function is missing on some platforms: mingw. +...@item +On Mac OS X 10.4.11 (PowerPC) the application needs to close the +master file descriptor, otherwise the process hangs and is not +possible to kill. @end itemize /Simon
/* Test of pty.h and openpty function. Copyright (C) 2009, 2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Written by Simon Josefsson <si...@josefsson.org>, 2009 and Bruno Haible <br...@clisp.org>, 2010. */ #include <util.h> #include <stdio.h> #include <string.h> #include <termios.h> #include <unistd.h> int main (int argc, char *argv[]) { { int master; int slave; /* Open a pseudo-terminal, as a master-slave pair. */ { int res = openpty (&master, &slave, NULL, NULL, NULL); if (res != 0) { fprintf (stderr, "openpty returned %d\n", res); return 1; } } /* Set the terminal characteristics. On Linux or MacOS X, they can be set on either the master or the slave; the effect is the same. But on Solaris, they have to be set on the master; tcgetattr on the slave fails. */ { int tcfd = slave; /* You can try tcfd = master; here. */ struct termios attributes; if (tcgetattr (tcfd, &attributes) < 0) { fprintf (stderr, "tcgetattr failed\n"); return 1; } /* Enable canonical processing, including erase. */ attributes.c_lflag |= ECHO | ICANON | ECHOE; attributes.c_cc[VERASE] = '\177'; if (tcsetattr (tcfd, TCSANOW, &attributes) < 0) { fprintf (stderr, "tcsetattr failed\n"); return 1; } } /* Write into the master side. */ { static const char input[] = "Hello worst\177\177ld!\n"; if (write (master, input, strlen (input)) < (int) strlen (input)) { fprintf (stderr, "write failed\n"); return 1; } } /* Read from the slave side. */ { char buf[100]; int res = read (slave, buf, sizeof (buf)); static const char expected[] = "Hello world!\n"; if (res < 0) { fprintf (stderr, "read failed\n"); return 1; } if (!(res == strlen (expected) && memcmp (buf, expected, strlen (expected)) == 0)) { fprintf (stderr, "read result unexpected\n"); return 1; } } if (argc >= 1 && strcmp (argv[1], "master") == 0) printf ("Closing master: %d\n", close (master)); if (argc >= 1 && strcmp (argv[1], "slave") == 0) printf ("Closing slave: %d\n", close (slave)); } return 0; }