Program Listing for File nonlocking_queue_impl.h
↰ Return to documentation for file (include/embers/primitives/nonlocking_queue_impl.h
)
/* Copyright © 2020 Advanced Micro Devices, Inc. All rights reserved */
#ifndef _EMBERS_NONLOCKING_QUEUE_IMPL_H_
#define _EMBERS_NONLOCKING_QUEUE_IMPL_H_
#include "embers/primitives/backoff.h"
#include "nonlocking_queue.h"
namespace embers
{
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ typename NonLockingQueue<T, MonCntType, scope_>::Contents
NonLockingQueue<T, MonCntType, scope_>::MakeQueueContents(
int hip_dev, unsigned int queue_flags, typename MonCntType::counter_int_type log2_size)
{
return Contents(log2_size, device::make_unique_with_attributes<
Entry[]>(hip_dev, queue_flags,
typename MonCntType::counter_int_type(1) << log2_size));
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ typename NonLockingQueue<T, MonCntType, scope_>::Contents
NonLockingQueue<T, MonCntType, scope_>::MakeQueueContentsHost(
unsigned int queue_flags, typename MonCntType::counter_int_type log2_size)
{
return Contents(log2_size,
host::make_unique_with_attributes<Entry[]>(queue_flags,
typename MonCntType::counter_int_type(
1)
<< log2_size));
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ NonLockingQueue<T, MonCntType, scope_>::NonLockingQueue(Contents contents)
: num_slots_(1 << contents.log2_size),
head_(MonCntType()),
tail_(MonCntType()),
contents_(std::move(contents.data))
{
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ inline typename MonCntType::counter_int_type
NonLockingQueue<T, MonCntType, scope_>::QIDX(typename MonCntType::counter_int_type val)
{
/* element_index = val % num_slot_s
* Since num_slots_ is always a power of two, this can be optimized to an AND operation
*/
return val & (num_slots_ - 1);
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ inline typename NonLockingQueue<T, MonCntType, scope_>::Entry *
NonLockingQueue<T, MonCntType, scope_>::GetEntry(typename MonCntType::counter_int_type index)
{
return &contents_[std::size_t(index)];
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ inline bool NonLockingQueue<T, MonCntType, scope_>::Empty()
{
return (head_.Value() - tail_.Value() == 0);
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ inline bool NonLockingQueue<T, MonCntType, scope_>::Full()
{
return (head_.Value() - tail_.Value() == num_slots_);
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ void NonLockingQueue<T, MonCntType, scope_>::Reset()
{
head_.Reset();
tail_.Reset();
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ T NonLockingQueue<T, MonCntType, scope_>::Dequeue()
{
while (true) {
if (Empty()) {
backoff();
continue;
}
typename MonCntType::counter_int_type index;
// wait until our commital has been accepted
while (!tail_.Appoint(&index, 1)) {
}
Entry *e = GetEntry(QIDX(index));
// wait for the data to be valid.
while (!e->LockEntry(Entry::VALID)) backoff();
e->AcquireFence();
// read the packet
T temp = e->data;
e->InvalidateAndRelease();
return temp;
}
}
template <typename T, typename MonCntType, MemoryScope scope_>
__host__ __device__ void NonLockingQueue<T, MonCntType, scope_>::Enqueue(T item)
{
while (true) {
if (Full()) {
backoff();
continue;
}
typename MonCntType::counter_int_type index;
// wait until our commital has been accepted
while (!head_.Appoint(&index, 1)) {
}
Entry *e = GetEntry(QIDX(index));
// wait for the data to be invalid.
while (!e->LockEntry(Entry::INVALID)) backoff();
e->data = item;
e->SetValidAndRelease();
return;
}
}
} // namespace embers
#endif // _EMBERS_NONLOCKING_QUEUE_IMPL_H_