Add atomic adjust impl that uses GCC intrinsics. Also, make use of "constexpr" when available.

This commit is contained in:
rdb 2014-07-17 13:11:06 +00:00
parent cea09d4b9e
commit 1be0fb5169
10 changed files with 253 additions and 17 deletions

View File

@ -23,7 +23,7 @@
#include "atomicAdjustDummyImpl.h"
typedef AtomicAdjustDummyImpl AtomicAdjust;
#elif defined(__i386__) || defined(_M_IX86)
#elif defined(__i386__) || defined(_M_IX86)
// For an i386 architecture, we'll always use the i386 implementation.
// It should be safe for any OS, and it might be a bit faster than
// any OS-provided calls.
@ -39,6 +39,15 @@ typedef AtomicAdjustI386Impl AtomicAdjust;
#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
// GCC 4.7 and above has built-in __atomic functions for atomic operations.
#include "atomicAdjustGccImpl.h"
typedef AtomicAdjustGccImpl AtomicAdjust;
#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1
#elif defined(THREAD_WIN32_IMPL)
#include "atomicAdjustWin32Impl.h"

View File

@ -0,0 +1,148 @@
// Filename: atomicAdjustGccImpl.I
// Created by: rdb (04Jul14)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::inc
// Access: Public, Static
// Description: Atomically increments the indicated variable.
////////////////////////////////////////////////////////////////////
INLINE void AtomicAdjustGccImpl::
inc(TVOLATILE AtomicAdjustGccImpl::Integer &var) {
__atomic_fetch_add(&var, 1, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::dec
// Access: Public, Static
// Description: Atomically decrements the indicated variable and
// returns true if the new value is nonzero, false if it
// is zero.
////////////////////////////////////////////////////////////////////
INLINE bool AtomicAdjustGccImpl::
dec(TVOLATILE AtomicAdjustGccImpl::Integer &var) {
return (__atomic_sub_fetch(&var, 1, __ATOMIC_SEQ_CST) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::add
// Access: Public, Static
// Description: Atomically computes var += delta. It is legal for
// delta to be negative.
////////////////////////////////////////////////////////////////////
INLINE void AtomicAdjustGccImpl::
add(TVOLATILE AtomicAdjustGccImpl::Integer &var,
AtomicAdjustGccImpl::Integer delta) {
__atomic_fetch_add(&var, delta, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::set
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl::
set(TVOLATILE AtomicAdjustGccImpl::Integer &var,
AtomicAdjustGccImpl::Integer new_value) {
return __atomic_exchange_n(&var, new_value, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::get
// Access: Public, Static
// Description: Atomically retrieves the snapshot value of the
// indicated variable. This is the only guaranteed safe
// way to retrieve the value that other threads might be
// asynchronously setting, incrementing, or decrementing
// (via other AtomicAjust methods).
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl::
get(const TVOLATILE AtomicAdjustGccImpl::Integer &var) {
return __atomic_load_n(&var, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::set_ptr
// Access: Public, Static
// Description: Atomically changes the indicated variable and
// returns the original value.
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl::
set_ptr(TVOLATILE AtomicAdjustGccImpl::Pointer &var,
AtomicAdjustGccImpl::Pointer new_value) {
return __atomic_exchange_n(&var, new_value, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::get_ptr
// Access: Public, Static
// Description: Atomically retrieves the snapshot value of the
// indicated variable. This is the only guaranteed safe
// way to retrieve the value that other threads might be
// asynchronously setting, incrementing, or decrementing
// (via other AtomicAjust methods).
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl::
get_ptr(const TVOLATILE AtomicAdjustGccImpl::Pointer &var) {
return __atomic_load_n(&var, __ATOMIC_SEQ_CST);
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::compare_and_exchange
// Access: Public, Static
// Description: Atomic compare and exchange.
//
// If mem is equal to old_value, store new_value in mem.
// In either case, return the original value of mem.
// The caller can test for success by comparing
// return_value == old_value.
//
// The atomic function expressed in pseudo-code:
//
// orig_value = mem;
// if (mem == old_value) {
// mem = new_value;
// }
// return orig_value;
//
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl::
compare_and_exchange(TVOLATILE AtomicAdjustGccImpl::Integer &mem,
AtomicAdjustGccImpl::Integer old_value,
AtomicAdjustGccImpl::Integer new_value) {
__atomic_compare_exchange_n(&mem, &old_value, new_value, false,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return old_value;
}
////////////////////////////////////////////////////////////////////
// Function: AtomicAdjustGccImpl::compare_and_exchange_ptr
// Access: Public, Static
// Description: Atomic compare and exchange.
//
// As above, but works on pointers instead of integers.
////////////////////////////////////////////////////////////////////
INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl::
compare_and_exchange_ptr(TVOLATILE AtomicAdjustGccImpl::Pointer &mem,
AtomicAdjustGccImpl::Pointer old_value,
AtomicAdjustGccImpl::Pointer new_value) {
__atomic_compare_exchange_n(&mem, &old_value, new_value, false,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return old_value;
}

View File

@ -0,0 +1,60 @@
// Filename: atomicAdjustGccImpl.h
// Created by: rdb (04Jul14)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ATOMICADJUSTGCCIMPL_H
#define ATOMICADJUSTGCCIMPL_H
#include "dtoolbase.h"
#include "selectThreadImpl.h"
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
////////////////////////////////////////////////////////////////////
// Class : AtomicAdjustGccImpl
// Description : Uses GCC built-ins to implement atomic adjustments.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOL AtomicAdjustGccImpl {
public:
#if __GCC_ATOMIC_LONG_LOCK_FREE > __GCC_ATOMIC_INT_LOCK_FREE
// If the long can be more lock-free than int, use it instead.
typedef __attribute__ ((aligned (__SIZEOF_LONG__))) long Integer;
#else
typedef __attribute__ ((aligned (__SIZEOF_INT__))) int Integer;
#endif
typedef void *UnalignedPointer;
typedef __attribute__ ((aligned (__SIZEOF_POINTER__))) UnalignedPointer Pointer;
INLINE static void inc(TVOLATILE Integer &var);
INLINE static bool dec(TVOLATILE Integer &var);
INLINE static void add(TVOLATILE Integer &var, Integer delta);
INLINE static Integer set(TVOLATILE Integer &var, Integer new_value);
INLINE static Integer get(const TVOLATILE Integer &var);
INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value);
INLINE static Pointer get_ptr(const TVOLATILE Pointer &var);
INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem,
Integer old_value,
Integer new_value);
INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem,
Pointer old_value,
Pointer new_value);
};
#include "atomicAdjustGccImpl.I"
#endif // HAVE_POSIX_THREADS
#endif

View File

@ -365,7 +365,7 @@ cpow(int x, int y) {
INLINE bool
cnan(double v) {
#ifndef _WIN32
return (isnan(v) != 0);
return (std::isnan(v) != 0);
#else
return (_isnan(v) != 0);
#endif

View File

@ -23,7 +23,7 @@
#include "dtoolbase.h"
#include <math.h>
#include <cmath>
// Windows defines isnan() in a different place and with a different
// name than everyone else. Sheesh.

View File

@ -33,6 +33,7 @@ using namespace std;
#define INLINE inline
#define TYPENAME typename
#define CONSTEXPR
#define EXPORT_TEMPLATE_CLASS(expcl, exptp, classname)
@ -119,6 +120,16 @@ typedef ios::seekdir ios_seekdir;
#define INLINE inline
#endif
#if defined(__has_extension) // Clang magic.
#if __has_extension(cxx_constexpr)
#define CONSTEXPR constexpr
#endif
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
#define CONSTEXPR constexpr
#else
#define CONSTEXPR INLINE
#endif
#if defined(WIN32_VC) && !defined(LINK_ALL_STATIC) && defined(EXPORT_TEMPLATES)
// This macro must be used to export an instantiated template class
// from a DLL. If the template class name itself contains commas, it

View File

@ -106,7 +106,7 @@ is_debug() const {
// methods are redefined to be static to make it more
// obvious to the compiler.
////////////////////////////////////////////////////////////////////
INLINE bool NotifyCategory::
CONSTEXPR bool NotifyCategory::
is_spam() {
return false;
}
@ -119,7 +119,7 @@ is_spam() {
// methods are redefined to be static to make it more
// obvious to the compiler.
////////////////////////////////////////////////////////////////////
INLINE bool NotifyCategory::
CONSTEXPR bool NotifyCategory::
is_debug() {
return false;
}

View File

@ -56,8 +56,8 @@ PUBLISHED:
INLINE bool is_spam() const;
INLINE bool is_debug() const;
#else
INLINE static bool is_spam();
INLINE static bool is_debug();
CONSTEXPR static bool is_spam();
CONSTEXPR static bool is_debug();
#endif
INLINE bool is_info() const;
INLINE bool is_warning() const;

View File

@ -80,30 +80,38 @@ is_on(NotifySeverity severity) {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
#ifdef NOTIFY_DEBUG
template<class GetCategory>
INLINE bool NotifyCategoryProxy<GetCategory>::
is_spam() {
#ifdef NOTIFY_DEBUG
return get_unsafe_ptr()->is_spam();
#else
return false;
#endif
}
#else
template<class GetCategory>
CONSTEXPR bool NotifyCategoryProxy<GetCategory>::
is_spam() {
return false;
}
#endif
////////////////////////////////////////////////////////////////////
// Function: NotifyCategoryProxy::is_debug
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
#ifdef NOTIFY_DEBUG
template<class GetCategory>
INLINE bool NotifyCategoryProxy<GetCategory>::
is_debug() {
#ifdef NOTIFY_DEBUG
return get_unsafe_ptr()->is_debug();
#else
return false;
#endif
}
#else
template<class GetCategory>
CONSTEXPR bool NotifyCategoryProxy<GetCategory>::
is_debug() {
return false;
}
#endif
////////////////////////////////////////////////////////////////////
// Function: NotifyCategoryProxy::is_info

View File

@ -85,8 +85,8 @@ public:
INLINE bool is_spam();
INLINE bool is_debug();
#else
INLINE static bool is_spam();
INLINE static bool is_debug();
CONSTEXPR static bool is_spam();
CONSTEXPR static bool is_debug();
#endif
INLINE bool is_info();
INLINE bool is_warning();