-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
add dedicated IO thread (capability only) #53422
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
Conversation
function make_io_thread()
tid = UInt[0]
threadwork = @cfunction function(arg::Ptr{Cvoid})
@CCall jl_set_io_loop_tid((Threads.threadid() - 1)::Int16)::Cvoid
wait() # spin uv_run as long as needed
nothing
end Cvoid (Ptr{Cvoid},)
err = @CCall uv_thread_create(tid::Ptr{UInt}, threadwork::Ptr{Cvoid}, C_NULL::Ptr{Cvoid})::Cint
err == 0 || Base.uv_error("uv_thread_create", err)
tid[]
end
IanButterworth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds great. Given this adds capability and you've given a tidy example, should that go in as a test, at least until an API is provided that can be used for the test?
|
I don't really trust threading to be stable enough to run a test for it. Gabriel has an existing PR to fix some of the threading bugs, so this PR is really only intended to help someone in the future to implement this by providing an example. |
|
Is this a minor enough change with a NFC default state to backport to 1.11 as experimental & undocumented? |
It has been oft-requested that we have a dedicated IO thread. That
actually turns out to already be the case of something that exists,
except that we hard-code the identity of that thread as being thread 0.
This PR replaces all of the places where we hard code that assumption
with a variable so that they are more easily searched for in the code.
It also adds an internal function (`jl_set_io_loop_tid`) that can be
used to transfer ownership of the loop to any (valid) tid. In
conjunction with the prior foreign-threads work and foreign-thread pool,
this lets us spawn a dedicate IO-management thread with this bit of
code:
```julia
function make_io_thread()
tid = UInt[0]
threadwork = @cfunction function(arg::Ptr{Cvoid})
Base.errormonitor(current_task()) # this may not go particularly well if the IO loop is dead, but try anyways
@CCall jl_set_io_loop_tid((Threads.threadid() - 1)::Int16)::Cvoid
wait() # spin uv_run as long as needed
nothing
end Cvoid (Ptr{Cvoid},)
err = @CCall uv_thread_create(tid::Ptr{UInt}, threadwork::Ptr{Cvoid}, C_NULL::Ptr{Cvoid})::Cint
err == 0 || Base.uv_error("uv_thread_create", err)
@CCall uv_thread_detach(tid::Ptr{UInt})::Cint
err == 0 || Base.uv_error("uv_thread_detach", err)
# n.b. this does not wait for the thread to start or to take ownership of the event loop
nothing
end
```
It has been oft-requested that we have a dedicated IO thread. That
actually turns out to already be the case of something that exists,
except that we hard-code the identity of that thread as being thread 0.
This PR replaces all of the places where we hard code that assumption
with a variable so that they are more easily searched for in the code.
It also adds an internal function (`jl_set_io_loop_tid`) that can be
used to transfer ownership of the loop to any (valid) tid. In
conjunction with the prior foreign-threads work and foreign-thread pool,
this lets us spawn a dedicate IO-management thread with this bit of
code:
```julia
function make_io_thread()
tid = UInt[0]
threadwork = @cfunction function(arg::Ptr{Cvoid})
Base.errormonitor(current_task()) # this may not go particularly well if the IO loop is dead, but try anyways
@CCall jl_set_io_loop_tid((Threads.threadid() - 1)::Int16)::Cvoid
wait() # spin uv_run as long as needed
nothing
end Cvoid (Ptr{Cvoid},)
err = @CCall uv_thread_create(tid::Ptr{UInt}, threadwork::Ptr{Cvoid}, C_NULL::Ptr{Cvoid})::Cint
err == 0 || Base.uv_error("uv_thread_create", err)
@CCall uv_thread_detach(tid::Ptr{UInt})::Cint
err == 0 || Base.uv_error("uv_thread_detach", err)
# n.b. this does not wait for the thread to start or to take ownership of the event loop
nothing
end
```
|
FWIW, the example given above currently reliably |
|
It does not segfault, but the |
It has been oft-requested that we have a dedicated IO thread. That actually turns out to already be the case of something that exists, except that we hard-code the identity of that thread as being thread 0. This PR replaces all of the places where we hard code that assumption with a variable so that they are more easily searched for in the code. It also adds an internal function (
jl_set_io_loop_tid) that can be used to transfer ownership of the loop to any (valid) tid. In conjunction with the prior foreign-threads work and foreign-thread pool, this lets us spawn a dedicate IO-management thread with this bit of code: