Opened 9 years ago

Last modified 5 years ago

#687 new enhancement

use posix_spawn for ccl:run-program

Reported by: rme Owned by: rme
Priority: normal Milestone:
Component: other Version: trunk
Keywords: Cc:


When the operating system supports it, use posix_spawn in lieu of fork/exec in the implementation of ccl:run-program.

Change History (3)

comment:1 Changed 8 years ago by rme describes a race involving closing file descriptors that we may want to watch out for.

On Mar 1, 2011, at 1:54 AM, Chris Suter wrote:

On Tue, Mar 1, 2011 at 8:47 PM, Greg Parker <gparker@…> wrote:


The problem is that there's no "close all but these" file action for posix_spawn(). There's no safe way for posix_spawn() to create a child process with all descriptors closed except a known set like stdin/out/err. You cannot safely use posix_spawn_file_actions_addclose() for every open descriptor in the parent, because other threads in the parent may be concurrently opening and closing those descriptors between the time you set up the file actions and the time you call posix_spawn().

But what if you added a close action for all possible file descriptors except for stdin, stdout & stderr? i.e. looped over all 1024 (or however many) file descriptors except for those three?

Doesn't work. If another thread is concurrently opening or closing descriptors during your scan and your call to posix_spawn(), you'll fail.

  1. If you set posix_spawn_file_actions_addclose() for a descriptor, and

another thread closes that descriptor before you call posix_spawn(), then posix_spawn() will return EBADF and not spawn the process.

  1. If you fail to set posix_spawn_file_actions_addclose() for a

descriptor, and another thread opens that descriptor before you call posix_spawn(), then the child process will have an unexpectedly open descriptor. This can lead to deadlocks elsewhere.

And how exactly would you close file descriptors between the fork and exec? How do you know what file descriptors to close?

Just like you said above: you loop through all 1024 (or however many) file descriptors and close everything except the ones you want. This is safe in the fork/exec case because there's only one thread in the child after fork(), so there's no race with other manipulation of the child's descriptors.

comment:2 Changed 5 years ago by rme

The above link describes a strategy whereby posix_spawn starts a little helper program that does the file descriptor manipulation, and then does the fork() and exec().

Or maybe we just forget about this complicated mess and keep on using fork() in ccl.

comment:3 Changed 5 years ago by rme

Apple's posix_spawnattr_setflags() accepts a flag named POSIX_SPAWN_CLOEXEC_DEFAULT. The man page says:

If this bit is set, then only file descriptors explicitly described by the file_actions argument are available in the spawned process; all of the other file descriptors are automatically closed in the spawned process.

It looks like this showed up in 10.7.2 or thereabouts.

Note: See TracTickets for help on using tickets.