as you note you can't create any fd (i.e. via open/socket/accept/dup/dup2/F_DUPFD/...) without a race condition between the creation and setting F_CLOEXEC in a threaded program. unix wasn't designed for threads. there are a few choices:
(1) all fd creation under a mutex... gross.
(2) portable: after fork() use dup2 to set up stdin/out/err then getrlimit(RLIMIT_NOFILE) and iterate for (int i = 2; i < N; ++i) { close(i); }
(3) not portable: linux (and perhaps others) is slowly acquiring O_CLOEXEC, F_DUPFD_CLOEXEC and other such flags so that you can cause fds to be created with F_CLOEXEC set from the start.
imho (2) is the best solution. you just have to catch all uses of fork(). i.e. popen() is hell.
as you note you can't create any fd (i.e. via open/socket/ accept/ dup/dup2/ F_DUPFD/ ...) without a race condition between the creation and setting F_CLOEXEC in a threaded program. unix wasn't designed for threads. there are a few choices:
(1) all fd creation under a mutex... gross.
(2) portable: after fork() use dup2 to set up stdin/out/err then getrlimit( RLIMIT_ NOFILE) and iterate for (int i = 2; i < N; ++i) { close(i); }
(3) not portable: linux (and perhaps others) is slowly acquiring O_CLOEXEC, F_DUPFD_CLOEXEC and other such flags so that you can cause fds to be created with F_CLOEXEC set from the start.
imho (2) is the best solution. you just have to catch all uses of fork(). i.e. popen() is hell.
-dean