Files
TheRock/rocm-libraries/projects/hipthreads/inc/hip/__mutex/unique_lock.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

289 lines
11 KiB
C++

// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Modifications Copyright (c) 2025 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.
#ifndef __LIBHIPTHREADS___MUTEX_UNIQUE_LOCK_H__
#define __LIBHIPTHREADS___MUTEX_UNIQUE_LOCK_H__
#include "hip/thread_config"
#include <mutex>
#include "hip/std/__memory/addressof.h"
#include "hip/std/__utility/swap.h"
/**
* @file
* @brief Flexible RAII mutex wrapper supporting deferred / try / adopt locking and move transfer.
* @ingroup mutex
*
* Device-side analogue of std::unique_lock. Compared to lock_guard this adds:
* - Optional acquisition strategies (immediate lock, defer, try, adopt).
* - Move semantics (transfer ownership between unique_lock objects).
* - Explicit lock()/unlock()/try_lock() member functions for use with
* condition variables and manual lock management.
*
* Planned (not yet enabled): timed locking (try_lock_for / try_lock_until).
*
* Warning:
* As with any RAII lock, do not create an unnamed temporary
* (e.g. unique_lock<spin_mutex>{m};) — it unlocks immediately.
*/
namespace cuda {
//====================================================================================================================//
// Adapted from libc++ ::std::unique_lock
//====================================================================================================================//
/**
* @tparam _Mutex Mutex type meeting BasicLockable (lock(), unlock()).
* @brief Movable (not copyable) lock owning at most one mutex.
* @ingroup mutex
*
* Features:
* - Multiple constructor tags: (default), defer_lock, try_to_lock, adopt_lock.
* - Manual lock()/unlock()/try_lock().
* - Release without unlocking (release()).
* - Ownership query (owns_lock() / operator bool()).
* - Move construct / assign transfers ownership; source is left empty.
*
* Invariants:
* - If owns_lock() is true then mutex() is non-null and locked by this wthread.
* - Destruction unlocks only if ownership is held.
*
* Timed locking hooks are commented out (TODO) — will forward to underlying mutex
* once TimedLockable support is implemented.
*/
template <class _Mutex>
class _LIBHIPTHREADS_TEMPLATE_VIS unique_lock {
public:
/// Underlying mutex type.
typedef _Mutex mutex_type;
private:
mutex_type* __m_;
bool __owns_;
public:
/// Constructs an empty non-owning lock (mutex() == nullptr).
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock() _NOEXCEPT : __m_(nullptr), __owns_(false) {}
/**
* @brief Locks the supplied mutex immediately.
* @param __m Target mutex (must not already be locked by this wthread).
* @post owns_lock() == true
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI explicit unique_lock(mutex_type& __m) : __m_(hip::std::addressof(__m)), __owns_(true) {
__m_->lock();
}
/**
* @brief Associates with a mutex without locking it yet.
* @param __m Target mutex.
* @param (defer_lock) Tag indicating deferred acquisition.
* @post owns_lock() == false
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(mutex_type& __m, ::std::defer_lock_t) _NOEXCEPT
: __m_(hip::std::addressof(__m)),
__owns_(false) {}
/**
* @brief Attempts to lock without blocking.
* @param __m Target mutex.
* @param (try_to_lock) Tag requesting a non-blocking attempt.
* @post owns_lock() reflects success.
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(mutex_type& __m, ::std::try_to_lock_t)
: __m_(hip::std::addressof(__m)), __owns_(__m.try_lock()) {}
/**
* @brief Assumes caller already holds the mutex.
* @param __m Target mutex already locked by this wthread.
* @param (adopt_lock) Tag asserting prior lock ownership.
* @pre Current wthread owns __m.
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(mutex_type& __m, ::std::adopt_lock_t) : __m_(hip::std::addressof(__m)), __owns_(true) {}
// TODO: Uncomment this once we implement chrono
// template <class _Clock, class _Duration>
// __device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::time_point<_Clock, _Duration>& __t)
// : __m_(hip::addressof(__m)), __owns_(__m.try_lock_until(__t)) {}
// TODO: Uncomment this once we implement chrono
// template <class _Rep, class _Period>
// __device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(mutex_type& __m, const chrono::duration<_Rep, _Period>& __d)
// : __m_(hip::addressof(__m)), __owns_(__m.try_lock_for(__d)) {}
/// Destructor unlocks if ownership is held.
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI ~unique_lock() {
if (__owns_)
__m_->unlock();
}
/// \name Deleted copy operations
/// Instances are movable but not copyable.
///@{
__device__ unique_lock(unique_lock const&) = delete;
__device__ unique_lock& operator=(unique_lock const&) = delete;
///@}
/**
* @brief Move constructs, transferring ownership.
* @param __u Source; becomes empty afterward.
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock(unique_lock&& __u) _NOEXCEPT : __m_(__u.__m_), __owns_(__u.__owns_) {
__u.__m_ = nullptr;
__u.__owns_ = false;
}
/**
* @brief Move assigns, releasing any owned mutex then taking __u's.
* @param __u Source; becomes empty.
* @return *this
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI unique_lock& operator=(unique_lock&& __u) _NOEXCEPT {
if (__owns_)
__m_->unlock();
__m_ = __u.__m_;
__owns_ = __u.__owns_;
__u.__m_ = nullptr;
__u.__owns_ = false;
return *this;
}
/**
* @brief Locks the associated mutex (must be associated & not owned).
* @throws (asserts in device build on misuse).
* @post owns_lock() == true
*/
__device__ void lock();
/**
* @brief Attempts to lock without blocking.
* @return true if the lock was obtained.
* @post owns_lock() reflects result.
*/
__device__ bool try_lock();
// TODO: Uncomment this once we implement chrono
// template <class _Rep, class _Period>
// __device__ bool try_lock_for(const chrono::duration<_Rep, _Period>& __d);
// TODO: Uncomment this once we implement chrono
// template <class _Clock, class _Duration>
// __device__ bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
/**
* @brief Unlocks the mutex.
* @pre owns_lock() == true
* @post owns_lock() == false
*/
__device__ void unlock();
/**
* @brief Exchanges state with another unique_lock.
* @param __u Other lock.
* @post Ownership flags and mutex pointers swapped.
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI void swap(unique_lock& __u) _NOEXCEPT {
hip::std::swap(__m_, __u.__m_);
hip::std::swap(__owns_, __u.__owns_);
}
/**
* @brief Releases association without unlocking.
* @return Previously associated mutex pointer (may be null).
* @post mutex()==nullptr && owns_lock()==false
*/
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI mutex_type* release() _NOEXCEPT {
mutex_type* __m = __m_;
__m_ = nullptr;
__owns_ = false;
return __m;
}
/// True if this object currently owns the mutex.
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI bool owns_lock() const _NOEXCEPT { return __owns_; }
/// Same as owns_lock().
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __owns_; }
/// Pointer to the associated mutex (may be null if default-constructed or released).
__device__ _LIBHIPTHREADS_HIDE_FROM_ABI mutex_type* mutex() const _NOEXCEPT { return __m_; }
};
_LIBHIPTHREADS_CTAD_SUPPORTED_FOR_TYPE(unique_lock);
template <class _Mutex>
__device__ void unique_lock<_Mutex>::lock() {
assert(__m_ != nullptr && "unique_lock::lock: references null mutex");
assert(!__owns_ && "unique_lock::lock: already locked");
__m_->lock();
__owns_ = true;
}
template <class _Mutex>
__device__ bool unique_lock<_Mutex>::try_lock() {
assert(__m_ != nullptr && "unique_lock::try_lock: references null mutex");
assert(!__owns_ && "unique_lock::try_lock: already locked");
__owns_ = __m_->try_lock();
return __owns_;
}
// TODO: Uncomment this once we implement chrono
// template <class _Mutex>
// template <class _Rep, class _Period>
// __device__ bool unique_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d) {
// assert(__m_ != nullptr && "unique_lock::try_lock_for: references null mutex");
// assert(!__owns_ && "unique_lock::try_lock_for: already locked");
// __owns_ = __m_->try_lock_for(__d);
// return __owns_;
// }
// TODO: Uncomment this once we implement chrono
// template <class _Mutex>
// template <class _Clock, class _Duration>
// __device__ bool unique_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) {
// assert(__m_ != nullptr && "unique_lock::try_lock_until: references null mutex");
// assert(!__owns_ && "unique_lock::try_lock_until: already locked");
// __owns_ = __m_->try_lock_until(__t);
// return __owns_;
// }
template <class _Mutex>
__device__ void unique_lock<_Mutex>::unlock() {
assert(__owns_ && "unique_lock::unlock: not locked");
__m_->unlock();
__owns_ = false;
}
template <class _Mutex>
__device__ inline _LIBHIPTHREADS_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) _NOEXCEPT {
__x.swap(__y);
}
} // namespace cuda
#endif // __LIBHIPTHREADS___MUTEX_UNIQUE_LOCK_H__