From 3227859ff21306c2f60d009e0a2b9d602322ea84 Mon Sep 17 00:00:00 2001 From: Sean Keely Date: Wed, 3 Nov 2021 01:24:00 -0500 Subject: [PATCH] Rework memory locks to allow device parallelism in alloc/free. Prior solution used a single global lock to protect the memory tracking structures. This change protects the memory tracking structure with a shared mutex (rw lock) in shared (r) mode for memory allocations and frees so that long duration processes, calling to kfd, can be done in parallel. Operations which must modify the memory map take the mutex in exclusive mode (w) and must not call to the thunk while holding the mutex. The fragment allocator now requires separate protection and is protected with a mutex at the device level. Protecting at the device level, rather than pool, allows retention of the current recursive design and allows calling Trim from withing Allocate. This could be made finer (pool level locks) but would require backing out of Allocate entirely to call Trim. Trim and any retried Allocation must be done in isolation (per device) or we may report OOM when memory is actually available in some pool's fragment cache. So some device level serialization is required in at least some paths. Change-Id: I7c1e94d6965ffcc602b12fefdd3a6e97b84b5e00 [ROCm/ROCR-Runtime commit: df55cb04507c0953a196d47b21f85c43aec13d08] --- .../runtime/hsa-runtime/core/inc/agent.h | 15 ++ .../hsa-runtime/core/inc/amd_memory_region.h | 10 +- .../runtime/hsa-runtime/core/inc/runtime.h | 5 +- .../core/runtime/amd_memory_region.cpp | 22 ++- .../hsa-runtime/core/runtime/runtime.cpp | 33 ++-- .../hsa-runtime/core/util/lnx/os_linux.cpp | 58 +++++++ .../runtime/hsa-runtime/core/util/locks.h | 142 ++++++++++++++---- .../runtime/hsa-runtime/core/util/os.h | 43 ++++++ .../hsa-runtime/core/util/win/os_win.cpp | 46 ++++++ 9 files changed, 320 insertions(+), 54 deletions(-) diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/agent.h b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/agent.h index 08683934cf..d669ab16ec 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/agent.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/agent.h @@ -53,8 +53,15 @@ #include "core/inc/queue.h" #include "core/inc/memory_region.h" #include "core/util/utils.h" +#include "core/util/locks.h" namespace rocr { + +// Forward declare AMD::MemoryRegion +namespace AMD { +class MemoryRegion; +} + namespace core { class Signal; @@ -65,6 +72,8 @@ typedef void (*HsaEventCallback)(hsa_status_t status, hsa_queue_t* source, // replaced by tools libraries. All funtions other than Convert, node_id, // device_type, and public_handle must be virtual. class Agent : public Checked<0xF6BC25EB17E6F917> { + friend class rocr::AMD::MemoryRegion; + public: // @brief Convert agent object into hsa_agent_t. // @@ -297,6 +306,12 @@ class Agent : public Checked<0xF6BC25EB17E6F917> { bool profiling_enabled_; + // Used by an Agent's MemoryRegions to ensure serial memory operation on the device. + // Serial memory operations are needed to ensure, among other things, that allocation failures are + // due to true OOM conditions and per region caching (Trim and Allocate must be serial and + // exclusive to ensure this). + KernelMutex agent_memory_lock_; + // Forbid copying and moving of this object DISALLOW_COPY_AND_ASSIGN(Agent); }; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_memory_region.h b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_memory_region.h index cce01e6587..f682415858 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_memory_region.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/amd_memory_region.h @@ -185,6 +185,8 @@ class MemoryRegion : public core::MemoryRegion { HSAuint64 virtual_size_; + // Protects against concurrent allow_access calls to fragments of the same block by virtue of all + // fragments of the block routing to the same MemoryRegion. mutable KernelMutex access_lock_; static const size_t kPageSize_ = 4096; @@ -193,6 +195,12 @@ class MemoryRegion : public core::MemoryRegion { hsa_amd_memory_pool_access_t GetAccessInfo(const core::Agent& agent, const core::Runtime::LinkInfo& link_info) const; + // Operational body for Allocate. Recursive. + hsa_status_t AllocateImpl(size_t& size, AllocateFlags alloc_flags, void** address) const; + + // Operational body for Free. Recursive. + hsa_status_t FreeImpl(void* address, size_t size) const; + class BlockAllocator { private: MemoryRegion& region_; @@ -200,7 +208,7 @@ class MemoryRegion : public core::MemoryRegion { public: explicit BlockAllocator(MemoryRegion& region) : region_(region) {} void* alloc(size_t request_size, size_t& allocated_size) const; - void free(void* ptr, size_t length) const { region_.Free(ptr, length); } + void free(void* ptr, size_t length) const { region_.FreeImpl(ptr, length); } size_t block_size() const { return block_size_; } }; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h index c31b2f7ba5..9f5b8acc5c 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/inc/runtime.h @@ -490,10 +490,11 @@ class Runtime { /// @brief Get the highest used node id. uint32_t max_node_id() const { return agents_by_node_.rbegin()->first; } - // Mutex object to protect multithreaded access to ::allocation_map_, + // Mutex object to protect multithreaded access to ::allocation_map_. + // Also ensures atomicity of pointer info queries by interlocking // KFD map/unmap, register/unregister, and access to hsaKmtQueryPointerInfo // registered & mapped arrays. - KernelMutex memory_lock_; + KernelSharedMutex memory_lock_; // Array containing tools library handles. std::vector tool_libs_; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/amd_memory_region.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/amd_memory_region.cpp index d96e5db294..7cbb543957 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/amd_memory_region.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/amd_memory_region.cpp @@ -157,6 +157,12 @@ MemoryRegion::MemoryRegion(bool fine_grain, bool kernarg, bool full_profile, cor MemoryRegion::~MemoryRegion() {} hsa_status_t MemoryRegion::Allocate(size_t& size, AllocateFlags alloc_flags, void** address) const { + ScopedAcquire lock(&owner()->agent_memory_lock_); + return AllocateImpl(size, alloc_flags, address); +} + +hsa_status_t MemoryRegion::AllocateImpl(size_t& size, AllocateFlags alloc_flags, + void** address) const { if (address == NULL) { return HSA_STATUS_ERROR_INVALID_ARGUMENT; } @@ -251,6 +257,11 @@ hsa_status_t MemoryRegion::Allocate(size_t& size, AllocateFlags alloc_flags, voi } hsa_status_t MemoryRegion::Free(void* address, size_t size) const { + ScopedAcquire lock(&owner()->agent_memory_lock_); + return FreeImpl(address, size); +} + +hsa_status_t MemoryRegion::FreeImpl(void* address, size_t size) const { if (fragment_allocator_.free(address)) return HSA_STATUS_SUCCESS; MakeKfdMemoryUnresident(address); @@ -262,6 +273,7 @@ hsa_status_t MemoryRegion::Free(void* address, size_t size) const { // TODO: Look into a better name and/or making this process transparent to exporting. hsa_status_t MemoryRegion::IPCFragmentExport(void* address) const { + ScopedAcquire lock(&owner()->agent_memory_lock_); if (!fragment_allocator_.discardBlock(address)) return HSA_STATUS_ERROR_INVALID_ALLOCATION; return HSA_STATUS_SUCCESS; } @@ -583,8 +595,10 @@ hsa_status_t MemoryRegion::AllowAccess(uint32_t num_agents, HsaMemMapFlags map_flag = map_flag_; map_flag.ui32.HostAccess |= (cpu_in_list) ? 1 : 0; - { - ScopedAcquire lock(&core::Runtime::runtime_singleton_->memory_lock_); + { // Sequence with pointer info since queries to other fragments of the block may be adjusted by + // this call. + ScopedAcquire lock( + core::Runtime::runtime_singleton_->memory_lock_.shared()); uint64_t alternate_va = 0; if (!AMD::MemoryRegion::MakeKfdMemoryResident( whitelist_nodes.size(), &whitelist_nodes[0], ptr, @@ -593,8 +607,6 @@ hsa_status_t MemoryRegion::AllowAccess(uint32_t num_agents, } } - lock.Release(); - return HSA_STATUS_SUCCESS; } @@ -700,7 +712,7 @@ void* MemoryRegion::BlockAllocator::alloc(size_t request_size, size_t& allocated void* ret; size_t bsize = AlignUp(request_size, block_size()); - hsa_status_t err = region_.Allocate( + hsa_status_t err = region_.AllocateImpl( bsize, core::MemoryRegion::AllocateRestrict | core::MemoryRegion::AllocateDirect, &ret); if (err != HSA_STATUS_SUCCESS) throw AMD::hsa_exception(err, "MemoryRegion::BlockAllocator::alloc failed."); diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp index 4673ae093b..019b739ca9 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/runtime/runtime.cpp @@ -276,11 +276,10 @@ hsa_status_t Runtime::IterateAgent(hsa_status_t (*callback)(hsa_agent_t agent, hsa_status_t Runtime::AllocateMemory(const MemoryRegion* region, size_t size, MemoryRegion::AllocateFlags alloc_flags, void** address) { - ScopedAcquire lock(&memory_lock_); hsa_status_t status = region->Allocate(size, alloc_flags, address); - // Track the allocation result so that it could be freed properly. if (status == HSA_STATUS_SUCCESS) { + ScopedAcquire lock(&memory_lock_); allocation_map_[*address] = AllocationRegion(region, size); } @@ -297,7 +296,7 @@ hsa_status_t Runtime::FreeMemory(void* ptr) { std::unique_ptr> notifiers; { - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); std::map::iterator it = allocation_map_.find(ptr); @@ -317,26 +316,23 @@ hsa_status_t Runtime::FreeMemory(void* ptr) { notifiers = std::move(it->second.notifiers); allocation_map_.erase(it); - - // Fast path to avoid doubling lock ops in the common case (no notifiers). - if (!notifiers) return region->Free(ptr, size); } // Notifiers can't run while holding the lock or the callback won't be able to manage memory. // The memory triggering the notification has already been removed from the memory map so can't // be double released during the callback. - for (auto& notifier : *notifiers) { - notifier.callback(notifier.ptr, notifier.user_data); + if (notifiers) { + for (auto& notifier : *notifiers) { + notifier.callback(notifier.ptr, notifier.user_data); + } } - // Fragment allocator requires protection. - ScopedAcquire lock(&memory_lock_); return region->Free(ptr, size); } hsa_status_t Runtime::RegisterReleaseNotifier(void* ptr, hsa_amd_deallocation_callback_t callback, void* user_data) { - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); auto mem = allocation_map_.upper_bound(ptr); if (mem != allocation_map_.begin()) { mem--; @@ -360,7 +356,7 @@ hsa_status_t Runtime::RegisterReleaseNotifier(void* ptr, hsa_amd_deallocation_ca hsa_status_t Runtime::DeregisterReleaseNotifier(void* ptr, hsa_amd_deallocation_callback_t callback) { hsa_status_t ret = HSA_STATUS_ERROR_INVALID_ARGUMENT; - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); auto mem = allocation_map_.upper_bound(ptr); if (mem != allocation_map_.begin()) { mem--; @@ -560,7 +556,7 @@ hsa_status_t Runtime::AllowAccess(uint32_t num_agents, size_t alloc_size = 0; { - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); std::map::const_iterator it = allocation_map_.find(ptr); @@ -786,7 +782,7 @@ hsa_status_t Runtime::PtrInfo(const void* ptr, hsa_amd_pointer_info_t* info, voi { // memory_lock protects access to the NMappedNodes array and fragment user data since these may // change with calls to memory APIs. - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); // We don't care if this returns an error code. // The type will be HSA_EXT_POINTER_TYPE_UNKNOWN if so. @@ -886,7 +882,7 @@ hsa_status_t Runtime::PtrInfo(const void* ptr, hsa_amd_pointer_info_t* info, voi hsa_status_t Runtime::SetPtrInfoData(const void* ptr, void* userptr) { { // Use allocation map if possible to handle fragments. - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); const auto& it = allocation_map_.find(ptr); if (it != allocation_map_.end()) { it->second.user_ptr = userptr; @@ -926,7 +922,7 @@ hsa_status_t Runtime::IPCCreate(void* ptr, size_t len, hsa_amd_ipc_memory_t* han // Holds size in (4K?) pages in thunk handle: Mark as a fragment and denote offset. handle->handle[6] |= 0x80000000 | offset; // Mark block for IPC. Prevents reallocation of exported memory. - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(memory_lock_.shared()); hsa_status_t err = allocation_map_[ptr].region->IPCFragmentExport(ptr); assert(err == HSA_STATUS_SUCCESS && "Region inconsistent with address map."); return err; @@ -951,11 +947,12 @@ hsa_status_t Runtime::IPCAttach(const hsa_amd_ipc_memory_t* handle, size_t len, // Extract fragment info bool isFragment = false; uint32_t fragOffset = 0; + auto fixFragment = [&]() { if (!isFragment) return; importAddress = reinterpret_cast(importAddress) + fragOffset; len = Min(len, importSize - fragOffset); - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); allocation_map_[importAddress] = AllocationRegion(nullptr, len); }; @@ -1017,7 +1014,7 @@ hsa_status_t Runtime::IPCAttach(const hsa_amd_ipc_memory_t* handle, size_t len, hsa_status_t Runtime::IPCDetach(void* ptr) { { // Handle imported fragments. - ScopedAcquire lock(&memory_lock_); + ScopedAcquire lock(&memory_lock_); const auto& it = allocation_map_.find(ptr); if (it != allocation_map_.end()) { if (it->second.region != nullptr) return HSA_STATUS_ERROR_INVALID_ARGUMENT; diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp index 6c27611519..b5d64fb57c 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/lnx/os_linux.cpp @@ -168,6 +168,7 @@ class os_thread { static_assert(sizeof(LibHandle) == sizeof(void*), "OS abstraction size mismatch"); static_assert(sizeof(Mutex) == sizeof(pthread_mutex_t*), "OS abstraction size mismatch"); +static_assert(sizeof(SharedMutex) == sizeof(pthread_rwlock_t*), "OS abstraction size mismatch"); static_assert(sizeof(Thread) == sizeof(os_thread*), "OS abstraction size mismatch"); LibHandle LoadLib(std::string filename) { @@ -457,6 +458,63 @@ uint64_t AccurateClockFrequency() { if (invPeriod == 0.0) invPeriod = 1.0 / double(time.tv_nsec); return 1000000000ull / uint64_t(time.tv_nsec); } + +SharedMutex CreateSharedMutex() { + pthread_rwlockattr_t attrib; + int err = pthread_rwlockattr_init(&attrib); + if (err != 0) { + assert(false && "rw lock attribute init failed."); + return nullptr; + } + err = pthread_rwlockattr_setkind_np(&attrib, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + assert(err == 0 && "Set rw lock attribute failure."); + + pthread_rwlock_t* lock = new pthread_rwlock_t; + err = pthread_rwlock_init(lock, &attrib); + if (err != 0) { + assert(false && "rw lock init failed."); + return nullptr; + } + + pthread_rwlockattr_destroy(&attrib); + return lock; +} + +bool TryAcquireSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_trywrlock(*(pthread_rwlock_t**)&lock); + return err == 0; +} + +bool AcquireSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_wrlock(*(pthread_rwlock_t**)&lock); + return err == 0; +} + +void ReleaseSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_unlock(*(pthread_rwlock_t**)&lock); + assert(err == 0 && "SharedMutex unlock failed."); +} + +bool TrySharedAcquireSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_tryrdlock(*(pthread_rwlock_t**)&lock); + return err == 0; +} + +bool SharedAcquireSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_rdlock(*(pthread_rwlock_t**)&lock); + return err == 0; +} + +void SharedReleaseSharedMutex(SharedMutex lock) { + int err = pthread_rwlock_unlock(*(pthread_rwlock_t**)&lock); + assert(err == 0 && "SharedMutex unlock failed."); +} + +void DestroySharedMutex(SharedMutex lock) { + pthread_rwlock_destroy(*(pthread_rwlock_t**)&lock); + delete *(pthread_rwlock_t**)&lock; +} + } // namespace os } // namespace rocr diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/locks.h b/projects/rocr-runtime/runtime/hsa-runtime/core/util/locks.h index 49ad6906fe..fd4d4569ba 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/locks.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/locks.h @@ -50,34 +50,6 @@ namespace rocr { -/// @brief: A class behaves as a lock in a scope. When trying to enter into the -/// critical section, creat a object of this class. After the control path goes -/// out of the scope, it will release the lock automatically. -template -class ScopedAcquire { - public: - /// @brief: When constructing, acquire the lock. - /// @param: lock(Input), pointer to an existing lock. - explicit ScopedAcquire(LockType* lock) : lock_(lock), doRelease(true) { lock_->Acquire(); } - - /// @brief: when destructing, release the lock. - ~ScopedAcquire() { - if (doRelease) lock_->Release(); - } - - /// @brief: Release the lock early. Avoid using when possible. - void Release() { - lock_->Release(); - doRelease = false; - } - - private: - LockType* lock_; - bool doRelease; - /// @brief: Disable copiable and assignable ability. - DISALLOW_COPY_AND_ASSIGN(ScopedAcquire); -}; - /// @brief: a class represents a kernel mutex. /// Uses the kernel's scheduler to keep the waiting thread from being scheduled /// until the lock is released (Best for long waits, though anything using @@ -144,6 +116,120 @@ class KernelEvent { DISALLOW_COPY_AND_ASSIGN(KernelEvent); }; +/// @brief: represents a yielding shared mutex. +/// aka read/write mutex +class KernelSharedMutex { + public: + /// @brief: Interfaces ScopedAcquire to shared operations. + class Shared { + public: + explicit Shared(KernelSharedMutex* lock) : lock_(lock) {} + bool Try() { return lock_->TryShared(); } + bool Acquire() { return lock_->AcquireShared(); } + void Release() { lock_->ReleaseShared(); } + + private: + KernelSharedMutex* lock_; + }; + + KernelSharedMutex() { lock_ = os::CreateSharedMutex(); } + ~KernelSharedMutex() { os::DestroySharedMutex(lock_); } + + // Exclusive mode operations + bool Try() { return os::TryAcquireSharedMutex(lock_); } + bool Acquire() { return os::AcquireSharedMutex(lock_); } + void Release() { os::ReleaseSharedMutex(lock_); } + + // Shared mode operations + bool TryShared() { return os::TrySharedAcquireSharedMutex(lock_); } + bool AcquireShared() { return os::SharedAcquireSharedMutex(lock_); } + void ReleaseShared() { os::SharedReleaseSharedMutex(lock_); } + + // Return shared operations interface + Shared shared() { return Shared(this); } + + private: + os::SharedMutex lock_; + + /// @brief: Disable copiable and assignable ability. + DISALLOW_COPY_AND_ASSIGN(KernelSharedMutex); +}; + +/// @brief: Type trait to identify mutex types +template class isMutex { + public: + enum { value = false }; +}; +template <> class isMutex { + public: + enum { value = true }; +}; +template <> class isMutex { + public: + enum { value = true }; +}; +template <> class isMutex { + public: + enum { value = true }; +}; + +/// @brief: A class behaves as a lock in a scope. When trying to enter into the +/// critical section, creat a object of this class. After the control path goes +/// out of the scope, it will release the lock automatically. +template class ScopedAcquire { + public: + /// @brief: When constructing, acquire the lock. + /// @param: lock(Input), pointer to an existing lock. + explicit ScopedAcquire(LockType* lock) : lock_(lock), doRelease(true) { + static_assert(isMutex::value, "ScopedAcquire requires a mutex type."); + lock_.Acquire(); + } + explicit ScopedAcquire(LockType lock) : lock_(lock), doRelease(true) { + static_assert(!isMutex::value, "Mutex types are not copyable."); + lock_.Acquire(); + } + + /// @brief: when destructing, release the lock. + ~ScopedAcquire() { + if (doRelease) lock_.Release(); + } + + /// @brief: Release the lock early. Avoid using when possible. + void Release() { + lock_.Release(); + doRelease = false; + } + + private: + /// @brief: Adapts between pointers to mutex types and mutex pointer types. + template class container { + public: + container(T* lock) : lock_(lock) {} + __forceinline bool Acquire() { return lock_->Acquire(); } + __forceinline void Release() { return lock_->Release(); } + + private: + T* lock_; + }; + + /// @brief: Specialization for mutex pointer types. + template class container { + public: + container(T lock) : lock_(lock) {} + __forceinline bool Acquire() { return lock_.Acquire(); } + __forceinline void Release() { return lock_.Release(); } + + private: + T lock_; + }; + + container::value> lock_; + bool doRelease; + + /// @brief: Disable copiable and assignable ability. + DISALLOW_COPY_AND_ASSIGN(ScopedAcquire); +}; + } // namespace rocr #endif // HSA_RUNTIME_CORE_SUTIL_LOCKS_H_ diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h b/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h index ec9f54a422..134ee9a87a 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/os.h @@ -52,6 +52,7 @@ namespace rocr { namespace os { typedef void* LibHandle; typedef void* Mutex; +typedef void* SharedMutex; typedef void* Thread; typedef void* EventHandle; @@ -110,6 +111,48 @@ void ReleaseMutex(Mutex lock); /// @return: void. void DestroyMutex(Mutex lock); +/// @brief: Creates a shared mutex, will return NULL if failed. +/// @param: void. +/// @return: SharedMutex. +SharedMutex CreateSharedMutex(); + +/// @brief: Tries to acquire the mutex in exclusive mode once, if successed, return true. +/// @param: lock(Input), handle to the shared mutex. +/// @return: bool. +bool TryAcquireSharedMutex(SharedMutex lock); + +/// @brief: Aquires the mutex in exclusive mode, if the mutex is locked, it will wait until it is +/// released. If the mutex is acquired successfully, it will return true. +/// @param: lock(Input), handle to the mutex. +/// @return: bool. +bool AcquireSharedMutex(SharedMutex lock); + +/// @brief: Releases the mutex from exclusive mode. +/// @param: lock(Input), handle to the mutex. +/// @return: void. +void ReleaseSharedMutex(SharedMutex lock); + +/// @brief: Tries to acquire the mutex in shared mode once, if successed, return true. +/// @param: lock(Input), handle to the mutex. +/// @return: bool. +bool TrySharedAcquireSharedMutex(SharedMutex lock); + +/// @brief: Aquires the mutex in shared mode, if the mutex in exclusive mode, it will wait until it +/// is released. If the mutex is acquired successfully, it will return true. +/// @param: lock(Input), handle to the mutex. +/// @return: bool. +bool SharedAcquireSharedMutex(SharedMutex lock); + +/// @brief: Releases the mutex from shared mode. +/// @param: lock(Input), handle to the mutex. +/// @return: void. +void SharedReleaseSharedMutex(SharedMutex lock); + +/// @brief: Destroys the mutex. +/// @param: lock(Input), handle to the mutex. +/// @return: void. +void DestroySharedMutex(SharedMutex lock); + /// @brief: Puts current thread to sleep. /// @param: delayInMs(Input), time in millisecond for sleeping. /// @return: void. diff --git a/projects/rocr-runtime/runtime/hsa-runtime/core/util/win/os_win.cpp b/projects/rocr-runtime/runtime/hsa-runtime/core/util/win/os_win.cpp index 226b54b4ac..cc543d5284 100644 --- a/projects/rocr-runtime/runtime/hsa-runtime/core/util/win/os_win.cpp +++ b/projects/rocr-runtime/runtime/hsa-runtime/core/util/win/os_win.cpp @@ -224,6 +224,52 @@ uint64_t AccurateClockFrequency() { QueryPerformanceFrequency((LARGE_INTEGER*)&ret); return ret; } + +SharedMutex CreateSharedMutex() { + assert(false && "Not implemented."); + abort(); + return nullptr; +} + +bool TryAcquireSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); + return false; +} + +bool AcquireSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); + return false; +} + +void ReleaseSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); +} + +bool TrySharedAcquireSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); + return false; +} + +bool SharedAcquireSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); + return false; +} + +void SharedReleaseSharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); +} + +void DestroySharedMutex(SharedMutex lock) { + assert(false && "Not implemented."); + abort(); +} + } // namespace os } // namespace rocr