[llvm-dev] call_once and TSan
Dmitry Vyukov via llvm-dev
llvm-dev at lists.llvm.org
Fri Sep 2 05:33:46 PDT 2016
On Fri, Sep 2, 2016 at 2:21 PM, Kuba Brecka <kuba.brecka at gmail.com> wrote:
> Same problem exists, thread A can still be within REAL(call_once), but after it ran user code and set the flag to ~0. Roughly, call_once does:
>
> __call_once(flag, arg, func) {
> mutex_lock(mut);
> if (flag == BEING_INITIALIZED) { wait }
> else if (flag == NOT_INITIALIZED_AT_ALL) {
> flag = BEING_INITIALIZED;
> mutex_unlock(mut);
> func(arg); // <=== user code callback
> mutex_lock(mut);
> atomic_store(&flag, FULLY_INITIALIZED, mo_release); // "release" store, but within a compiled dylib, thus invisible to TSan
> }
> mutex_unlock(mut);
> }
>
> If thread A is just after the release store, which is invisible to TSan, __tsan_acquire in thread B will have no effect, and the stores from the callback to func(arg) will not be synchronized to thread B.
right
> Anyway, I just realized that we can wrap "func" into our own callback, which will perform the (extra) __tsan_release... Do you think that would work? E.g.:
>
> void call_once_callback_wrapper(...) {
> orig_func(orig_arg);
> __tsan_release(flag);
> }
>
> INTERCEPTOR(call_once, o, func, arg) {
> REAL(call_once)(flag, ..., call_once_callback_wrapper);
> }
this should work
but I am obviously bad at thinking today
More information about the llvm-dev
mailing list