-// Copyright (C) 2002, 2004, 2006, 2008, 2009, 2010, 2011, 2012
-// Free Software Foundation, Inc.
+// Copyright (C) 2002-2024 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
#include <cxxabi.h>
#include <exception>
#include <new>
+
+#ifdef __USING_MCFGTHREAD__
+
+#include <mcfgthread/cxa.h>
+
+namespace __cxxabiv1 {
+
+extern "C" int
+__cxa_guard_acquire (__guard* g) _GLIBCXX_NOTHROW
+ {
+ return __MCF_cxa_guard_acquire(g);
+ }
+
+extern "C" void
+__cxa_guard_release (__guard* g) _GLIBCXX_NOTHROW
+ {
+ __MCF_cxa_guard_release(g);
+ }
+
+extern "C" void
+__cxa_guard_abort (__guard* g) _GLIBCXX_NOTHROW
+ {
+ __MCF_cxa_guard_abort(g);
+ }
+
+} // namespace __cxxabiv1
+
+#else // __USING_MCFGTHREAD__
+
#include <ext/atomicity.h>
#include <ext/concurrence.h>
+#include <bits/atomic_lockfree_defines.h>
#if defined(__GTHREADS) && defined(__GTHREAD_HAS_COND) \
&& (ATOMIC_INT_LOCK_FREE > 1) && defined(_GLIBCXX_HAVE_LINUX_FUTEX)
# include <climits>
# endif
# ifndef _GLIBCXX_GUARD_TEST_AND_ACQUIRE
+
+// Test the guard variable with a memory load with
+// acquire semantics.
+
inline bool
__test_and_acquire (__cxxabiv1::__guard *g)
{
- bool b = _GLIBCXX_GUARD_TEST (g);
- _GLIBCXX_READ_MEM_BARRIER;
- return b;
+ unsigned char __c;
+ unsigned char *__p = reinterpret_cast<unsigned char *>(g);
+ __atomic_load (__p, &__c, __ATOMIC_ACQUIRE);
+ (void) __p;
+ return _GLIBCXX_GUARD_TEST(&__c);
}
# define _GLIBCXX_GUARD_TEST_AND_ACQUIRE(G) __test_and_acquire (G)
# endif
# ifndef _GLIBCXX_GUARD_SET_AND_RELEASE
+
+// Set the guard variable to 1 with memory order release semantics.
+
inline void
__set_and_release (__cxxabiv1::__guard *g)
{
- _GLIBCXX_WRITE_MEM_BARRIER;
- _GLIBCXX_GUARD_SET (g);
+ unsigned char *__p = reinterpret_cast<unsigned char *>(g);
+ unsigned char val = 1;
+ __atomic_store (__p, &val, __ATOMIC_RELEASE);
+ (void) __p;
}
# define _GLIBCXX_GUARD_SET_AND_RELEASE(G) __set_and_release (G)
# endif
static inline void
throw_recursive_init_exception()
{
-#ifdef __EXCEPTIONS
+#if __cpp_exceptions
throw __gnu_cxx::recursive_init_error();
#else
// Use __builtin_trap so we don't require abort().
# ifdef _GLIBCXX_USE_FUTEX
// If __atomic_* and futex syscall are supported, don't use any global
// mutex.
- if (__gthread_active_p ())
+
+ // Use the same bits in the guard variable whether single-threaded or not,
+ // so that __cxa_guard_release and __cxa_guard_abort match the logic here
+ // even if __libc_single_threaded becomes false between now and then.
+
+ if (__gnu_cxx::__is_single_threaded())
+ {
+ // No need to use atomics, and no need to wait for other threads.
+ int *gi = (int *) (void *) g;
+ if (*gi == 0)
+ {
+ *gi = _GLIBCXX_GUARD_PENDING_BIT;
+ return 1;
+ }
+ else
+ throw_recursive_init_exception();
+ }
+ else
{
int *gi = (int *) (void *) g;
const int guard_bit = _GLIBCXX_GUARD_BIT;
syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAIT, expected, 0);
}
}
-# else
+# else // ! _GLIBCXX_USE_FUTEX
if (__gthread_active_p ())
{
mutex_wrapper mw;
}
}
# endif
-#endif
+#endif // ! __GTHREADS
return acquire (g);
}
extern "C"
- void __cxa_guard_abort (__guard *g) throw ()
+ void __cxa_guard_abort (__guard *g) noexcept
{
#ifdef _GLIBCXX_USE_FUTEX
// If __atomic_* and futex syscall are supported, don't use any global
// mutex.
- if (__gthread_active_p ())
+
+ if (__gnu_cxx::__is_single_threaded())
+ {
+ // No need to use atomics, and no other threads to wake.
+ int *gi = (int *) (void *) g;
+ *gi = 0;
+ return;
+ }
+ else
{
int *gi = (int *) (void *) g;
const int waiting_bit = _GLIBCXX_GUARD_WAITING_BIT;
}
extern "C"
- void __cxa_guard_release (__guard *g) throw ()
+ void __cxa_guard_release (__guard *g) noexcept
{
#ifdef _GLIBCXX_USE_FUTEX
// If __atomic_* and futex syscall are supported, don't use any global
// mutex.
- if (__gthread_active_p ())
+
+ if (__gnu_cxx::__is_single_threaded())
+ {
+ int *gi = (int *) (void *) g;
+ *gi = _GLIBCXX_GUARD_BIT;
+ return;
+ }
+ else
{
int *gi = (int *) (void *) g;
const int guard_bit = _GLIBCXX_GUARD_BIT;
syscall (SYS_futex, gi, _GLIBCXX_FUTEX_WAKE, INT_MAX);
return;
}
+
#elif defined(__GTHREAD_HAS_COND)
if (__gthread_active_p())
{
#endif
}
}
+
+#endif // __USING_MCFGTHREAD__