Re: extended file handles

Dean Gaudet (dgaudet-list-linux-kernel@arctic.org)
Tue, 30 Jun 1998 12:24:42 -0700 (PDT)


On Tue, 30 Jun 1998, MOLNAR Ingo wrote:

> [mingo@hal ce]$ ./ce
> fd(3,3) open(..,..|O_CLOSEXEC) feature works!
>
> wondering wether the libc & standards guys like this approach though.

Cool :) You may want call it O_CLOEXEC -- which sounds closer to the
FD_CLOEXEC that solaris defines for fcntl(F_SETFD).

If you support O_CLOEXEC with fcntl() as well, then a single system call
can be used to turn the result of accept()/socket()/socketpair()/pipe()
into a non-blocking, non-inherited socket.

Here's another idea which solves almost all the problems, without any
need for O_CLOEXEC.

pid_t clonefd(void *sp, unsigned long flags,
const int *fd_split, size_t n_fd);

where:
sp and flags are as in clone()

fd_split is an array of file descriptors that describe exactly
which descriptors the child will keep... there's various
different ways to do this. If it's not listed in this array
it will be closed in the child.

n_fd is the number of descriptors in fd_split

the result is similar to clone

fd_split has various possible semantics, I'm not sure of the best,
all may be possible with more flags:

- assume that the parent has used pipe() or open() to set up a few
descriptors for the child and plans to turn them into 0, 1, and 2
in the child. So copy fd_split[n] to the nth descriptor in the
child, and close each in the parent. i.e.:

int childin[2];
int childout[2];
int childerr[2];
int fd_split[3];

pipe(childin);
pipe(childout);
pipe(childerr);
fd_split[0] = childin[0];
fd_split[1] = childout[1];
fd_split[2] = childerr[1];
if (clonefd(NULL, CLONE_FS|CLONE_SIGHAND|CLONE_VM, fd_split, 3)) {
/* in parent, childin[0], childout[1], and childerr[1] are
* no longer open
*/
}
else {
/* in child, the only open descriptors are 0, 1, 2 */
exec(something);
}

(this one is the best for apache and shells)

- assume that the parent is trying to share an open fd with the child
(i.e. a log file). In this case copy fd_split[n] to the nth
descriptor in the child and leave them open in the parent. So the
parent would have to explicitly call close() on the descriptors it
didn't intend to share.

(dunno, what's it good for? You can simulate it with the first
and a few extra dup()s)

- copy fd_split to the child without renumbering -- so if
fd_split[0] == 34, then the child has descriptor 34 open. Works with
either of the above two semantics.

clonefd() is essentially an extension to clone() to tune it for spawning
new programs. With it there's almost no reason for XFDs... the
remaining reason is to get away from POSIX' "lowest available
descriptor" semantic... which is easy for open(), but still a pain
for socket()/accept()/etc.

Dean

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu