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