Commit 913b8233 authored by Marian Triebe's avatar Marian Triebe Committed by Dominik Charousset

Add workaround for a bug in `compare_exchange_weak`

Instead of `compare_exchange_weak` we use `comare_exchange_strong`
on older compilers to prevent race conditions.
This bug is present in GCC <= 4.8.2 and Clang <= 3.4.0.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60272
https://llvm.org/bugs/show_bug.cgi?id=18899
parent 4781c75f
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_CAS_WEAK_HPP
#define CAF_DETAIL_CAS_WEAK_HPP
#include <atomic>
#include "caf/config.hpp"
namespace caf {
namespace detail {
template<class T>
bool cas_weak(std::atomic<T>* obj, T* expected, T desired) {
# if (defined(CAF_CLANG) && CAF_COMPILER_VERSION < 30401) \
|| (defined(CAF_GCC) && CAF_COMPILER_VERSION < 40803)
return std::atomic_compare_exchange_strong(obj, expected, desired);
# else
return std::atomic_compare_exchange_weak(obj, expected, desired);
# endif
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_CAS_WEAK_HPP
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/detail/cas_weak.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -117,7 +119,7 @@ class singletons { ...@@ -117,7 +119,7 @@ class singletons {
if (p == nullptr) { if (p == nullptr) {
return; return;
} }
if (ptr.compare_exchange_weak(p, nullptr)) { if (cas_weak<T*>(&ptr, &p, nullptr)) {
p->dispose(); p->dispose();
return; return;
} }
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
#include <limits> #include <limits>
#include <thread> #include <thread>
#include "caf/detail/shared_spinlock.hpp" #include "caf/detail/shared_spinlock.hpp"
#include "caf/detail/cas_weak.hpp"
namespace { namespace {
inline long min_long() { inline long min_long() {
...@@ -42,9 +45,8 @@ void shared_spinlock::lock() { ...@@ -42,9 +45,8 @@ void shared_spinlock::lock() {
long v = m_flag.load(); long v = m_flag.load();
for (;;) { for (;;) {
if (v != 0) { if (v != 0) {
// std::this_thread::yield();
v = m_flag.load(); v = m_flag.load();
} else if (m_flag.compare_exchange_weak(v, min_long())) { } else if (cas_weak(&m_flag, &v, min_long())) {
return; return;
} }
// else: next iteration // else: next iteration
...@@ -75,7 +77,7 @@ void shared_spinlock::unlock() { ...@@ -75,7 +77,7 @@ void shared_spinlock::unlock() {
bool shared_spinlock::try_lock() { bool shared_spinlock::try_lock() {
long v = m_flag.load(); long v = m_flag.load();
return (v == 0) ? m_flag.compare_exchange_weak(v, min_long()) : false; return (v == 0) ? cas_weak(&m_flag, &v, min_long()) : false;
} }
void shared_spinlock::lock_shared() { void shared_spinlock::lock_shared() {
...@@ -84,7 +86,7 @@ void shared_spinlock::lock_shared() { ...@@ -84,7 +86,7 @@ void shared_spinlock::lock_shared() {
if (v < 0) { if (v < 0) {
// std::this_thread::yield(); // std::this_thread::yield();
v = m_flag.load(); v = m_flag.load();
} else if (m_flag.compare_exchange_weak(v, v + 1)) { } else if (cas_weak(&m_flag, &v, v + 1)) {
return; return;
} }
// else: next iteration // else: next iteration
...@@ -97,7 +99,7 @@ void shared_spinlock::unlock_shared() { ...@@ -97,7 +99,7 @@ void shared_spinlock::unlock_shared() {
bool shared_spinlock::try_lock_shared() { bool shared_spinlock::try_lock_shared() {
long v = m_flag.load(); long v = m_flag.load();
return (v >= 0) ? m_flag.compare_exchange_weak(v, v + 1) : false; return (v >= 0) ? cas_weak(&m_flag, &v, v + 1) : false;
} }
} // namespace detail } // namespace detail
......
...@@ -21,7 +21,7 @@ void inc_actor_instances() { ...@@ -21,7 +21,7 @@ void inc_actor_instances() {
long v1 = ++s_actor_instances; long v1 = ++s_actor_instances;
long v2 = s_max_actor_instances.load(); long v2 = s_max_actor_instances.load();
while (v1 > v2) { while (v1 > v2) {
s_max_actor_instances.compare_exchange_weak(v2, v1); s_max_actor_instances.compare_exchange_strong(v2, v1);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment