@@ -91,64 +91,71 @@ render_arg(io, arg::Base.RefValue{T}) where {T} = print(io, "Ref{", T, "}")
91
91
92
92
93
93
# # version of ccall that calls jl_gc_safe_enter|leave around the inner ccall
94
-
95
- # TODO : replace with JuliaLang/julia#49933 once merged
96
-
97
94
# note that this is generally only safe with functions that do not call back into Julia.
98
95
# when callbacks occur, the code should ensure the GC is not running by wrapping the code
99
96
# in the `@gcunsafe` macro
100
97
101
- function ccall_macro_lower (func, rettype, types, args, nreq)
102
- # instead of re-using ccall or Expr(:foreigncall) to perform argument conversion,
103
- # we need to do so ourselves in order to insert a jl_gc_safe_enter|leave
104
- # just around the inner ccall
105
-
106
- cconvert_exprs = []
107
- cconvert_args = []
108
- for (typ, arg) in zip (types, args)
109
- var = gensym (" $(func) _cconvert" )
110
- push! (cconvert_args, var)
111
- push! (cconvert_exprs, :($ var = Base. cconvert ($ (esc (typ)), $ (esc (arg)))))
112
- end
113
-
114
- unsafe_convert_exprs = []
115
- unsafe_convert_args = []
116
- for (typ, arg) in zip (types, cconvert_args)
117
- var = gensym (" $(func) _unsafe_convert" )
118
- push! (unsafe_convert_args, var)
119
- push! (unsafe_convert_exprs, :($ var = Base. unsafe_convert ($ (esc (typ)), $ arg)))
120
- end
121
-
122
- call = quote
123
- $ (unsafe_convert_exprs... )
124
-
125
- gc_state = @ccall (jl_gc_safe_enter ():: Int8 )
126
- ret = ccall (
127
- $ (esc (func)), $ (esc (rettype)), $ (Expr (:tuple , map (esc, types)... )),
128
- $ (unsafe_convert_args... )
129
- )
130
- @ccall (jl_gc_safe_leave (gc_state:: Int8 ):: Cvoid )
131
- ret
132
- end
133
-
134
- return quote
135
- @inline
136
- $ (cconvert_exprs... )
137
- GC. @preserve $ (cconvert_args... ) $ (call)
138
- end
139
- end
98
+ const HAS_CCALL_GCSAFE = VERSION >= v " 1.13.0-DEV.70" || v " 1.12-DEV.2029" <= VERSION < v " 1.13-"
140
99
141
100
"""
142
- @gcsafe_ccall ...
101
+ @gcsafe_ccall ...
143
102
144
103
Call a foreign function just like `@ccall`, but marking it safe for the GC to run. This is
145
104
useful for functions that may block, so that the GC isn't blocked from running, but may also
146
105
be required to prevent deadlocks (see JuliaGPU/CUDA.jl#2261).
147
106
148
107
Note that this is generally only safe with non-Julia C functions that do not call back into
149
- Julia. When using callbacks, the code should make sure to transition back into GC-unsafe
150
- mode using the `@gcunsafe` macro.
108
+ the Julia directly.
151
109
"""
152
- macro gcsafe_ccall (expr)
153
- return ccall_macro_lower (Base. ccall_macro_parse (expr)... )
154
- end
110
+ macro gcsafe_ccall end
111
+
112
+ if HAS_CCALL_GCSAFE
113
+ macro gcsafe_ccall (expr)
114
+ exprs = Any[:(gc_safe = true ), expr]
115
+ return Base. ccall_macro_lower ((:ccall ), Base. ccall_macro_parse (exprs)... )
116
+ end
117
+ else
118
+ function ccall_macro_lower (func, rettype, types, args, nreq)
119
+ # instead of re-using ccall or Expr(:foreigncall) to perform argument conversion,
120
+ # we need to do so ourselves in order to insert a jl_gc_safe_enter|leave
121
+ # just around the inner ccall
122
+
123
+ cconvert_exprs = []
124
+ cconvert_args = []
125
+ for (typ, arg) in zip (types, args)
126
+ var = gensym (" $(func) _cconvert" )
127
+ push! (cconvert_args, var)
128
+ push! (cconvert_exprs, :($ var = Base. cconvert ($ (esc (typ)), $ (esc (arg)))))
129
+ end
130
+
131
+ unsafe_convert_exprs = []
132
+ unsafe_convert_args = []
133
+ for (typ, arg) in zip (types, cconvert_args)
134
+ var = gensym (" $(func) _unsafe_convert" )
135
+ push! (unsafe_convert_args, var)
136
+ push! (unsafe_convert_exprs, :($ var = Base. unsafe_convert ($ (esc (typ)), $ arg)))
137
+ end
138
+
139
+ call = quote
140
+ $ (unsafe_convert_exprs... )
141
+
142
+ gc_state = @ccall (jl_gc_safe_enter ():: Int8 )
143
+ ret = ccall (
144
+ $ (esc (func)), $ (esc (rettype)), $ (Expr (:tuple , map (esc, types)... )),
145
+ $ (unsafe_convert_args... )
146
+ )
147
+ @ccall (jl_gc_safe_leave (gc_state:: Int8 ):: Cvoid )
148
+ ret
149
+ end
150
+
151
+ return quote
152
+ @inline
153
+ $ (cconvert_exprs... )
154
+ GC. @preserve $ (cconvert_args... ) $ (call)
155
+ end
156
+ end
157
+
158
+ macro gcsafe_ccall (expr)
159
+ return ccall_macro_lower (Base. ccall_macro_parse (expr)... )
160
+ end
161
+ end # HAS_CCALL_GCSAFE
0 commit comments