-
-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Bug Report
What's the issue you encountered?
When a program uses the libctru thread API (e.g. threadCreate
) to manage threads, without using pthread or std::thread
, theoretically it should still be possible to use synchronization primitives from pthread or the C++ concurrency support library.
However, if something in said program uses std::mutex
for example, by default it actually does not do any synchronization. That is because libstdc++
has an intermediate abstraction called "gthread" which tries to do something "smart".
If you look into its functions, like __gthread_mutex_trylock
, they check the return value of __gthread_active_p()
:
Lines 767 to 774 in 2eb98d6
static inline int | |
__gthread_mutex_trylock (__gthread_mutex_t *__mutex) | |
{ | |
if (__gthread_active_p ()) | |
return __gthrw_(pthread_mutex_trylock) (__mutex); | |
else | |
return 0; | |
} |
Lines 260 to 266 in 2eb98d6
static inline int | |
__gthread_active_p (void) | |
{ | |
static void *const __gthread_active_ptr | |
= __extension__ (void *) >HR_ACTIVE_PROXY; | |
return __gthread_active_ptr != 0; | |
} |
Basically what it does is: reference all pthread functions with weak symbols, if a pthread function is 0 (undefined, which means pthread isn't linked into the binary) then it basically skips actually doing the synchronization the functions are supposed to be doing.
Remember that the program is using the libctru thread API directly? This means not calling pthread_create
, which means no strong reference to pthread, which means pthread isn't linked into the binary. Which means std::mutex
is effectively broken in this setup.
How can the issue be reproduced?
Test a program which uses libctru's threadCreate
to create threads and uses std::mutex
and do something that will fail if the mutex doesn't work. (Sorry, don't have time to make a self contained reproducer yet.)
Environment?
- Arch Linux
- devkitARM r65-1
Additional context?
- It's not me who wants to intentionally mix libctru thread with pthread stuff, but a third-party library that uses
std::mutex
. This issue took me many hours to track down. - I tried adding
-pthread
to the compile and link flags, but that doesn't force the pthread weak symbols to be linked. - I did find a workaround to fix this issue, which is to define
_GLIBCXX_GTHREAD_USE_WEAK=0
. This disables all the shenanigans involving weak symbols and causes__gthread_active_p()
to always return 1, so the synchronization primitives actually works.