From 710ce964c80712ffdb64b993f20b8ef6c4c57530 Mon Sep 17 00:00:00 2001 From: James Benton Date: Fri, 25 May 2018 18:47:11 +0100 Subject: [PATCH] wutstdc++: Add remaining gthreads reliant std code. --- libraries/wutstdc++/CMakeLists.txt | 4 + libraries/wutstdc++/condition_variable.cc | 158 ++++++++++++++++++++++ libraries/wutstdc++/future.cc | 62 +++++++++ libraries/wutstdc++/mutex.cc | 97 +++++++++++++ libraries/wutstdc++/shared_ptr.cc | 88 ++++++++++++ 5 files changed, 409 insertions(+) create mode 100644 libraries/wutstdc++/condition_variable.cc create mode 100644 libraries/wutstdc++/future.cc create mode 100644 libraries/wutstdc++/mutex.cc create mode 100644 libraries/wutstdc++/shared_ptr.cc diff --git a/libraries/wutstdc++/CMakeLists.txt b/libraries/wutstdc++/CMakeLists.txt index d807475..98311a6 100644 --- a/libraries/wutstdc++/CMakeLists.txt +++ b/libraries/wutstdc++/CMakeLists.txt @@ -2,12 +2,16 @@ cmake_minimum_required(VERSION 3.2) project(wutstdc++ CXX) add_library(wutstdc++ + condition_variable.cc + future.cc gthread.cc gthread_cond.cc gthread_keys.cc gthread_mutex.cc gthread_once.cc gthread_recursive_mutex.cc + mutex.cc + shared_ptr.cc thread.cc include/bits/gthr-default.h) diff --git a/libraries/wutstdc++/condition_variable.cc b/libraries/wutstdc++/condition_variable.cc new file mode 100644 index 0000000..a302354 --- /dev/null +++ b/libraries/wutstdc++/condition_variable.cc @@ -0,0 +1,158 @@ +// condition_variable -*- C++ -*- + +// Copyright (C) 2008-2018 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#include +#include + +#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifdef __GTHREAD_COND_INIT + condition_variable::condition_variable() noexcept = default; +#else + condition_variable::condition_variable() noexcept + { + __GTHREAD_COND_INIT_FUNCTION(&_M_cond); + } +#endif + + condition_variable::~condition_variable() noexcept + { + // XXX no thread blocked + /* int __e = */ __gthread_cond_destroy(&_M_cond); + // if __e == EBUSY then blocked + } + + void + condition_variable::wait(unique_lock& __lock) noexcept + { + int __e = __gthread_cond_wait(&_M_cond, __lock.mutex()->native_handle()); + + if (__e) + std::terminate(); + } + + void + condition_variable::notify_one() noexcept + { + int __e = __gthread_cond_signal(&_M_cond); + + // XXX not in spec + // EINVAL + if (__e) + __throw_system_error(__e); + } + + void + condition_variable::notify_all() noexcept + { + int __e = __gthread_cond_broadcast(&_M_cond); + + // XXX not in spec + // EINVAL + if (__e) + __throw_system_error(__e); + } + + extern void + __at_thread_exit(__at_thread_exit_elt*); + + namespace + { + __gthread_key_t key; + + void run(void* p) + { + auto elt = (__at_thread_exit_elt*)p; + while (elt) + { + auto next = elt->_M_next; + elt->_M_cb(elt); + elt = next; + } + } + + void run() + { + auto elt = (__at_thread_exit_elt*)__gthread_getspecific(key); + __gthread_setspecific(key, nullptr); + run(elt); + } + + struct notifier final : __at_thread_exit_elt + { + notifier(condition_variable& cv, unique_lock& l) + : cv(&cv), mx(l.release()) + { + _M_cb = ¬ifier::run; + __at_thread_exit(this); + } + + ~notifier() + { + mx->unlock(); + cv->notify_all(); + } + + condition_variable* cv; + mutex* mx; + + static void run(void* p) { delete static_cast(p); } + }; + + + void key_init() { + struct key_s { + key_s() { __gthread_key_create (&key, run); } + ~key_s() { __gthread_key_delete (key); } + }; + static key_s ks; + // Also make sure the callbacks are run by std::exit. + std::atexit (run); + } + } + + void + __at_thread_exit(__at_thread_exit_elt* elt) + { + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + __gthread_once (&once, key_init); + + elt->_M_next = (__at_thread_exit_elt*)__gthread_getspecific(key); + __gthread_setspecific(key, elt); + } + + void + notify_all_at_thread_exit(condition_variable& cv, unique_lock l) + { + (void) new notifier{cv, l}; + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 diff --git a/libraries/wutstdc++/future.cc b/libraries/wutstdc++/future.cc new file mode 100644 index 0000000..f3b877a --- /dev/null +++ b/libraries/wutstdc++/future.cc @@ -0,0 +1,62 @@ +// future -*- C++ -*- + +// Copyright (C) 2009-2018 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#include +#include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) + __future_base::_Result_base::_Result_base() = default; + + __future_base::_Result_base::~_Result_base() = default; + + void + __future_base::_State_baseV2::_Make_ready::_S_run(void* p) + { + unique_ptr<_Make_ready> mr{static_cast<_Make_ready*>(p)}; + if (auto state = mr->_M_shared_state.lock()) + { + // Use release MO to synchronize with observers of the ready state. + state->_M_status._M_store_notify_all(_Status::__ready, + memory_order_release); + } + } + + // defined in src/c++11/condition_variable.cc + extern void + __at_thread_exit(__at_thread_exit_elt* elt); + + void + __future_base::_State_baseV2::_Make_ready::_M_set() + { + _M_cb = &_Make_ready::_S_run; + __at_thread_exit(this); + } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std diff --git a/libraries/wutstdc++/mutex.cc b/libraries/wutstdc++/mutex.cc new file mode 100644 index 0000000..b62bf87 --- /dev/null +++ b/libraries/wutstdc++/mutex.cc @@ -0,0 +1,97 @@ +// mutex -*- C++ -*- + +// Copyright (C) 2008-2018 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#include + +#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) +#ifndef _GLIBCXX_HAVE_TLS +namespace +{ + inline std::unique_lock*& + __get_once_functor_lock_ptr() + { + static std::unique_lock* __once_functor_lock_ptr = 0; + return __once_functor_lock_ptr; + } +} +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifdef _GLIBCXX_HAVE_TLS + __thread void* __once_callable; + __thread void (*__once_call)(); +#else + // Explicit instantiation due to -fno-implicit-instantiation. + template class function; + function __once_functor; + + mutex& + __get_once_mutex() + { + static mutex once_mutex; + return once_mutex; + } + + // code linked against ABI 3.4.12 and later uses this + void + __set_once_functor_lock_ptr(unique_lock* __ptr) + { + __get_once_functor_lock_ptr() = __ptr; + } + + // unsafe - retained for compatibility with ABI 3.4.11 + unique_lock& + __get_once_functor_lock() + { + static unique_lock once_functor_lock(__get_once_mutex(), defer_lock); + return once_functor_lock; + } +#endif + + extern "C" + { + void __once_proxy() + { +#ifndef _GLIBCXX_HAVE_TLS + function __once_call = std::move(__once_functor); + if (unique_lock* __lock = __get_once_functor_lock_ptr()) + { + // caller is using new ABI and provided lock ptr + __get_once_functor_lock_ptr() = 0; + __lock->unlock(); + } + else + __get_once_functor_lock().unlock(); // global lock +#endif + __once_call(); + } + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 diff --git a/libraries/wutstdc++/shared_ptr.cc b/libraries/wutstdc++/shared_ptr.cc new file mode 100644 index 0000000..426839e --- /dev/null +++ b/libraries/wutstdc++/shared_ptr.cc @@ -0,0 +1,88 @@ +// Support for pointer abstractions -*- C++ -*- + +// Copyright (C) 2011-2018 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#include + +namespace __gnu_internal _GLIBCXX_VISIBILITY(hidden) +{ + const unsigned char mask = 0xf; + const unsigned char invalid = mask + 1; + + /* Returns different instances of __mutex depending on the passed index + * in order to limit contention. + */ + __gnu_cxx::__mutex& get_mutex(unsigned char i); +} + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifdef __GTHREADS + namespace + { + inline unsigned char key(const void* addr) + { return _Hash_impl::hash(addr) & __gnu_internal::mask; } + } + + _Sp_locker::_Sp_locker(const void* p) noexcept + { + if (__gthread_active_p()) + { + _M_key1 = _M_key2 = key(p); + __gnu_internal::get_mutex(_M_key1).lock(); + } + else + _M_key1 = _M_key2 = __gnu_internal::invalid; + } + + _Sp_locker::_Sp_locker(const void* p1, const void* p2) noexcept + { + if (__gthread_active_p()) + { + _M_key1 = key(p1); + _M_key2 = key(p2); + if (_M_key2 < _M_key1) + __gnu_internal::get_mutex(_M_key2).lock(); + __gnu_internal::get_mutex(_M_key1).lock(); + if (_M_key2 > _M_key1) + __gnu_internal::get_mutex(_M_key2).lock(); + } + else + _M_key1 = _M_key2 = __gnu_internal::invalid; + } + + _Sp_locker::~_Sp_locker() + { + if (_M_key1 != __gnu_internal::invalid) + { + __gnu_internal::get_mutex(_M_key1).unlock(); + if (_M_key2 != _M_key1) + __gnu_internal::get_mutex(_M_key2).unlock(); + } + } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace