Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Bad file descriptor" error #5

Closed
schrauf opened this issue Jul 29, 2020 · 14 comments
Closed

"Bad file descriptor" error #5

schrauf opened this issue Jul 29, 2020 · 14 comments

Comments

@schrauf
Copy link

schrauf commented Jul 29, 2020

Hi, I saw your (great) presentation today and wanted to try TerminalUserInterfaces.jl
but I'm having a "Bad file descriptor" error. posted the issue here since I think my problem starts with TERMIOS.
I don't understand it, sorry if it is obvious.

Working in linux (linux mint 19.3 64 bit).
I copied the usage example from the docs into a file "termios-debug.jl":

using TERMIOS
const T = TERMIOS
term_stdin = T.termios()
T.tcgetattr(stdin, term_stdin)
term_stdin.c_iflag |= T.IGNBRK
T.tcsetattr(stdin, T.TCSANOW, term_stdin)
user@host:dir$ julia termios-debug.jl 
ERROR: LoadError: TERMIOSError: tcgetattr failed: Bad file descriptor
Stacktrace:
 [1] tcgetattr(::RawFD, ::TERMIOS.termios) at ~/.julia/packages/TERMIOS/Kvyl9/src/TERMIOS.jl:610
 [2] tcgetattr(::Base.TTY, ::TERMIOS.termios) at ~/.julia/packages/TERMIOS/Kvyl9/src/TERMIOS.jl:612
 [3] top-level scope at dir/termios-debug.jl:4
 [4] include(::Module, ::String) at ./Base.jl:377
 [5] exec_options(::Base.JLOptions) at ./client.jl:288
 [6] _start() at ./client.jl:484
in expression starting at dir/termios-debug.jl:4
@kdheepak
Copy link
Owner

kdheepak commented Jul 29, 2020

I've experienced that error on my Mac as well. For me it is intermittent/inconsistent. Some runs, everything works fine. Are you experiencing this error every time you run it?

I've also been able to decrease the number of times I get this by moving the code that calls tcgetattr into a function. Can you try this and see if it makes a difference?

using TERMIOS
const T = TERMIOS

function main()
    term_stdin = T.termios()
    T.tcgetattr(stdin, term_stdin)
    term_stdin.c_iflag |= T.IGNBRK
    T.tcsetattr(stdin, T.TCSANOW, term_stdin)
end

main()

Or just in a repl?

Your code was erroring in the first call to tcgettr. And the bad file descriptor means that it is not able to tcgetattr on the stdin file, and I'm not sure why that would be the case.

@schrauf
Copy link
Author

schrauf commented Jul 29, 2020

Thanks for your time and the fast response!
I'm experiencing this error every time (which might make it easier to debug :)

I've just tried your suggestion both as a file and in the repl, and I get the same error.
In case it helps, my stdin works:

julia> print(stdin, "here")
here
julia> stdin
Base.TTY(RawFD(0x0000000a) paused, 0 bytes waiting)

@kdheepak
Copy link
Owner

Interesting. Can you try the following in python?

import termios, sys
fd = sys.stdin.fileno()
print(fd)
termios.tcgetattr(fd)

@schrauf
Copy link
Author

schrauf commented Jul 29, 2020

Yes,

In [1]: import termios, sys 
   ...: fd = sys.stdin.fileno() 
   ...: print(fd) 
   ...: termios.tcgetattr(fd)                                                                                                          
0
Out[1]: 
[16640,
 5,
 191,
 35387,
 15,
 15,
 [b'\x03',
  b'\x1c',
  b'\x7f',
...
b'\x00']]

the last element of a list is itself a list with 32 byte elements

@kdheepak
Copy link
Owner

In Python, this is the source:

https://github.com/python/cpython/blob/ba18c0b13ba3c08077ea3db6658328523823a33f/Modules/termios.c#L81-L96

And in julia, this is the source:

TERMIOS.jl/src/TERMIOS.jl

Lines 601 to 613 in 37d991d

"""
tcgetattr(fd::RawFD, term::termios)
tcgetattr(s::Base.LibuvStream, term::termios)
tcgetattr(f::Int, term::termios)
Get the tty attributes for file descriptor fd
"""
function tcgetattr(fd::RawFD, term::termios)
r = ccall(:tcgetattr, Cint, (Cint, Ptr{Cvoid}), fd, Ref(term))
r == -1 ? throw(TERMIOSError("tcgetattr failed: $(Base.Libc.strerror())")) : nothing
end
tcgetattr(s::Base.LibuvStream, term) = tcgetattr(_file_handle(s), term)
tcgetattr(f::Int, term) = tcgetattr(RawFD(f), term)

