Skip to content

Commit 6468dcb

Browse files
maleadtvchuravy
andauthored
Lock cfunction trampoline cache and freelist accesses. (#39621)
Co-authored-by: Valentin Churavy <v.churavy@gmail.com>
1 parent 62a3b26 commit 6468dcb

File tree

2 files changed

+11
-9
lines changed

2 files changed

+11
-9
lines changed

src/runtime_ccall.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,11 @@ extern "C" JL_DLLEXPORT char *jl_format_filename(const char *output_pattern)
210210
}
211211

212212

213+
static jl_mutex_t trampoline_lock; // for accesses to the cache and freelist
214+
213215
static void *trampoline_freelist;
214216

215-
static void *trampoline_alloc()
217+
static void *trampoline_alloc() // lock taken by caller
216218
{
217219
const int sz = 64; // oversized for most platforms. todo: use precise value?
218220
if (!trampoline_freelist) {
@@ -245,7 +247,7 @@ static void *trampoline_alloc()
245247
return tramp;
246248
}
247249

248-
static void trampoline_free(void *tramp)
250+
static void trampoline_free(void *tramp) // lock taken by caller
249251
{
250252
*(void**)tramp = trampoline_freelist;
251253
trampoline_freelist = tramp;
@@ -260,17 +262,18 @@ static void trampoline_deleter(void **f)
260262
f[0] = NULL;
261263
f[2] = NULL;
262264
f[3] = NULL;
265+
JL_LOCK_NOGC(&trampoline_lock);
263266
if (tramp)
264267
trampoline_free(tramp);
265268
if (fobj && cache)
266269
ptrhash_remove((htable_t*)cache, fobj);
267270
if (nval)
268271
free(nval);
272+
JL_UNLOCK_NOGC(&trampoline_lock);
269273
}
270274

271275
// Use of `cache` is not clobbered in JL_TRY
272276
JL_GCC_IGNORE_START("-Wclobbered")
273-
// TODO: need a thread lock around the cache access parts of this function
274277
extern "C" JL_DLLEXPORT
275278
jl_value_t *jl_get_cfunction_trampoline(
276279
// dynamic inputs:
@@ -284,6 +287,7 @@ jl_value_t *jl_get_cfunction_trampoline(
284287
jl_value_t **vals)
285288
{
286289
// lookup (fobj, vals) in cache
290+
JL_LOCK_NOGC(&trampoline_lock);
287291
if (!cache->table)
288292
htable_new(cache, 1);
289293
if (fill != jl_emptysvec) {
@@ -295,6 +299,7 @@ jl_value_t *jl_get_cfunction_trampoline(
295299
}
296300
}
297301
void *tramp = ptrhash_get(cache, (void*)fobj);
302+
JL_UNLOCK_NOGC(&trampoline_lock);
298303
if (tramp != HT_NOTFOUND) {
299304
assert((jl_datatype_t*)jl_typeof(tramp) == result_type);
300305
return (jl_value_t*)tramp;
@@ -347,10 +352,12 @@ jl_value_t *jl_get_cfunction_trampoline(
347352
free(nval);
348353
jl_rethrow();
349354
}
355+
JL_LOCK_NOGC(&trampoline_lock);
350356
tramp = trampoline_alloc();
351357
((void**)result)[0] = tramp;
352358
tramp = init_trampoline(tramp, nval);
353359
ptrhash_put(cache, (void*)fobj, result);
360+
JL_UNLOCK_NOGC(&trampoline_lock);
354361
return result;
355362
}
356363
JL_GCC_IGNORE_STOP

test/threads_exec.jl

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,6 @@ end
471471

472472
function test_thread_cfunction()
473473
# ensure a runtime call to `get_trampoline` will be created
474-
# TODO: get_trampoline is not thread-safe (as this test shows)
475474
fs = [ Core.Box() for i in 1:1000 ]
476475
@noinline cf(f) = @cfunction $f Float64 ()
477476
cfs = Vector{Base.CFunction}(undef, length(fs))
@@ -494,11 +493,7 @@ function test_thread_cfunction()
494493
@test sum(ok) == 10000
495494
end
496495
if cfunction_closure
497-
if nthreads() == 1
498-
test_thread_cfunction()
499-
else
500-
@test_broken "cfunction trampoline code not thread-safe"
501-
end
496+
test_thread_cfunction()
502497
end
503498

504499
# Compare the two ways of checking if threading is enabled.

0 commit comments

Comments
 (0)