On Sat, Feb 29, 2020 at 12:16 PM Philip Boampong <pboampo...@gmail.com> wrote:
>
> On Sat, Feb 29, 2020 at 1:34 PM Ian Lance Taylor <i...@golang.org> wrote:
> >
> > It does not make sense to use dup2 if you are not in control of the FD
> > namespace.  In order to use dup2 you need to specify the new FD.  If
> > that FD might be concurrently opened by some other package, or by the
> > runtime, then you can not use dup2 safely.
>
> But if you opened newfd yourself, or if it is 0/1/2 and you never
> closed os.Std*, then you *can* dup2 safely, regardless of other
> packages.

Those are examples where you are in charge of the FD namespace
(assuming you know that no other code is doing to touch descriptors
0/1/2).


> > This doesn't mean that Go program can never use dup2.  The runtime
> > will only open a file descriptor when requested.  You can avoid
> > packages that open descriptors at unpredictable times.
>
> Can you really do that? I don't think the standard library guarantees
> that it will not create a new FD behind the scenes tomorrow (nor it
> exactly documents its FD usage and timing).
>
> > Is this a theoretical question or one that arises from real code?
>
> It's not theoretical, I became aware of EINTR and I'm trying to fix my own 
> code.
> I use dup2 to redirect FD 0/1/2 from inside the program itself (I know
> I can assign to os.Std* but that is not always sufficient or safe).
> The most common case is to redirect stderr including panic output.

So you are calling dup2(N, 2)?  What problem are you trying to avoid?


> As you can see, I cannot retry dup2 on EINTR unless I'm sure that the
> first call has left newfd open, otherwise I will incur the race. But
> if I don't retry it, then I have no way to recover from ordinary
> signals!

What race are you worried about?  You are already assuming that
nothing else is going to touch descriptor 2.  dup2 is documented to
atomically close newfd and duplicate oldfd onto it.  That means that
either newfd is untouched, or oldfd is duplicated onto it.  That is
true whether dup2 returns EINTR or not.  And dup2 is not documented to
return EINTR, and the Linux kernel code shown above does not have any
path that returns EINTR.


> I don't think you can argue that I'm supposed to have control of the
> FD namespace: the whole point of dup2 being atomic [1] is that users
> may not have such control, see also [2][3].

You need to have control because you have to know what is happening
with newfd.  If two different goroutines call dup2(..., 2) then you
need to know which goroutine is going to run last.


> (I'm not actually getting EINTR from my dup2's, but I want to handle
> it correctly if it can happen.)
>
> > > Just to ask the an obvious question: is dup2() idempotent or not?
> >
> > dup2 in itself is idempotent.
>
> It's hard to talk about idempotence when the context changes
> unpredictably (FD state).
> Dup2 is "atomic", in the sense that newfd is never reusable during the
> whole syscall.
> But is it "atomic" in the sense that it will either "leave FDs
> unchanged with an error", or "complete without error", nothing in
> between?

That is what it means to atomically close newfd and duplicate oldfd
onto newfd.  It will either leave newfd unchanged, or it will
duplicate oldfd onto newfd.  Any other possibility would not be
atomic.

Quoting the GNU/Linux man page:

       The  steps  of  closing  and reusing the file descriptor newfd are per‐
       formed atomically.  This is  important,  because  trying  to  implement
       equivalent  functionality  using close(2) and dup() would be subject to
       race conditions, whereby newfd might be reused between the  two  steps.
       Such  reuse  could  happen because the main program is interrupted by a
       signal handler that allocates a file descriptor, or because a  parallel
       thread allocates a file descriptor.

Note the explicit mention of a signal handler.

Ian

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcUdUu3dH37SFy%2BntDYc_GmcCp8QjukO%2BD%3DG672DY88W0Q%40mail.gmail.com.

Reply via email to