kern/176233: [libc] [patch] New dup3() implementation for FreeBSD
Jukka A. Ukkonen
jau at iki.fi
Wed Feb 20 09:50:02 UTC 2013
The following reply was made to PR kern/176233; it has been noted by GNATS.
From: jau at iki.fi (Jukka A. Ukkonen)
To: jilles at stack.nl (Jilles Tjoelker)
Cc: bug-followup at FreeBSD.org, jau at iki.fi
Subject: Re: kern/176233: [libc] [patch] New dup3() implementation for FreeBSD
Date: Wed, 20 Feb 2013 11:13:14 +0200 (EET)
Quoting Jilles Tjoelker:
>
> PR kern/176233:
> > [dup3 implementation based on F_DUP2FD_CLOEXEC]
>
> The dup3() function appears to be used in the wild and there is a gnulib
> replacement for it, even though it seems of rather limited use compared
> to fcntl(F_DUPFD_CLOEXEC). Most uses of dup2() are for passing fd 0, 1
> or 2 to a process so that the close-on-exec flag should be clear.
>
> I think glibc's [EINVAL] on oldfd == newfd actually makes some sense as
> it forces the programmer to separate clearly the cases where oldfd !=
> newfd and oldfd == newfd. http://austingroupbugs.net/view.php?id=411
> also proposes requiring it.
This is a kind of a philosophical choise.
Do we expect the programmer to pass two equal file descriptors
intentionally or not?
The Linux community and the Austin group have taken the view in
which they do not trust the programmer to do it intentionally.
The NetBSD way is to rely on the programmer to use the trick
by choise, not by accident. Personally I rather like the latter
approach. ;-)
Also simple good style favors sticking to similar behavior as the
existing dup2() while the "big academic problem" Linux has been
solving with their deviant behavior is in fact more of a paper tiger.
Anyhow were the large majority to prefer the pointlessly restrictive
(in my mind) Linux approach over the NetBSD approach and over
consistency with the existing dup2(), you have the necessary check
included in my patch between "#if 0/#endif".
Any time this sort of discussion about which school of thought to
follow breaks up I quite miss the old ConvexOS "warp" concept.
It would allow us to choose both ways at the same time.
In ConvexOS warp was part of the process features which were inherited
by the children, and the setting allowed various parts of the system
(system calls, library functions, etc.) to choose which tradition and
which school of thouht to follow. One just had to set a warp variable
on the command line and the shell set that for the child processes
using the setwarp() system call just before exec*().
In this case I would personally like to enclose the check against
equal file descriptors within a special warp check and be over
with it...
if (getwarp() == WARP_LINUX) {
if (oldd == newd) {
return (EINVAL);
}
}
FreeBSD just does not support the warp concept - at least not yet.
OTOH adding the warp feature might actually help with the linuxulator
and other emulation efforts.
> The O_NONBLOCK and O_NOSIGPIPE flags appear contrary to the idea of
> dup2/dup3 since they affect the underlying object and not just the new
> file descriptor like O_CLOEXEC does.
Right, I checked the current FreeBSD implementations of O_NONBLOCK and
SO_NOSIGPIPE, which is the closest thing FreeBSD has to O_NOSIGPIPE.
They seem to be implemented as flags in the file pointer structure
and in the socket structure, not as part of the descriptor.
The first question of course is whether the flags really have to be
implemented this way, if the interpretation gives raise to problems?
The second equally obvious question is, what prevents the programmer
from setting those flags on the resulting new descriptor anyhow right
after calling the existing dup2() and still affecting also the old
descriptor in the process?
Since the most common action to the old descriptor after dup2() is
anyhow close() in case (oldfd != newfd), the side effect to the old
descriptor should be mostly irrelevant. At the same time the added
convenience to the programmer might be quite beneficial in avoiding
situations in which one simply forgets to set such flags when they
would be needed.
Compactness and readability of the code is also enhanced when one
does not have to write separate function/system calls after dup2()
to get the same effect.
A technical limitation might simply not be the proper solution to
something which would be better served by adding a serious warning
in the manual page saying roughly...
"Do not call dup*() and then expect calling lseek() or changing flags
on one of the multiple descriptors to an object not to affect the
behavior when using any of the other descriptors to the same object.
The dup*() family only adds handles to an object. It does not make
copies of the underlying object.
Though you gain multiple descriptors you still have only one object.
If you change an object through any of the descriptors, the change
will be visible also when using the object through any of the other
descriptors."
> Unknown/unsupported flags should indeed [EINVAL] so we have a chance to
> add new flags later.
;-)
Cheers,
// jau
.--- ..- -.- -.- .- .- .-.-.- ..- -.- -.- --- -. . -.
/ Jukka A. Ukkonen, Oxit Ltd, Finland
/__ M.Sc. (sw-eng & cs) (Phone) +358-500-606-671
/ Internet: Jukka.Ukkonen(a)Oxit.Fi
/ Internet: jau(a)iki.fi
v
.--- .- ..- ...-.- .. -.- .. .-.-.- ..-. ..
+ + + + My opinions are mine and mine alone, not my employers. + + + +
More information about the freebsd-bugs
mailing list