Browse Source

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

rdb 11 years ago
parent
commit
1be0fb5169

+ 10 - 1
dtool/src/dtoolbase/atomicAdjust.h

@@ -23,7 +23,7 @@
 #include "atomicAdjustDummyImpl.h"
 #include "atomicAdjustDummyImpl.h"
 typedef AtomicAdjustDummyImpl AtomicAdjust;
 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.
 // 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
 // It should be safe for any OS, and it might be a bit faster than
 // any OS-provided calls.
 // any OS-provided calls.
@@ -39,6 +39,15 @@ typedef AtomicAdjustI386Impl AtomicAdjust;
 #define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
 #define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1
 #define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 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)
 #elif defined(THREAD_WIN32_IMPL)
 
 
 #include "atomicAdjustWin32Impl.h"
 #include "atomicAdjustWin32Impl.h"

+ 148 - 0
dtool/src/dtoolbase/atomicAdjustGccImpl.I

@@ -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;
+}

+ 60 - 0
dtool/src/dtoolbase/atomicAdjustGccImpl.h

@@ -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

+ 1 - 1
dtool/src/dtoolbase/cmath.I

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

+ 1 - 1
dtool/src/dtoolbase/cmath.h

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

+ 11 - 0
dtool/src/dtoolbase/dtoolbase_cc.h

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

+ 2 - 2
dtool/src/prc/notifyCategory.I

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

+ 2 - 2
dtool/src/prc/notifyCategory.h

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

+ 12 - 4
dtool/src/prc/notifyCategoryProxy.I

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

+ 2 - 2
dtool/src/prc/notifyCategoryProxy.h

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