@@ -4,12 +4,6 @@ const max_ccall_threads = parse(Int, get(ENV, "UV_THREADPOOL_SIZE", "4"))
44const thread_notifiers = Union{Condition, Nothing}[nothing for i in 1 : max_ccall_threads]
55const threadcall_restrictor = Semaphore (max_ccall_threads)
66
7- function notify_fun (idx)
8- global thread_notifiers
9- notify (thread_notifiers[idx])
10- return
11- end
12-
137"""
148 @threadcall((cfunc, clib), rettype, (argtypes...), argvals...)
159
@@ -36,62 +30,71 @@ macro threadcall(f, rettype, argtypes, argvals...)
3630 argvals = map (esc, argvals)
3731
3832 # construct non-allocating wrapper to call C function
39- wrapper = :(function wrapper (args_ptr:: Ptr{Cvoid} , retval_ptr:: Ptr{Cvoid} )
33+ wrapper = :(function (args_ptr:: Ptr{Cvoid} , retval_ptr:: Ptr{Cvoid} )
4034 p = args_ptr
35+ # the rest of the body is created below
4136 end )
4237 body = wrapper. args[2 ]. args
4338 args = Symbol[]
44- for (i,T) in enumerate (argtypes)
39+ for (i, T) in enumerate (argtypes)
4540 arg = Symbol (" arg" , i)
4641 push! (body, :($ arg = unsafe_load (convert (Ptr{$ T}, p))))
47- push! (body, :(p += sizeof ($ T)))
42+ push! (body, :(p += Core . sizeof ($ T)))
4843 push! (args, arg)
4944 end
5045 push! (body, :(ret = ccall ($ f, $ rettype, ($ (argtypes... ),), $ (args... ))))
5146 push! (body, :(unsafe_store! (convert (Ptr{$ rettype}, retval_ptr), ret)))
52- push! (body, :(return sizeof ($ rettype)))
47+ push! (body, :(return Int (Core . sizeof ($ rettype) )))
5348
5449 # return code to generate wrapper function and send work request thread queue
55- :( let
56- $ wrapper
57- do_threadcall (wrapper , $ rettype, Any[$ (argtypes... )], Any[$ (argvals... )])
50+ wrapper = Expr ( Symbol ( " hygienic-scope " ), wrapper, @__MODULE__ )
51+ return :( let fun_ptr = @cfunction ( $ wrapper, Int, (Ptr{Cvoid}, Ptr{Cvoid}))
52+ do_threadcall (fun_ptr , $ rettype, Any[$ (argtypes... )], Any[$ (argvals... )])
5853 end )
5954end
6055
61- function do_threadcall (wrapper :: Function , rettype:: Type , argtypes:: Vector , argvals:: Vector )
56+ function do_threadcall (fun_ptr :: Ptr{Cvoid} , rettype:: Type , argtypes:: Vector , argvals:: Vector )
6257 # generate function pointer
63- fun_ptr = cfunction (wrapper, Int, Tuple{Ptr{Cvoid}, Ptr{Cvoid}})
64- c_notify_fun = cfunction (notify_fun, Cvoid, Tuple{Cint})
58+ c_notify_fun = @cfunction (
59+ function notify_fun (idx)
60+ global thread_notifiers
61+ notify (thread_notifiers[idx])
62+ return
63+ end , Cvoid, (Cint,))
6564
6665 # cconvert, root and unsafe_convert arguments
6766 roots = Any[]
68- args_size = isempty (argtypes) ? 0 : sum (sizeof, argtypes)
67+ args_size = isempty (argtypes) ? 0 : sum (Core . sizeof, argtypes)
6968 args_arr = Vector {UInt8} (undef, args_size)
7069 ptr = pointer (args_arr)
7170 for (T, x) in zip (argtypes, argvals)
71+ isbits (T) || throw (ArgumentError (" threadcall requires isbits argument types" ))
7272 y = cconvert (T, x)
7373 push! (roots, y)
74- unsafe_store! (convert (Ptr{T}, ptr), unsafe_convert (T, y))
75- ptr += sizeof (T)
74+ unsafe_store! (convert (Ptr{T}, ptr), unsafe_convert (T, y):: T )
75+ ptr += Core . sizeof (T)
7676 end
7777
7878 # create return buffer
79- ret_arr = Vector {UInt8} (undef, sizeof (rettype))
79+ ret_arr = Vector {UInt8} (undef, Core . sizeof (rettype))
8080
8181 # wait for a worker thread to be available
8282 acquire (threadcall_restrictor)
8383 idx = findfirst (isequal (nothing ), thread_notifiers):: Int
8484 thread_notifiers[idx] = Condition ()
8585
86- # queue up the work to be done
87- ccall (:jl_queue_work , Cvoid,
88- (Ptr{Cvoid}, Ptr{UInt8}, Ptr{UInt8}, Ptr{Cvoid}, Cint),
89- fun_ptr, args_arr, ret_arr, c_notify_fun, idx)
86+ GC. @preserve args_arr ret_arr roots begin
87+ # queue up the work to be done
88+ ccall (:jl_queue_work , Cvoid,
89+ (Ptr{Cvoid}, Ptr{UInt8}, Ptr{UInt8}, Ptr{Cvoid}, Cint),
90+ fun_ptr, args_arr, ret_arr, c_notify_fun, idx)
9091
91- # wait for a result & return it
92- wait (thread_notifiers[idx])
93- thread_notifiers[idx] = nothing
94- release (threadcall_restrictor)
92+ # wait for a result & return it
93+ wait (thread_notifiers[idx])
94+ thread_notifiers[idx] = nothing
95+ release (threadcall_restrictor)
9596
96- unsafe_load (convert (Ptr{rettype}, pointer (ret_arr)))
97+ r = unsafe_load (convert (Ptr{rettype}, pointer (ret_arr)))
98+ end
99+ return r
97100end
0 commit comments