Use std::atomic
Replace amd::Atomic with std::atomic. Remove make_atomic uses by converting the variable to std::atomic and making sure the memory order is relaxed when synchronizes-with is not needed. Delete utils/atomic.hpp. Change-Id: I0b36db8d604a8510ac6e36b32885fd16a1b8ccfa
Этот коммит содержится в:
коммит произвёл
Saleel Kudchadker
родитель
cef70aa8d3
Коммит
5d4b6f74d3
@@ -19,7 +19,6 @@
|
||||
THE SOFTWARE. */
|
||||
|
||||
#include "device/device.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/monitor.hpp"
|
||||
#include "utils/options.hpp"
|
||||
#include "comgrctx.hpp"
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "comgrctx.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -1345,7 +1346,7 @@ bool Program::initBuild(amd::option::Options* options) {
|
||||
programOptions_ = options;
|
||||
|
||||
if (options->oVariables->DumpFlags > 0) {
|
||||
static amd::Atomic<unsigned> build_num = 0;
|
||||
static std::atomic<uint> build_num{0};
|
||||
options->setBuildNo(build_num++);
|
||||
}
|
||||
buildLog_.clear();
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "device/gpu/gpusettings.hpp"
|
||||
#include "device/gpu/gpuappprofile.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "acl.h"
|
||||
#include "vaminterface.h"
|
||||
@@ -316,7 +317,7 @@ class Device : public NullDevice, public CALGSLDevice {
|
||||
Resource::MemoryType type_; //!< The buffer's type
|
||||
size_t bufSize_; //!< Staged buffer size
|
||||
std::list<Memory*> freeBuffers_; //!< The list of free buffers
|
||||
amd::Atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
std::atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
amd::Monitor lock_; //!< Staged buffer acquire/release lock
|
||||
const Device& gpuDevice_; //!< GPU device object
|
||||
};
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define GPUMEMORY_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "device/gpu/gpuresource.hpp"
|
||||
#include <map>
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include "device/gpu/gpublit.hpp"
|
||||
#include "device/gpu/gputimestamp.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "hsa_ext_image.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "platform/program.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
//! \namespace gpu GPU Resource Implementation
|
||||
namespace gpu {
|
||||
|
||||
@@ -412,7 +414,7 @@ class Resource : public amd::HeapObject {
|
||||
|
||||
const Device& gpuDevice_; //!< GPU device
|
||||
CalResourceDesc cal_; //!< CAL descriptor for this resource
|
||||
amd::Atomic<int> mapCount_; //!< Total number of maps
|
||||
std::atomic<int> mapCount_; //!< Total number of maps
|
||||
void* address_; //!< Physical address of this resource
|
||||
size_t offset_; //!< Resource offset
|
||||
size_t curRename_; //!< Current active rename in the list
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "acl.h"
|
||||
#include "memory"
|
||||
|
||||
#include <atomic>
|
||||
#include <unordered_set>
|
||||
|
||||
/*! \addtogroup PAL
|
||||
@@ -258,7 +259,7 @@ class Device : public NullDevice {
|
||||
Resource::MemoryType type_; //!< The buffer's type
|
||||
size_t bufSize_; //!< Staged buffer size
|
||||
std::list<Memory*> freeBuffers_; //!< The list of free buffers
|
||||
amd::Atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
std:atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
amd::Monitor lock_; //!< Stgaed buffer acquire/release lock
|
||||
const Device& gpuDevice_; //!< GPU device object
|
||||
};
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "device/pal/palresource.hpp"
|
||||
#include <map>
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "device/pal/paldevice.hpp"
|
||||
#include "device/pal/palblit.hpp"
|
||||
#include "device/pal/paltimestamp.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "hsa_ext_image.h"
|
||||
#ifdef _WIN32
|
||||
#include <d3d10_1.h>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "device/pal/paldefs.hpp"
|
||||
#include "util/palBuddyAllocatorImpl.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
|
||||
//! \namespace pal PAL Resource Implementation
|
||||
@@ -479,7 +480,7 @@ class Resource : public amd::HeapObject {
|
||||
|
||||
const Device& gpuDevice_; //!< GPU device
|
||||
Descriptor desc_; //!< Descriptor for this resource
|
||||
amd::Atomic<int> mapCount_; //!< Total number of maps
|
||||
std::atomic<int> mapCount_; //!< Total number of maps
|
||||
void* address_; //!< Physical address of this resource
|
||||
size_t offset_; //!< Resource offset
|
||||
GpuMemoryReference* memRef_; //!< PAL resource reference
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "hsa_ext_amd.h"
|
||||
#include "hsa_ven_amd_loader.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@@ -281,7 +282,7 @@ class Device : public NullDevice {
|
||||
|
||||
size_t bufSize_; //!< Staged buffer size
|
||||
std::list<Memory*> freeBuffers_; //!< The list of free buffers
|
||||
amd::Atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
std::atomic_uint acquiredCnt_; //!< The total number of acquired buffers
|
||||
amd::Monitor lock_; //!< Stgaed buffer acquire/release lock
|
||||
const Device& gpuDevice_; //!< GPU device object
|
||||
};
|
||||
@@ -535,7 +536,7 @@ class Device : public NullDevice {
|
||||
std::vector<LinkAttrType>* link_attr);
|
||||
|
||||
public:
|
||||
amd::Atomic<uint> numOfVgpus_; //!< Virtual gpu unique index
|
||||
std::atomic<uint> numOfVgpus_; //!< Virtual gpu unique index
|
||||
|
||||
//! enum for keeping the total and available queue priorities
|
||||
enum QueuePriority : uint { Low = 0, Normal = 1, High = 2, Total = 3};
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <xmmintrin.h>
|
||||
#endif /*!ATI_ARCH_ARM*/
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
@@ -169,7 +170,7 @@ class HeapObject {
|
||||
/*! \brief For all reference counted objects.
|
||||
*/
|
||||
class ReferenceCountedObject {
|
||||
volatile uint referenceCount_;
|
||||
std::atomic<uint> referenceCount_;
|
||||
|
||||
protected:
|
||||
virtual ~ReferenceCountedObject() {}
|
||||
@@ -185,7 +186,7 @@ class ReferenceCountedObject {
|
||||
};
|
||||
void operator delete(void* obj, size_t extSize) { ReferenceCountedObject::operator delete(obj); }
|
||||
|
||||
uint referenceCount() const { return referenceCount_; }
|
||||
uint referenceCount() const { return referenceCount_.load(std::memory_order_relaxed); }
|
||||
|
||||
uint retain();
|
||||
uint release();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <time.h>
|
||||
#include <intrin.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "thread/monitor.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "thread/monitor.hpp"
|
||||
|
||||
#define USE_PROF_API 1
|
||||
|
||||
#if USE_PROF_API
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "platform/agent.hpp"
|
||||
#include "os/alloc.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -91,7 +92,7 @@ uint64_t epoch = 0;
|
||||
bool Event::setStatus(int32_t status, uint64_t timeStamp) {
|
||||
assert(status <= CL_QUEUED && "invalid status");
|
||||
|
||||
int32_t currentStatus = status_;
|
||||
int32_t currentStatus = this->status();
|
||||
if (currentStatus <= CL_COMPLETE || currentStatus <= status) {
|
||||
// We can only move forward in the execution status.
|
||||
return false;
|
||||
@@ -104,7 +105,7 @@ bool Event::setStatus(int32_t status, uint64_t timeStamp) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!make_atomic(status_).compareAndSet(currentStatus, status)) {
|
||||
if (!status_.compare_exchange_strong(currentStatus, status, std::memory_order_relaxed)) {
|
||||
// Somebody else beat us to it, let them deal with the release/signal.
|
||||
return false;
|
||||
}
|
||||
@@ -154,7 +155,7 @@ bool Event::setCallback(int32_t status, Event::CallBackFunction callback, void*
|
||||
; // Someone else is also updating the head of the linked list! reload.
|
||||
|
||||
// Check if the event has already reached 'status'
|
||||
if (status_ <= status && entry->callback_ != CallBackFunction(0)) {
|
||||
if (this->status() <= status && entry->callback_ != CallBackFunction(0)) {
|
||||
if (entry->callback_.exchange(NULL) != NULL) {
|
||||
callback(as_cl(this), status, entry->data_);
|
||||
}
|
||||
@@ -183,30 +184,30 @@ void Event::processCallbacks(int32_t status) const {
|
||||
}
|
||||
|
||||
bool Event::awaitCompletion() {
|
||||
if (status_ > CL_COMPLETE) {
|
||||
if (status() > CL_COMPLETE) {
|
||||
// Notifies current command queue about waiting
|
||||
if (!notifyCmdQueue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClPrint(LOG_DEBUG, LOG_WAIT, "waiting for event %p to complete, current status %d", this, status_);
|
||||
ClPrint(LOG_DEBUG, LOG_WAIT, "waiting for event %p to complete, current status %d", this, status());
|
||||
auto* queue = command().queue();
|
||||
if ((queue != nullptr) && queue->vdev()->ActiveWait()) {
|
||||
while (status_ > CL_COMPLETE) {
|
||||
while (status() > CL_COMPLETE) {
|
||||
amd::Os::yield();
|
||||
}
|
||||
} else {
|
||||
ScopedLock lock(lock_);
|
||||
|
||||
// Wait until the status becomes CL_COMPLETE or negative.
|
||||
while (status_ > CL_COMPLETE) {
|
||||
while (status() > CL_COMPLETE) {
|
||||
lock_.wait();
|
||||
}
|
||||
}
|
||||
ClPrint(LOG_DEBUG, LOG_WAIT, "event %p wait completed", this);
|
||||
}
|
||||
|
||||
return status_ == CL_COMPLETE;
|
||||
return status() == CL_COMPLETE;
|
||||
}
|
||||
|
||||
bool Event::notifyCmdQueue() {
|
||||
|
||||
@@ -90,7 +90,7 @@ class Event : public RuntimeObject {
|
||||
Monitor lock_;
|
||||
|
||||
std::atomic<CallBackEntry*> callbacks_; //!< linked list of callback entries.
|
||||
volatile int32_t status_; //!< current execution status.
|
||||
std::atomic<int32_t> status_; //!< current execution status.
|
||||
std::atomic_flag notified_; //!< Command queue was notified
|
||||
|
||||
protected:
|
||||
@@ -163,7 +163,7 @@ class Event : public RuntimeObject {
|
||||
const ProfilingInfo& profilingInfo() const { return profilingInfo_; }
|
||||
|
||||
//! Return this command's execution status.
|
||||
int32_t status() const { return status_; }
|
||||
int32_t status() const { return status_.load(std::memory_order_relaxed); }
|
||||
|
||||
//! Insert the given \a callback into the callback stack.
|
||||
bool setCallback(int32_t status, CallBackFunction callback, void* data);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "platform/memory.hpp"
|
||||
#include "device/device.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace amd {
|
||||
|
||||
bool BufferRect::create(const size_t* bufferOrigin, const size_t* region, size_t bufferRowPitch,
|
||||
@@ -277,7 +279,7 @@ bool Memory::create(void* initFrom, bool sysMemAlloc, bool skipAlloc, bool force
|
||||
|
||||
// Create memory on all available devices
|
||||
for (size_t i = 0; i < devices.size(); i++) {
|
||||
deviceAlloced_[devices[i]] = AllocInit;
|
||||
deviceAlloced_[devices[i]].store(AllocInit, std::memory_order_relaxed);
|
||||
|
||||
deviceMemories_[i].ref_ = devices[i];
|
||||
deviceMemories_[i].value_ = NULL;
|
||||
@@ -301,11 +303,11 @@ bool Memory::addDeviceMemory(const Device* dev) {
|
||||
AllocState create = AllocCreate;
|
||||
AllocState init = AllocInit;
|
||||
|
||||
if (make_atomic(deviceAlloced_[dev]).compareAndSet(init, create)) {
|
||||
if (deviceAlloced_[dev].compare_exchange_strong(init, create, std::memory_order_acq_rel)) {
|
||||
// Check if runtime already allocated all available slots for device memory
|
||||
if (numDevices() == NumDevicesWithP2P()) {
|
||||
// Mark the allocation as an empty
|
||||
deviceAlloced_[dev] = AllocInit;
|
||||
deviceAlloced_[dev].store(AllocInit, std::memory_order_release);
|
||||
return false;
|
||||
}
|
||||
device::Memory* dm = dev->createMemory(*this);
|
||||
@@ -325,17 +327,17 @@ bool Memory::addDeviceMemory(const Device* dev) {
|
||||
} else {
|
||||
LogError("Video memory allocation failed!");
|
||||
// Mark the allocation as an empty
|
||||
deviceAlloced_[dev] = AllocInit;
|
||||
deviceAlloced_[dev].store(AllocInit, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure runtime finished memory allocation.
|
||||
// Loop if in the create state
|
||||
while (deviceAlloced_[dev] == AllocCreate) {
|
||||
while (deviceAlloced_[dev].load(std::memory_order_acquire) == AllocCreate) {
|
||||
Os::yield();
|
||||
}
|
||||
|
||||
if (deviceAlloced_[dev] == AllocComplete) {
|
||||
if (deviceAlloced_[dev].load(std::memory_order_acquire) == AllocComplete) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
@@ -357,7 +359,7 @@ void Memory::replaceDeviceMemory(const Device* dev, device::Memory* dm) {
|
||||
}
|
||||
|
||||
deviceMemories_[i].value_ = dm;
|
||||
deviceAlloced_[dev] = AllocRealloced;
|
||||
deviceAlloced_[dev].store(AllocRealloced, std::memory_order_release);
|
||||
}
|
||||
|
||||
device::Memory* Memory::getDeviceMemory(const Device& dev, bool alloc) {
|
||||
|
||||
@@ -146,7 +146,7 @@ class Memory : public amd::RuntimeObject {
|
||||
DeviceMemory* deviceMemories_;
|
||||
|
||||
//! The device alloced state
|
||||
std::unordered_map<const Device*, AllocState> deviceAlloced_;
|
||||
std::unordered_map<const Device*, std::atomic<AllocState>> deviceAlloced_;
|
||||
|
||||
//! Linked list of destructor callbacks.
|
||||
std::atomic<DestructorCallBackEntry*> destructorCallbacks_;
|
||||
|
||||
@@ -102,10 +102,12 @@ public:
|
||||
~RuntimeTearDown() { /*Runtime::tearDown();*/ }
|
||||
} runtime_tear_down;
|
||||
|
||||
uint ReferenceCountedObject::retain() { return ++make_atomic(referenceCount_); }
|
||||
uint ReferenceCountedObject::retain() {
|
||||
return referenceCount_.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
}
|
||||
|
||||
uint ReferenceCountedObject::release() {
|
||||
uint newCount = --make_atomic(referenceCount_);
|
||||
uint newCount = referenceCount_.fetch_sub(1, std::memory_order_relaxed) - 1;
|
||||
if (newCount == 0) {
|
||||
if (terminate()) {
|
||||
delete this;
|
||||
|
||||
@@ -1,457 +0,0 @@
|
||||
/* Copyright (c) 2009-present Advanced Micro Devices, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE. */
|
||||
|
||||
/*! \file atomic.hpp
|
||||
* \brief Declarations for Memory order access and Atomic operations.
|
||||
*
|
||||
* \author Laurent Morichetti
|
||||
* \date October 2008
|
||||
*/
|
||||
|
||||
#ifndef ATOMIC_HPP_
|
||||
#define ATOMIC_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <intrin.h>
|
||||
#elif defined(ATI_ARCH_X86)
|
||||
#include <emmintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Threads
|
||||
* @{
|
||||
*
|
||||
* \addtogroup Atomic Atomic Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief Static functions for atomic operations.
|
||||
*/
|
||||
class AtomicOperation : AllStatic {
|
||||
private:
|
||||
//! Template to specialize atomic intrinsics on register size.
|
||||
template <int N> struct Intrinsics {
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T add(T increment, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T swap(T value, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and xchge value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T compareAndSwap(T compare, volatile T* dest, T value);
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T increment(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T decrement(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T _or(T mask, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically and \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static inline T _and(T mask, volatile T* dest);
|
||||
};
|
||||
|
||||
public:
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T add(T inc, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::add((T)inc, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T swap(T value, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::swap(value, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and exchange value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T> static T compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return Intrinsics<sizeof(T)>::compareAndSwap(compare, dest, value);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T increment(volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::increment(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic decrement.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T decrement(volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::decrement(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T _or(T mask, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::_or((T)mask, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T> static T _and(T mask, volatile T* dest) {
|
||||
return Intrinsics<sizeof(T)>::_and((T)mask, dest);
|
||||
}
|
||||
};
|
||||
|
||||
/*@}*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::add(T increment, volatile T* dest) {
|
||||
return (T)_InterlockedExchangeAdd((volatile long*)dest, (long)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::swap(T value, volatile T* dest) {
|
||||
return (T)_InterlockedExchange((volatile long*)dest, (long)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return (T)_InterlockedCompareExchange((volatile long*)dest, (long)value, (long)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::increment(volatile T* dest) {
|
||||
return (T)(_InterlockedIncrement((volatile long*)dest) - 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::decrement(volatile T* dest) {
|
||||
return (T)(_InterlockedDecrement((volatile long*)dest) + 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::_or(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedOr((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<4>::_and(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedAnd((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::add(T increment, volatile T* dest) {
|
||||
return (T)_InterlockedExchangeAdd64((volatile __int64*)dest, (__int64)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::swap(T value, volatile T* dest) {
|
||||
return (T)_InterlockedExchange64((volatile __int64*)dest, (__int64)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return (T)_InterlockedCompareExchange64((volatile __int64*)dest, (__int64)value,
|
||||
(__int64)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::increment(volatile T* dest) {
|
||||
return (T)(_InterlockedIncrement64((volatile __int64*)dest) - 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::decrement(volatile T* dest) {
|
||||
return (T)(_InterlockedDecrement64((volatile __int64*)dest) + 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::_or(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedOr64((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<8>::_and(T mask, volatile T* dest) {
|
||||
return (T)_InterlockedAnd64((volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#endif // _LP64
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::add(T inc, volatile T* dest) {
|
||||
return __sync_fetch_and_add(dest, inc);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::swap(T value, volatile T* dest) {
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::compareAndSwap(T compare, volatile T* dest, T value) {
|
||||
return __sync_val_compare_and_swap(dest, compare, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::increment(volatile T* dest) {
|
||||
return add(T(1), dest);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::decrement(volatile T* dest) {
|
||||
return add(T(-1), dest);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::_or(T mask, volatile T* dest) {
|
||||
return __sync_fetch_and_or(dest, mask);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T AtomicOperation::Intrinsics<N>::_and(T mask, volatile T* dest) {
|
||||
return __sync_fetch_and_and(dest, mask);
|
||||
}
|
||||
|
||||
#else
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
/*! \addtogroup Atomic Atomic Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief A variable of type T with atomic properties.
|
||||
*/
|
||||
template <typename T> class Atomic {
|
||||
private:
|
||||
typedef typename std::remove_volatile<
|
||||
typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type value_type;
|
||||
typename std::add_volatile<T>::type value_; //!< \brief The variable.
|
||||
|
||||
public:
|
||||
//! Construct a new %Atomic variable of type T.
|
||||
Atomic() : value_(T(0)) {}
|
||||
//! Construct a new %Atomic variable of type T from \a value.
|
||||
Atomic(T value) : value_(value) {}
|
||||
//! Construct a new %Atomic variable of type T from another %Atomic.
|
||||
Atomic(const Atomic<T>& atomic) : value_(atomic.value_) {}
|
||||
//! Copy value into this %Atomic variable.
|
||||
Atomic<T>& operator=(T value) {
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Return the %Atomic variable value.
|
||||
operator T() const { return T(value_); }
|
||||
//! Return the %Atomic variable value.
|
||||
T operator->() const { return T(value_); }
|
||||
//! Return the %Atomic variable's address.
|
||||
typename std::add_pointer<typename std::add_volatile<value_type>::type>::type operator&() {
|
||||
return &value_;
|
||||
}
|
||||
|
||||
//! Atomically add \a inc to this variable.
|
||||
Atomic<T>& operator+=(value_type inc) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically subtract \a inc to this variable.
|
||||
Atomic<T>& operator-=(value_type inc) {
|
||||
value_type modifier = 0;
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(modifier - inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically OR \a value to this variable.
|
||||
Atomic<T>& operator|=(value_type mask) {
|
||||
AtomicOperation::_or(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically AND \a value to this variable.
|
||||
Atomic<T>& operator&=(value_type mask) {
|
||||
AtomicOperation::_and(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator++() {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_) + 1;
|
||||
} else {
|
||||
return AtomicOperation::increment(&value_) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator--() {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc =
|
||||
static_cast<value_type>(-static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_) - 1;
|
||||
} else {
|
||||
return AtomicOperation::decrement(&value_) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its previous value.
|
||||
typename std::remove_reference<T>::type operator++(int) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
} else {
|
||||
return AtomicOperation::increment(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its previous value.
|
||||
T operator--(int) {
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc =
|
||||
static_cast<value_type>(-static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
} else {
|
||||
return AtomicOperation::decrement(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Atomically compare this variable with \a compare and set
|
||||
* to value if equals
|
||||
*/
|
||||
bool compareAndSet(T compare, T value) {
|
||||
return compare == AtomicOperation::compareAndSwap(compare, &value_, value);
|
||||
}
|
||||
|
||||
//! Atomically set this variable to \a value and return its previous value.
|
||||
T swap(T value) { return AtomicOperation::swap(value, &value_); }
|
||||
|
||||
/*! \brief Execute a stores fence followed by a store to this variable.
|
||||
*
|
||||
* This storeRelease operation ensures that all store to memory operations
|
||||
* preceding this function will be globally visible before the update to
|
||||
* this variable's value.
|
||||
*/
|
||||
void storeRelease(T value) {
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
/*! \brief Execute a load from this variable followed by a loads fence.
|
||||
*
|
||||
* This loadAcquire operation ensures that all load from memory operations
|
||||
* following this function will be globally visible after the read from
|
||||
* this variable's value.
|
||||
*/
|
||||
T loadAcquire() const {
|
||||
T value = value_;
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
//! Helper function to tie an Atomic<T&> to a variable of type T.
|
||||
template <typename T> inline Atomic<T&> make_atomic(T& t) { return Atomic<T&>(t); }
|
||||
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*ATOMIC_HPP_*/
|
||||
@@ -19,11 +19,11 @@
|
||||
THE SOFTWARE. */
|
||||
|
||||
#include "thread/monitor.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define MONITOR_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user