os: File.Fd() sets the underlying fd to non-blocking mode

755 views
Skip to first unread message

Nick Patavalis

unread,
Mar 9, 2018, 6:31:35 PM3/9/18
to golang-dev




Hi,

Since go 1.9, os.File's are backed by a mechanism similar to netpoll, whenever possible.
This means that you can set read and write deadlines on them, and that you can
safely Close() a file from another goroutine while Read and / or Write calls are active.

I'm working a lot with device nodes (/dev/XXX files, like serial ports /dev/ttySx, but 
not only) and this was the best news for me. Truly godsend.

Sadly it turns out I **cannot** use this new feature, for a trivial and equally frustrating 
reason:

Occasionally I need to access the underlying file-descriptor of a device in order to do 
a trivial ioctl(). But if I call File.Fd(), then the underlying filedes is set to blocking mode, 
and I lose (forever) all the cool poller support (deadlines, etc). 

I thought I could turn the filedes to nonblocking mode myself, but this 
will not do: I would also need to set internal File / pfd attributes which I have 
no access to.

Alternatively, I thought I could start with a filedes (i.e. use syscall.Open) and convert 
it to a file,  using NewFile() (so I don't have to call File.Fd()) but again, looking at the 
code, File's created with NewFile are *not* considered pollable (for reasons I do 
not understand).

You can imagine my utter frustration!! 

It's as if someone deliberately tried to make the feature useless and block-off any 
possibility of me using it. Am I missing something? Is there a way around this in 
the current state of things?  

If not, please, please, please: Give me a way to get a file's underlying filedes without 
setting it to non-blocking mode, and (most importantly) without loosing all the poller 
goodies. It's no more than a couple of lines of code (a new method or whatever), but 
without them, you 're making the situation IMPOSSIBLE for me (and, I guess for 
others too). And, I believe, my case (accessing pollable device nodes) is exactly one 
of those for which the poller support was added to File's for.  

I could even write the code myself if you wish (it's *that* trivial) in the form of a new 
method, like File.RawFd() or something...

Thanks for you attention, and sorry for the long post.

/npat

Russ Cox

unread,
Mar 9, 2018, 8:17:48 PM3/9/18
to Nick Patavalis, golang-dev
It should work to call syscall.Open to get an fd in non-blocking mode and then pass it to os.NewFile. That is, start with an fd and turn it into a File (and remember the old fd), instead of the reverse. 

For Go 1.11 maybe we should make os.File implement syscall.Conn.

Best,
Russ

Dave Cheney

unread,
Mar 9, 2018, 8:22:15 PM3/9/18
to Russ Cox, Nick Patavalis, golang-dev
Nick, could you please raise an issue, https://golang.org/issue/new so
that it can be earmarked for Go 1.11
> --
> You received this message because you are subscribed to the Google Groups
> "golang-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-dev+...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Nick Patavalis

unread,
Mar 9, 2018, 8:39:30 PM3/9/18
to Russ Cox, golang-dev
On Sat, Mar 10, 2018 at 3:17 AM, Russ Cox <r...@golang.org> wrote:
> It should work to call syscall.Open to get an fd in non-blocking mode and
> then pass it to os.NewFile. That is, start with an fd and turn it into a
> File (and remember the old fd), instead of the reverse.
>

This would be perfectly adequate, but I don't think it will work. See:

src/os/file_unix.go, lines 75-135

File.NewFile calls File.newFile with the third arg being kindNewFile,
this in turn calls pfd.Init() with pollable=false, which, I believe,
won't do.

Am I mistaken?

/npat

Nick Patavalis

unread,
Mar 9, 2018, 8:59:54 PM3/9/18
to Russ Cox, golang-dev, Nick Patavalis
​​Hi,

On Sat, Mar 10, 2018 at 3:17 AM, Russ Cox <r...@golang.org> wrote:
>
> For Go 1.11 maybe we should make os.File implement syscall.Conn.
>

While syscall.Conn would be adequate (and maybe a nice solution for
network connections), pragmatically, I would strongly prefer a much
simpler solution like a File.FdRaw() or File.RawFd() method with the
obvious semantics. You aleady have File.Fd() so you are not exposing
anything you didn't already. There is a lot of code who simply does
File.Fd() to get the filedes and do ioctls (or more complicated
control functions---say, termios) to it. All one would need to change
would be to call FdRaw() instead of Fd() and the code would still work
with the new features.  With sycall.Conn the user would have to
patch-up complicated closures and such... which is not very
convenient.

While I do undestand that the​ current behavior of File.Fd() is for
compatibility, in a sense, FdRaw() does what Fd() always did: Just
return the filedes without messing with the file. Most don't call Fd()
to subsequently do a syscall.Read or Write on the filedes (they can do
it directly with the File). So they wouldn't care if the returned fd
is in blocking mode or not. What they / we do care is that the call
does not magically alter the operation of the File in such a great
extend.

/npat

On Sat, Mar 10, 2018 at 3:17 AM, Russ Cox <r...@golang.org> wrote:

Nick Patavalis

unread,
Mar 9, 2018, 9:05:14 PM3/9/18
to Dave Cheney, Russ Cox, golang-dev
Dave,

> Nick, could you please raise an issue, https://golang.org/issue/new
> so that it can be earmarked for Go 1.11

Sure, I will.

/npat

Nick Patavalis

unread,
Mar 10, 2018, 6:42:23 AM3/10/18
to Dave Cheney, Russ Cox, golang-dev
Reply all
Reply to author
Forward
0 new messages