# openpty slave handle close() hang



## brianb (Mar 26, 2014)

We have some x-platform code to launch a sub-process with a comm channel using openpty() and posix_spawn(). Overview: 1) openpty() to get a master/slave pair, 2) turn off ECHO and ICANON on the slave fd, 3) posix_spawn_file dup2 the slave to stdin, stderr, and stdout, 4) posix_spawn the command, 5) cleanup in master, including close() for the slave. On FreeBSD 10.0 x86-64 the slave close() will hang, the same code works on Linux (kernel 3.x) and OSX (10.6+).

For our automated tests we are just launching a shell script that does 
	
	



```
#!/usr/bin/env sh; echo hello world
```

Anyone have any ideas as to what might be going on?

Here are the relevant sections of this function:

```
#define belog(fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
       if (-1 == openpty(&master, &slave, NULL, NULL, NULL)) {
            belog("%s: openpty failed: %s", __FUNCTION__, strerror(errno));
            return (errno);
        }
        
        // Child: We don't want input buffering, or to echo our parent's characters.
        if (0 == tcgetattr(slave, &tio)) {
            tio.c_lflag &= ~ECHO;
            if (0 == (flags & kdLaunchBuffered))
                tio.c_lflag &= ~ICANON;
            else {
                #if DEBUG
                belog("%s: buffering pty input", __FUNCTION__);
                #endif
                tio.c_lflag |= ICANON;
            }
            (void)tcsetattr(slave, TCSANOW|TCSAFLUSH, &tio);
        } else {
            belog("%s: failed to get child terminal attrs: %s", __FUNCTION__, strerror(errno));
        }
        
        // set the pty slave descriptor as the child's std I/O
        if (0 == serr)
            serr = posix_spawn_file_actions_adddup2(&actions, slave, STDIN_FILENO);
        if (0 == serr)
            serr = posix_spawn_file_actions_adddup2(&actions, slave, STDOUT_FILENO);
        if (0 == serr)
            serr = posix_spawn_file_actions_adddup2(&actions, slave, STDERR_FILENO);
        PSASSERT(slave > STDERR_FILENO, "why?");
        if (0 == serr && slave > STDERR_FILENO)
            serr = posix_spawn_file_actions_addclose(&actions, slave);
        
        if (0 != serr) {
            belog("%s: posix_spawn_file_actions failed: %s", __FUNCTION__, strerror(errno));
        }
```


```
posix_spawnattr_t attrs;
serr = posix_spawnattr_init(&attrs);
   if (PS_EXPECTED(0 == serr)) {
        extern char **environ;
        serr = posix_spawn(&pid, path, &actions, &attrs, argv, environ);
    }
    
    (void)close(slave);
    (void)posix_spawn_file_actions_destroy(&actions);
    (void)posix_spawnattr_destroy(&attrs);
```


----------

