< prev index next >
src/hotspot/share/runtime/atomic.hpp
Print this page
@@ -32,10 +32,11 @@
#include "metaprogramming/isPointer.hpp"
#include "metaprogramming/isSame.hpp"
#include "metaprogramming/primitiveConversions.hpp"
#include "metaprogramming/removeCV.hpp"
#include "metaprogramming/removePointer.hpp"
+#include "runtime/orderAccess.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
enum atomic_memory_order {
// The modes that align with C++11 are intended to
@@ -46,10 +47,16 @@
memory_order_acq_rel = 4,
// Strong two-way memory barrier.
memory_order_conservative = 8
};
+enum ScopedFenceType {
+ X_ACQUIRE
+ , RELEASE_X
+ , RELEASE_X_FENCE
+};
+
class Atomic : AllStatic {
public:
// Atomic operations on int64 types are not available on all 32-bit
// platforms. If atomic ops on int64 are defined here they must only
// be used from code that verifies they are available at runtime and
@@ -73,16 +80,25 @@
// to D, an integral/enum type equal to D, or a type equal to D that
// is primitive convertible using PrimitiveConversions.
template<typename T, typename D>
inline static void store(T store_value, volatile D* dest);
+ template <typename T, typename D>
+ inline static void release_store(volatile D* dest, T store_value);
+
+ template <typename T, typename D>
+ inline static void release_store_fence(volatile D* dest, T store_value);
+
// Atomically load from a location
// The type T must be either a pointer type, an integral/enum type,
// or a type that is primitive convertible using PrimitiveConversions.
template<typename T>
inline static T load(const volatile T* dest);
+ template <typename T>
+ inline static T load_acquire(const volatile T* dest);
+
// Atomically add to a location. Returns updated value. add*() provide:
// <fence> add-value-to-dest <membar StoreLoad|StoreStore>
template<typename I, typename D>
inline static D add(I add_value, D volatile* dest,
@@ -198,10 +214,14 @@
//
// The default implementation is a volatile load. If a platform
// requires more for e.g. 64 bit loads, a specialization is required
template<size_t byte_size> struct PlatformLoad;
+ // Give platforms a variation point to specialize.
+ template<size_t byte_size, ScopedFenceType type> struct PlatformOrderedStore;
+ template<size_t byte_size, ScopedFenceType type> struct PlatformOrderedLoad;
+
private:
// Dispatch handler for add. Provides type-based validity checking
// and limited conversions around calls to the platform-specific
// implementation layer provided by PlatformAdd.
template<typename I, typename D, typename Enable = void>
@@ -576,10 +596,36 @@
T operator()(T exchange_value,
T volatile* dest,
atomic_memory_order order) const;
};
+template <ScopedFenceType T>
+class ScopedFenceGeneral: public StackObj {
+ public:
+ void prefix() {}
+ void postfix() {}
+};
+
+// The following methods can be specialized using simple template specialization
+// in the platform specific files for optimization purposes. Otherwise the
+// generalized variant is used.
+
+template<> inline void ScopedFenceGeneral<X_ACQUIRE>::postfix() { OrderAccess::acquire(); }
+template<> inline void ScopedFenceGeneral<RELEASE_X>::prefix() { OrderAccess::release(); }
+template<> inline void ScopedFenceGeneral<RELEASE_X_FENCE>::prefix() { OrderAccess::release(); }
+template<> inline void ScopedFenceGeneral<RELEASE_X_FENCE>::postfix() { OrderAccess::fence(); }
+
+template <ScopedFenceType T>
+class ScopedFence : public ScopedFenceGeneral<T> {
+ void *const _field;
+ public:
+ ScopedFence(void *const field) : _field(field) { prefix(); }
+ ~ScopedFence() { postfix(); }
+ void prefix() { ScopedFenceGeneral<T>::prefix(); }
+ void postfix() { ScopedFenceGeneral<T>::postfix(); }
+};
+
// platform specific in-line definitions - must come before shared definitions
#include OS_CPU_HEADER(atomic)
// shared in-line definitions
@@ -592,15 +638,48 @@
template<typename T>
inline T Atomic::load(const volatile T* dest) {
return LoadImpl<T, PlatformLoad<sizeof(T)> >()(dest);
}
+template<size_t byte_size, ScopedFenceType type>
+struct Atomic::PlatformOrderedLoad {
+ template <typename T>
+ T operator()(const volatile T* p) const {
+ ScopedFence<type> f((void*)p);
+ return Atomic::load(p);
+ }
+};
+
+template <typename T>
+inline T Atomic::load_acquire(const volatile T* p) {
+ return LoadImpl<T, PlatformOrderedLoad<sizeof(T), X_ACQUIRE> >()(p);
+}
+
template<typename T, typename D>
inline void Atomic::store(T store_value, volatile D* dest) {
StoreImpl<T, D, PlatformStore<sizeof(D)> >()(store_value, dest);
}
+template<size_t byte_size, ScopedFenceType type>
+struct Atomic::PlatformOrderedStore {
+ template <typename T>
+ void operator()(T v, volatile T* p) const {
+ ScopedFence<type> f((void*)p);
+ Atomic::store(v, p);
+ }
+};
+
+template <typename T, typename D>
+inline void Atomic::release_store(volatile D* p, T v) {
+ StoreImpl<T, D, PlatformOrderedStore<sizeof(D), RELEASE_X> >()(v, p);
+}
+
+template <typename T, typename D>
+inline void Atomic::release_store_fence(volatile D* p, T v) {
+ StoreImpl<T, D, PlatformOrderedStore<sizeof(D), RELEASE_X_FENCE> >()(v, p);
+}
+
template<typename I, typename D>
inline D Atomic::add(I add_value, D volatile* dest,
atomic_memory_order order) {
return AddImpl<I, D>()(add_value, dest, order);
}
< prev index next >