-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Closed
Labels
multithreadingBase.Threads and related functionalityBase.Threads and related functionality
Description
There's multiple issues with @threadcall I've spotted while debugging a test.
- segfaults when printing/... in called cfunction
foo(a) = (println("$a"); Cint(42))
foo_c = cfunction(foo, Cint, (Cint,))
@show ccall(foo_c, Cint, (Cint,), 1)
@show @threadcall(foo_c, Cint, (Cint,), 1)Probably by design, but the docs don't mention such a restriction.
- argument passing botched
foo(a,b) = (Cint(a+b))
foo_c = cfunction(foo, Cint, (Cint,Cint))
@show ccall(foo_c, Cint, (Cint,Cint), 1, 2)
@show @threadcall(foo_c, Cint, (Cint,Cint), 1, 2) # returns 2The reason is a missing ptr adjustment when creating the args array in do_threadcall:
# cconvert, root and unsafe_convert arguments
roots = Any[]
args_size = isempty(argtypes) ? 0 : sum(sizeof, argtypes)
args_arr = Array{UInt8}(args_size)
ptr = pointer(args_arr)
for (T, x) in zip(argtypes, argvals)
y = cconvert(T, x)
push!(roots, y)
unsafe_store!(convert(Ptr{T}, ptr), unsafe_convert(T, y))
ptr += sizeof(T) # ADDED
end- example 2 often deadlocks
When debugging 2) by adding some print statements to do_threadcall, Julia easily locked up. Not sure whether or not this is expected, but I thought I'd mention it anyway.
import Base: do_threadcall
import Base: cconvert, unsafe_convert,
acquire, threadcall_restrictor,
thread_notifiers, c_notify_fun, release
function do_threadcall(wrapper::Function, rettype::Type, argtypes::Vector, argvals::Vector)
# generate function pointer
fun_ptr = cfunction(wrapper, Int, (Ptr{Void}, Ptr{Void}))
# cconvert, root and unsafe_convert arguments
roots = Any[]
args_size = isempty(argtypes) ? 0 : sum(sizeof, argtypes)
args_arr = Array{UInt8}(args_size)
ptr = pointer(args_arr)
for (T, x) in zip(argtypes, argvals)
y = cconvert(T, x)
push!(roots, y)
unsafe_store!(convert(Ptr{T}, ptr), unsafe_convert(T, y))
ptr += sizeof(T) # ADDED
end
# create return buffer
ret_arr = Array{UInt8}(sizeof(rettype))
# wait for a worker thread to be available
acquire(threadcall_restrictor)
idx = findfirst(isnull, thread_notifiers)
thread_notifiers[idx] = Nullable{Condition}(Condition())
# queue up the work to be done
println("queue work")
ccall(:jl_queue_work, Void,
(Ptr{Void}, Ptr{UInt8}, Ptr{UInt8}, Ptr{Void}, Cint),
fun_ptr, args_arr, ret_arr, c_notify_fun, idx)
# wait for a result & return it
println("wait for it")
wait(get(thread_notifiers[idx]))
thread_notifiers[idx] = Nullable{Condition}()
release(threadcall_restrictor)
unsafe_load(convert(Ptr{rettype}, pointer(ret_arr)))
end
using Base.Test
foo(a,b) = (Cint(a+b))
foo_c = cfunction(foo, Cint, (Cint,Cint))
@show ccall(foo_c, Cint, (Cint,Cint), 1, 2)
@show @threadcall(foo_c, Cint, (Cint,Cint), 1, 2)Tested on latest master.
Metadata
Metadata
Assignees
Labels
multithreadingBase.Threads and related functionalityBase.Threads and related functionality