#include <bits/c++config.h>
#include <bits/gthr.h>
#include <bits/atomic_word.h>
+#if __has_include(<sys/single_threaded.h>)
+# include <sys/single_threaded.h>
+#endif
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ __attribute__((__always_inline__))
+ inline bool
+ __is_single_threaded() _GLIBCXX_NOTHROW
+ {
+#ifndef __GTHREADS
+ return true;
+#elif __has_include(<sys/single_threaded.h>)
+ return ::__libc_single_threaded;
+#else
+ return !__gthread_active_p();
+#endif
+ }
+
// Functions for portable atomic access.
// To abstract locking primitives across all thread policies, use:
// __exchange_and_add_dispatch
__attribute__ ((__always_inline__))
__exchange_and_add_dispatch(_Atomic_word* __mem, int __val)
{
-#ifdef __GTHREADS
- if (__gthread_active_p())
+ if (__is_single_threaded())
+ return __exchange_and_add_single(__mem, __val);
+ else
return __exchange_and_add(__mem, __val);
-#endif
- return __exchange_and_add_single(__mem, __val);
}
inline void
__attribute__ ((__always_inline__))
__atomic_add_dispatch(_Atomic_word* __mem, int __val)
{
-#ifdef __GTHREADS
- if (__gthread_active_p())
- {
- __atomic_add(__mem, __val);
- return;
- }
-#endif
- __atomic_add_single(__mem, __val);
+ if (__is_single_threaded())
+ __atomic_add_single(__mem, __val);
+ else
+ __atomic_add(__mem, __val);
}
_GLIBCXX_END_NAMESPACE_VERSION
# 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())
{
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-pthread" }
+// { dg-do run { target *-*-linux-gnu } }
+// { dg-require-effective-target pthread }
+
+// PR libstdc++/96817
+
+int init()
+{
+#if __has_include(<sys/single_threaded.h>)
+ // This deadlocks unless __libc_single_threaded is available in Glibc,
+ // because __cxa_guard_acquire uses __gthread_active_p and the
+ // multithreaded init can't detect recursion (see PR 97211).
+ static int i = init();
+#endif
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ init();
+}