ringbuffer.h revision e7201bd31b4c7beb1a2d0c4659477946e263d5cf
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
32template<typename T>
33class RingBuffer
34{
35public:
36    RingBuffer()
37        : mpRingBuffer(nullptr), mNumEntries(0), mRingHead(0), mRingTail(0)
38    {
39    }
40
41    ~RingBuffer()
42    {
43        Destroy();
44    }
45
46    void Init(uint32_t numEntries)
47    {
48        SWR_ASSERT(numEntries > 0);
49        mNumEntries = numEntries;
50        mpRingBuffer = (T*)_aligned_malloc(sizeof(T)*numEntries, 64);
51        SWR_ASSERT(mpRingBuffer != nullptr);
52        memset(mpRingBuffer, 0, sizeof(T)*numEntries);
53    }
54
55    void Destroy()
56    {
57        _aligned_free(mpRingBuffer);
58        mpRingBuffer = nullptr;
59    }
60
61    T& operator[](const uint32_t index)
62    {
63        SWR_ASSERT(index < mNumEntries);
64        return mpRingBuffer[index];
65    }
66
67    INLINE void Enqueue()
68    {
69        mRingHead++; // There's only one producer.
70    }
71
72    INLINE void Dequeue()
73    {
74        InterlockedIncrement(&mRingTail); // There are multiple consumers.
75    }
76
77    INLINE bool IsEmpty()
78    {
79        return (GetHead() == GetTail());
80    }
81
82    INLINE bool IsFull()
83    {
84        ///@note We don't handle wrap case due to using 64-bit indices.
85        ///      It would take 11 million years to wrap at 50,000 DCs per sec.
86        ///      If we used 32-bit indices then its about 23 hours to wrap.
87        uint64_t numEnqueued = GetHead() - GetTail();
88        SWR_ASSERT(numEnqueued <= mNumEntries);
89
90        return (numEnqueued == mNumEntries);
91    }
92
93    INLINE uint64_t GetTail() volatile { return mRingTail; }
94    INLINE uint64_t GetHead() volatile { return mRingHead; }
95
96protected:
97    T* mpRingBuffer;
98    uint32_t mNumEntries;
99
100    OSALIGNLINE(volatile uint64_t) mRingHead;  // Consumer Counter
101    OSALIGNLINE(volatile uint64_t) mRingTail;  // Producer Counter
102};
103