Program Listing for File locking_queue.h

Return to documentation for file (include/embers/primitives/locking_queue.h)

/* Copyright © 2020 Advanced Micro Devices, Inc. All rights reserved */

#ifndef _EMBERS_LOCKING_QUEUE_H_
#define _EMBERS_LOCKING_QUEUE_H_

#include "embers/memory.h"
#include "embers/atomic.h"

namespace embers
{

template <typename T, typename LockType>
class LockingQueue1P1C
{
  /* Locking Queue with Single Producer Single Consumer
   *
   * When agents attempt to Enqueue / Dequeue items, they will first attempt to lock-acquire
   * the lock_ using CAS.
   *
   * as CAS is a RMW operation, the cacheline will move between the agents.
   * Thus, if we can have the lock in the same CL as the consumer / producer indexes, that is ideal.
   */

 private:
  size_t num_entries_;
  size_t cons_index_;
  size_t prod_index_;
  LockType lock_;
  unique_ptr<T[]> contents_;

  __device__ __host__ size_t QIDX(size_t index);
  __device__ __host__ size_t QWRP(size_t index);

  __device__ __host__ bool QueueFull(size_t prod, size_t cons);
  __device__ __host__ bool QueueEmpty(size_t prod, size_t cons);
  __device__ __host__ void QueueIncIndex(size_t *const index);
  __device__ __host__ void QueueIncProd();
  __device__ __host__ void QueueIncCons();
  __device__ __host__ bool QueueHasSpace(size_t n);
  __device__ __host__ size_t UnprocessedEntriesCount();

 public:
  class Contents
  {
   private:
    size_t log2_size;
    unique_ptr<T[]> data;
    Contents(size_t log2_size, unique_ptr<T[]> data) : log2_size(log2_size), data(std::move(data))
    {
    }
    friend LockingQueue1P1C;
  };
  __host__ static Contents MakeQueueContents(int hip_dev, unsigned int queue_flags,
                                             size_t log2_size);
  __host__ static Contents MakeQueueContentsHost(unsigned int queue_flags, size_t log2_size);

  __host__ LockingQueue1P1C() = default;
  __host__ ~LockingQueue1P1C() = default;
  __host__ LockingQueue1P1C(const LockingQueue1P1C &) = delete;
  __host__ LockingQueue1P1C &operator=(const LockingQueue1P1C &) = delete;
  __host__ LockingQueue1P1C(LockingQueue1P1C &&) = default;
  __host__ LockingQueue1P1C(Contents contents);

  __host__ __device__ void Enqueue(T item);
  __host__ __device__ T Dequeue();
  __host__ __device__ void EnqueueMultiple(T *item, size_t n);
  __host__ __device__ void DequeueMultiple(T *item, size_t n);
  __host__ __device__ size_t EnqueueUpTo(T *item, size_t max);
  __host__ __device__ size_t DequeueUpTo(T *item, size_t max);
};
}  // namespace embers

#include "locking_queue_impl.h"
#endif  // _EMBERS_LOCKING_QUEUE_H_