You can see they are pretty much identical.

Now, the only thing that could be different is the layout of the termios struct itself.

Can you print termios.tcgetattr(fd) in python, and print T.termios() in julia?

If there's a difference in the layout, then it is something that can be fixed in this package. If there's no difference in the layout, we'll have to ping someone on the core Julia team who has knowledge of libuv and Julia's IO system for more information about what is going on.

@kdheepak
Copy link
Owner

Interestingly the tests on Travis are passing:

https://travis-ci.com/github/kdheepak/TERMIOS.jl/jobs/287020194#L153

term = TERMIOS.termios()
TERMIOS.tcgetattr(stdin, term)
@test term.c_iflag == c_iflag
@test term.c_oflag == c_oflag
@test term.c_cflag == c_cflag
@test term.c_lflag == c_lflag
@test_broken term.c_cc == c_cc
@test term.c_ispeed == c_ispeed
@test term.c_ospeed == c_ospeed

@c42f
Copy link

c42f commented Jul 30, 2020

Regarding layout, the result of using gcc -E with the following test.c:

#include <termios.h>
#include <unistd.h>

indicates that on my system we have

typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;

struct termios
  {
    tcflag_t c_iflag;
    tcflag_t c_oflag;
    tcflag_t c_cflag;
    tcflag_t c_lflag;
    cc_t c_line;
    cc_t c_cc[32];
    speed_t c_ispeed;
    speed_t c_ospeed;
  };

All looks ABI compatible when compared to TERMIOS.termios

@c42f
Copy link

c42f commented Jul 30, 2020

Is this a problem?

julia> TERMIOS._file_handle(stdout)
RawFD(0x61636d20)

julia> stdout
Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting)

The RawFD's don't match here. There's Base._fd which can be used to return RawFD(0x0000000d), but replacing _file_handle with that leads the system to complain about ioctls instead. Which might be progress, or maybe not.

@schrauf
Copy link
Author

schrauf commented Jul 30, 2020

Ok, I also have a mismatch in my personal computer.

julia> using TERMIOS

julia> TERMIOS._file_handle(stdout)
RawFD(0x20657370)

julia> stdout
Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting)

In a remote server I also have a mismatch, but with a different output for _file_handle(stdout).

julia> using TERMIOS

julia> TERMIOS._file_handle(stdout)
RawFD(0x00000000)

julia> stdout
Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting)

If I try in the server the code suggested by @kdheepak here, then I don't get the "Bad file descriptor" error. But later when trying examples from TerminalUserInterface.jl I get the complain about ioctls which @c42f mentions.

@kdheepak
Copy link
Owner

kdheepak commented Aug 8, 2020

julia> TERMIOS._file_handle(stdout)
RawFD(0x61636d20)

julia> stdout
Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting)

So this is definitely the issue, right?

_file_handle(s::Base.LibuvStream) = ccall(:jl_uv_file_handle, Base.OS_HANDLE, (Ptr{Cvoid},), s.handle)

Any idea what we should use instead?

@c42f
Copy link

c42f commented Aug 10, 2020

Well, there's Base._fd as I noted above. It's possible this is correct, though i didn't look into it in detail.

@kdheepak
Copy link
Owner

Is IOCTL error related to this issue?

kdheepak/TerminalUserInterfaces.jl#3

If so, I can make the Base._fd changes and make a new release. It still will need fixing the IOCTL, but at least it is progress. I'll also set up a Linux VM so that I can debug this locally.

@kdheepak
Copy link
Owner

kdheepak commented Sep 6, 2020

Surprisingly I'm unable to reproduce this issue on my Ubuntu VM.

Screen Shot 2020-09-06 at 4 57 22 PM

But I've gone ahead updated to use Base._fd. I tested that on my Mac and on Ubuntu, and it seems like it works. But was working for me before I made the change as well.

I just submitted a registration request for a new version (v0.2.1) of this package: 3c32ffd. When that is merged and tagged, if others can try it out that would be great.

@kdheepak
Copy link
Owner

I'm closing this issue. I believe with the fix it should now work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants