# How to read without blocking

**URL:** https://discourse.julialang.org/t/how-to-read-without-blocking/81409
**Category:** General Usage
**Tags:** question
**Created:** [May 21, 2022, 10:33am UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409 "2022-05-21T10:33:15Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 21, 2022, 10:33am UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/1 "2022-05-21T10:33:15Z")

</div>

How can I read from an input device on Linux in a non-blocking way, perhaps with a timeout?

I have this function:

```julia
function read_event(js::JSDevice)
    event = read(js.device, sizeof(JSEvent); all = false)
    if sizeof(event) != sizeof(JSEvent)
        return nothing
    end
    reinterpret(JSEvent, event)[]
end

```

It never returns `nothing`, instead it blocks until the correct amount of bytes are available.

Is there a way to check how many bytes are available for reading before reading?

Full code: [Joysticks.jl/Joysticks.jl at main · ufechner7/Joysticks.jl · GitHub](https://github.com/ufechner7/Joysticks.jl/blob/main/src/Joysticks.jl)

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 21, 2022, 10:41am UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/2 "2022-05-21T10:41:23Z")

</div>

In the documentation of the C api it says:

```julia
3. Reading
~~~~~~~~~~

If you open the device in blocking mode, a read will block (that is,
wait) forever until an event is generated and effectively read. There
are two alternatives if you can't afford to wait forever (which is,
admittedly, a long time;)

	a) use select to wait until there's data to be read on fd, or
	   until it timeouts. There's a good example on the select(2)
	   man page.

	b) open the device in non-blocking mode (O_NONBLOCK)

```

But how can I open the device in non-blocking mode?  
My current code:

```julia
            file = open(filename, "r+")
            device = JSDevice(file, fd(file), 0, 0)

```

For the `open` function of Julia I could not find any option O\_NONBLOCK …

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [May 21, 2022, 11:20am UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/3 "2022-05-21T11:20:32Z")

</div>

> [@ufechner7](#):
>
> How can I read from an input device on Linux in a non-blocking way

Normally in Julia you would use an `@async` task (a green thread). The task will wake up when bytes are available to read.

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 21, 2022, 11:31am UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/4 "2022-05-21T11:31:29Z")

</div>

Well, I tried, but it does not work, because while the read command is blocking no other Julia code is being executed.

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 21, 2022, 12:38pm UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/5 "2022-05-21T12:38:57Z")

</div>

What I need is the Julia equivalent or translation of this C code:

```julia
js = open(device, O_RDONLY | O_NONBLOCK);

```

This does not work:

```julia
file = open(filename, "r+")

```

Found this open issue in Julia: [Review of IO blocking behaviour · Issue #24526 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/24526)  
Anybody around who knows how to translate C code to Julia?

---

<div class="post-metadata">

### Author: ![paulmelis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paulmelis/32/35063_2.png) [@paulmelis](https://discourse.julialang.org/u/paulmelis)
#### Post date: [May 21, 2022, 1:09pm UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/6 "2022-05-21T13:09:34Z")

</div>

> [@ufechner7](#):
>
> Anybody around who knows how to translate C code to Julia?

You can use `ccall()` to directly call the underlying functions yourself. Since (I guess) you only need to open, close and read from the joystick device file something like this would do it:

```julia
O_RDONLY = 0
O_NONBLOCK = 2048

jfd = ccall(:open, Cint, (Cstring, Cint), "/dev/input/js0", O_RDONLY|O_NONBLOCK)
println("fd = $(jfd)")

N = 100
buf = Vector{UInt8}(undef, N)

# Loop until we read succesfully 5 times
count = 0
while count < 5

    # ssize_t read(int fd, void *buf, size_t count)
    res = ccall(:read, Cssize_t, (Cint, Ptr{Cuchar}, Csize_t), jfd, buf, N)
    
    if res != -1        
        println("read() returned $(res) bytes")
        println(buf[1:res])
        global count += 1
    end
    
end

ccall(:close, Cint, (Cint,), jfd)

```

With a gamepad attached to my system I get output like this:

```julia
melis@juggle 15:06:~$ julia t.jl
fd = 18
# Initial joystick data returned
read() returned 96 bytes
UInt8[0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x00, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x01, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x02, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x03, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x04, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x05, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x06, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x07, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x08, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x09, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x81, 0x0a, 0xcb, 0x6d, 0xc0, 0x55, 0x00, 0x00, 0x82, 0x00, 0x00]
read() returned 56 bytes
UInt8[0x43, 0x6e, 0xc0, 0x55, 0xfe, 0xff, 0x82, 0x01, 0x43, 0x6e, 0xc0, 0x55, 0x01, 0x80, 0x82, 0x02, 0x43, 0x6e, 0xc0, 0x55, 0x00, 0x00, 0x82, 0x03, 0x43, 0x6e, 0xc0, 0x55, 0xfe, 0xff, 0x82, 0x04, 0x43, 0x6e, 0xc0, 0x55, 0x01, 0x80, 0x82, 0x05, 0x43, 0x6e, 0xc0, 0x55, 0x00, 0x00, 0x82, 0x06, 0x43, 0x6e, 0xc0, 0x55, 0x00, 0x00, 0x82, 0x07, 0xcb]
# read() continuously returns -1 within the loop, until I trigger the joystick again
read() returned 8 bytes
UInt8[0x5a, 0x73, 0xc0, 0x55, 0xdd, 0xf4, 0x02, 0x00, 0x43]
read() returned 8 bytes
UInt8[0x61, 0x73, 0xc0, 0x55, 0xb0, 0xe5, 0x02, 0x00, 0x43]
read() returned 8 bytes
UInt8[0x68, 0x73, 0xc0, 0x55, 0x80, 0xd5, 0x02, 0x00, 0x43]

```

You would then have to map the returned bytes to the actual joystick data you need, but hopefully this is a start.

Edit: and to verify that this indeed opens the device file with the correct options:

```julia
melis@juggle 15:10:~$ strace julia t.jl 2>&1 | grep js0
openat(AT_FDCWD, "/dev/input/js0", O_RDONLY|O_NONBLOCK) = 16

```

Edit 2: fixed off-by-one in indexing `buf`, due to my Python habits 😉

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [May 21, 2022, 1:41pm UTC](https://discourse.julialang.org/t/how-to-read-without-blocking/81409/7 "2022-05-21T13:41:31Z")

</div>

The following code works:

```julia
const O_RDONLY = 0
const O_NONBLOCK = 2048

function open_joystick(filename = "/dev/input/js0")
    if Sys.islinux()
        if ispath(filename)
            jfd = ccall(:open, Cint, (Cstring, Cint), filename, O_RDONLY|O_NONBLOCK)
            device = JSDevice(filename, jfd, 0, 0)
            device.axis_count = axis_count(device) 
            device.button_count = button_count(device)
            return device
        else
            println("ERROR: The device $filename does not exist!")
            return nothing
        end
    else
        error("Currently Joystick.jl supports only Linux!")
        nothing
    end
end

```

```julia
function read_event(js::JSDevice)
    event = Vector{UInt8}(undef, sizeof(JSEvent))
    res = ccall(:read, Cssize_t, (Cint, Ptr{Cuchar}, Csize_t), js.fd, event, sizeof(JSEvent))
    if res == -1    
        return nothing
    end
    reinterpret(JSEvent, event)[]
end

```

Complete code: [GitHub - ufechner7/Joysticks.jl: Joystick interface for Julia](https://github.com/ufechner7/Joysticks.jl)

Thank you very much! 🙂
