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

send() / recv() on UDPSocket is not async-safe #57001

Open
ettersi opened this issue Jan 9, 2025 · 1 comment
Open

send() / recv() on UDPSocket is not async-safe #57001

ettersi opened this issue Jan 9, 2025 · 1 comment

Comments

@ettersi
Copy link
Contributor

ettersi commented Jan 9, 2025

The following code tries to send a UDP packet to socat -v PIPE udp-recvfrom:9809,fork and then receive the echo response, but it consistently fails.

julia> using Sockets

julia> sock = UDPSocket()
       bind(sock, ip"127.0.0.1", 0)

       errormonitor(@async println(String(recv(sock))))
       send(sock, ip"127.0.0.1", 9809, "hello")

       sleep(1)
       close(sock)

Unhandled Task ERROR: EOFError: read end of file
Stacktrace:
 [1] try_yieldto(undo::typeof(Base.ensure_rescheduled))
   @ Base ./task.jl:958
 [2] wait()
   @ Base ./task.jl:1022
 [3] wait(c::Base.GenericCondition{Base.Threads.SpinLock}; first::Bool)
   @ Base ./condition.jl:130
 [4] wait
   @ ./condition.jl:125 [inlined]
 [5] recvfrom(sock::UDPSocket)
   @ Sockets ~/.julia/juliaup/julia-1.11.2+0.x64.apple.darwin14/share/julia/stdlib/v1.11/Sockets/src/Sockets.jl:359
 [6] recv
   @ ~/.julia/juliaup/julia-1.11.2+0.x64.apple.darwin14/share/julia/stdlib/v1.11/Sockets/src/Sockets.jl:324 [inlined]
 [7] (::var"#7#8")()
   @ Main ./REPL[6]:4

The problem is that the send() "activates" the UDP socket and yields to the async task, and then the recv() notices that the socket is already "active" and skips registering the libuv callback.

if ccall(:uv_is_active, Cint, (Ptr{Cvoid},), sock.handle) == 0
err = ccall(:uv_udp_recv_start, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}),
sock,
@cfunction(Base.uv_alloc_buf, Cvoid, (Ptr{Cvoid}, Csize_t, Ptr{Cvoid})),
@cfunction(uv_recvcb, Cvoid, (Ptr{Cvoid}, Cssize_t, Ptr{Cvoid}, Ptr{Cvoid}, Cuint)))

Original discussion: https://discourse.julialang.org/t/async-udp-socket-usage/

@ettersi
Copy link
Contributor Author

ettersi commented Jan 9, 2025

For what it's worth, the "active" check was introduced a decade(!) ago due to this issue: #6505

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

1 participant