-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
add dedicated IO thread (capability only) #53422
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
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: