1 /****************************************************************************
2  * Copyright (C) 2016 Intel Corporation.   All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * @file arena.h
24  *
25  * @brief RingBuffer
26  *        The RingBuffer class manages all aspects of the ring buffer including
27  *        the head/tail indices, etc.
28  *
29  ******************************************************************************/
30 #pragma once
31 
32 template <typename T>
33 class RingBuffer
34 {
35 public:
RingBuffer()36     RingBuffer() : mpRingBuffer(nullptr), mNumEntries(0), mRingHead(0), mRingTail(0) {}
37 
~RingBuffer()38     ~RingBuffer() { Destroy(); }
39 
Init(uint32_t numEntries)40     void Init(uint32_t numEntries)
41     {
42         SWR_ASSERT(numEntries > 0);
43         SWR_ASSERT(((1ULL << 32) % numEntries) == 0,
44                    "%d is not evenly divisible into 2 ^ 32.  Wrap errors will occur!",
45                    numEntries);
46         mNumEntries  = numEntries;
47         mpRingBuffer = (T*)AlignedMalloc(sizeof(T) * numEntries, 64);
48         SWR_ASSERT(mpRingBuffer != nullptr);
49         memset((void*)mpRingBuffer, 0, sizeof(T) * numEntries);
50     }
51 
Destroy()52     void Destroy()
53     {
54         AlignedFree(mpRingBuffer);
55         mpRingBuffer = nullptr;
56     }
57 
58     T& operator[](const uint32_t index)
59     {
60         SWR_ASSERT(index < mNumEntries);
61         return mpRingBuffer[index];
62     }
63 
Enqueue()64     INLINE void Enqueue()
65     {
66         mRingHead++; // There's only one producer.
67         // Assert to find wrap-around cases, NEVER ENABLE DURING CHECKIN!!
68         // SWR_REL_ASSERT(mRingHead);
69     }
70 
Dequeue()71     INLINE void Dequeue()
72     {
73         InterlockedIncrement(&mRingTail); // There are multiple consumers.
74     }
75 
IsEmpty()76     INLINE bool IsEmpty() { return (GetHead() == GetTail()); }
77 
IsFull()78     INLINE bool IsFull()
79     {
80         uint32_t numEnqueued = GetHead() - GetTail();
81         SWR_ASSERT(numEnqueued <= mNumEntries);
82 
83         return (numEnqueued == mNumEntries);
84     }
85 
GetTail()86     INLINE uint32_t GetTail() volatile { return mRingTail; }
GetHead()87     INLINE uint32_t GetHead() volatile { return mRingHead; }
88 
89 protected:
90     T*       mpRingBuffer;
91     uint32_t mNumEntries;
92 
93     OSALIGNLINE(volatile uint32_t) mRingHead; // Consumer Counter
94     OSALIGNLINE(volatile uint32_t) mRingTail; // Producer Counter
95 };
96