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