+#ifndef USE_CTRULIB_2
+/* Backported CondVar API from libctru 2.0, and under its license:
+ https://github.com/devkitPro/libctru
+ Slightly modified for compatibility with older libctru. */
+
+typedef s32 CondVar;
+
+static inline Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
+{
+ return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);
+}
+
+static inline Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
+{
+ return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);
+}
+
+static inline void __dmb(void)
+{
+ __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
+}
+
+static inline void CondVar_BeginWait(CondVar* cv, LightLock* lock)
+{
+ s32 val;
+ do
+ val = __ldrex(cv) - 1;
+ while (__strex(cv, val));
+ LightLock_Unlock(lock);
+}
+
+static inline bool CondVar_EndWait(CondVar* cv, s32 num_threads)
+{
+ bool hasWaiters;
+ s32 val;
+
+ do {
+ val = __ldrex(cv);
+ hasWaiters = val < 0;
+ if (hasWaiters)
+ {
+ if (num_threads < 0)
+ val = 0;
+ else if (val <= -num_threads)
+ val += num_threads;
+ else
+ val = 0;
+ }
+ } while (__strex(cv, val));
+
+ return hasWaiters;
+}
+
+static inline void CondVar_Init(CondVar* cv)
+{
+ *cv = 0;
+}
+
+static inline void CondVar_Wait(CondVar* cv, LightLock* lock)
+{
+ CondVar_BeginWait(cv, lock);
+ syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
+ LightLock_Lock(lock);
+}
+
+static inline int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
+{
+ CondVar_BeginWait(cv, lock);
+
+ bool timedOut = false;
+ Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
+ if (R_DESCRIPTION(rc) == RD_TIMEOUT)
+ {
+ timedOut = CondVar_EndWait(cv, 1);
+ __dmb();
+ }
+
+ LightLock_Lock(lock);
+ return timedOut;
+}
+
+static inline void CondVar_WakeUp(CondVar* cv, s32 num_threads)
+{
+ __dmb();
+ if (CondVar_EndWait(cv, num_threads))
+ syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
+ else
+ __dmb();
+}
+
+static inline void CondVar_Signal(CondVar* cv)
+{
+ CondVar_WakeUp(cv, 1);
+}
+
+static inline void CondVar_Broadcast(CondVar* cv)
+{
+ CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
+}
+/* End libctru 2.0 backport */
+#endif
+
+/* libctru threads return void but pthreads return void pointer */
+static bool mutex_inited = false;
+static LightLock safe_double_thread_launch;
+static void *(*start_routine_jump)(void*);
+
+static void ctr_thread_launcher(void* data)
+{
+ void *(*start_routine_jump_safe)(void*) = start_routine_jump;
+ LightLock_Unlock(&safe_double_thread_launch);
+ start_routine_jump_safe(data);
+}