Tervel  1.0.0
A collection of wait-free containers and algorithms.
ring_buffer.h
Go to the documentation of this file.
1 /*
2 The MIT License (MIT)
3 
4 Copyright (c) 2015 University of Central Florida's Computer Software Engineering
5 Scalable & Secure Systems (CSE - S3) Lab
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24 */
25 
26 
35 #ifndef TERVEL_CONTAINERS_WF_RINGBUFFER_RINGBUFFER_H_
36 #define TERVEL_CONTAINERS_WF_RINGBUFFER_RINGBUFFER_H_
37 
38 #include <atomic>
39 #include <assert.h>
40 #include <cstddef>
41 #include <memory>
42 #include <thread>
43 #include <string>
44 
45 #include <tervel/util/info.h>
46 #include <tervel/util/util.h>
49 
50 namespace tervel {
51 namespace containers {
52 namespace wf {
53 
72 template<typename T>
73 class RingBuffer {
74  static const uintptr_t num_lsb = 3;
75  static const uintptr_t delayMark_lsb = 0x1;
76  static const uintptr_t emptytype_lsb = 0x2;
77  static const uintptr_t oprec_lsb = 0x4;
78  static const uintptr_t clear_lsb = 7;
79 
80  static_assert(sizeof(T) == sizeof(uintptr_t) &&
81  sizeof(uintptr_t) == sizeof(uint64_t), " Pointers muse be 64 bits");
82 
83  public:
92  class Value {
93  public:
98  Value() {};
99  friend RingBuffer;
100  private:
106  int64_t func_seqid() {
107  return seqid_;
108  }
109 
115  void func_seqid(int64_t s) {
116  seqid_ = s;
117  }
118 
127  void atomic_change_seqid(int64_t e, int64_t n) {
128  std::atomic<int64_t> *a;
129  a = reinterpret_cast<std::atomic<int64_t> *>(&seqid_);
130  bool res = a->compare_exchange_strong(e, n);
131  assert( (res || e ==n) && " Seqid changed to an unexpected value in the"
132  " progress assurance scheme");
133  }
134  int64_t seqid_{-1};
135  };
136 
143  RingBuffer(size_t capacity);
144 
150  bool isFull();
151 
161  bool isFull(int64_t tail, int64_t head);
162 
163 
169  bool isEmpty();
170 
179  bool isEmpty(int64_t tail, int64_t head);
180 
190  bool enqueue(T value);
191 
200  bool dequeue(T &value);
201 
208  std::string debug_string();
209 
210  private:
211 
226  bool readValue(int64_t pos, uintptr_t &val);
227 
236  static inline uintptr_t EmptyType(int64_t seqid);
237 
247  static inline int64_t getEmptyTypeSeqId(uintptr_t val);
248 
259  static inline uintptr_t ValueType(T value, int64_t seqid);
260 
268  static inline T getValueType(uintptr_t val);
269 
279  static inline int64_t getValueTypeSeqId(uintptr_t val);
280 
288  static inline uintptr_t DelayMarkValue(uintptr_t val);
289 
301  void getInfo(uintptr_t val, int64_t &val_seqid,
302  bool &val_isValueType, bool &val_isMarked);
303 
312  static inline bool isEmptyType(uintptr_t p);
313 
322  static inline bool isValueType(uintptr_t p);
323 
332  static inline bool isDelayedMarked(uintptr_t p);
333 
339  int64_t nextHead();
340 
346  int64_t getHead();
347 
348  int64_t casHead(int64_t &expected, int64_t new_val);
349 
355  int64_t nextTail();
356 
362  int64_t getTail();
363 
364  int64_t casTail(int64_t &expected, int64_t new_val);
365 
375  static inline int64_t counterAction(std::atomic<int64_t> &counter, int64_t val);
376 
384  int64_t nextSeqId(int64_t seqid);
385 
394  int64_t getPos(int64_t seqid);
395 
411  bool backoff(int64_t pos, uintptr_t val);
412 
421  void atomic_delay_mark(int64_t pos);
422 
430  std::string debug_string(uintptr_t val);
431 
432 
433  class BufferOp;
434  class EnqueueOp;
435  class DequeueOp;
436  class Helper;
437 
438  const int64_t capacity_;
439  std::atomic<int64_t> head_ {0};
440  std::atomic<int64_t> tail_ {0};
441  std::unique_ptr<std::atomic<uintptr_t>[]> array_;
442 
443 }; // class RingBuffer<Value>
444 
445 
446 
447 } // namespace wf
448 } // namespace containers
449 } // namespace tervel
450 
455 
459 
461 
462 
463 #endif // TERVEL_CONTAINERS_WF_RINGBUFFER_RINGBUFFER_H_
static bool isValueType(uintptr_t p)
returns whether or not p represents an ValueType
Definition: ring_buffer_imp.h:397
RingBuffer(size_t capacity)
Ring Buffer constructor.
Definition: ring_buffer_imp.h:34
Value()
Empty constructor.
Definition: ring_buffer.h:98
int64_t nextTail()
performs a fetch-and-add on the tail counter
Definition: ring_buffer_imp.h:350
bool readValue(int64_t pos, uintptr_t &val)
This function attempts to load a value from the buffer.
Definition: ring_buffer_imp.h:77
static uintptr_t EmptyType(int64_t seqid)
Creates a uintptr_t that represents an EmptyType.
Definition: ring_buffer_imp.h:358
void atomic_delay_mark(int64_t pos)
This function places a bitmark on the value held at address.
Definition: ring_buffer_imp.h:71
bool backoff(int64_t pos, uintptr_t val)
A backoff routine in the event of thread delay.
Definition: ring_buffer_imp.h:420
std::unique_ptr< std::atomic< uintptr_t >[]> array_
Definition: ring_buffer.h:441
TODO(steven):
Definition: mcas.h:36
int64_t getPos(int64_t seqid)
Returns the position a seqid belongs at.
Definition: ring_buffer_imp.h:412
static int64_t getEmptyTypeSeqId(uintptr_t val)
Returns the seqid encoded in the passed value.
Definition: ring_buffer_imp.h:380
int64_t func_seqid()
Returns the items seqid.
Definition: ring_buffer.h:106
int64_t getHead()
performs an atomic load on the head counter
Definition: ring_buffer_imp.h:324
bool dequeue(T &value)
Dequeues a value from the buffer.
Definition: ring_buffer_imp.h:117
static uintptr_t DelayMarkValue(uintptr_t val)
Takes a uintptr_t and places a bitmark on the delayMark_lsb.
Definition: ring_buffer_imp.h:374
static const uintptr_t num_lsb
Definition: ring_buffer.h:74
std::atomic< int64_t > tail_
Definition: ring_buffer.h:440
int64_t seqid_
Definition: ring_buffer.h:134
bool isFull()
Returns whether or not the ring buffer is full.
Definition: ring_buffer_imp.h:44
const int64_t capacity_
Definition: ring_buffer.h:436
void func_seqid(int64_t s)
Sets the items seqid.
Definition: ring_buffer.h:115
This is a non-blocking FIFO ring buffer design that was made wait-free by applying a progress assuran...
Definition: ring_buffer.h:73
void atomic_change_seqid(int64_t e, int64_t n)
Conditionally updates the seqid.
Definition: ring_buffer.h:127
static const uintptr_t clear_lsb
Definition: ring_buffer.h:78
static T getValueType(uintptr_t val)
Returns the value type from a uintptr.
Definition: ring_buffer_imp.h:109
static int64_t getValueTypeSeqId(uintptr_t val)
Returns the seqid of the passed value.
Definition: ring_buffer_imp.h:385
RingBuffer value class, values stored in the class must extend it.
Definition: ring_buffer.h:92
static bool isDelayedMarked(uintptr_t p)
returns whether or not p has a delay mark
Definition: ring_buffer_imp.h:402
friend RingBuffer
Definition: ring_buffer.h:98
int64_t nextHead()
performs a fetch-and-add on the head counter
Definition: ring_buffer_imp.h:334
static uintptr_t ValueType(T value, int64_t seqid)
Creates a uintptr_t that represents an ValueType.
Definition: ring_buffer_imp.h:366
int64_t getTail()
performs an atomic load on the tail counter
Definition: ring_buffer_imp.h:340
std::string debug_string()
This function returns a string debugging information.
Definition: ring_buffer_imp.h:460
static int64_t counterAction(std::atomic< int64_t > &counter, int64_t val)
utility function for incrementing counter
Definition: ring_buffer_imp.h:313
int64_t nextSeqId(int64_t seqid)
Returns the next seqid.
Definition: ring_buffer_imp.h:407
bool isEmpty()
Returns whether or not the ring buffer is empty.
Definition: ring_buffer_imp.h:58
static bool isEmptyType(uintptr_t p)
returns whether or not p represents an EmptyType
Definition: ring_buffer_imp.h:392
static const uintptr_t delayMark_lsb
Definition: ring_buffer.h:75
std::atomic< int64_t > head_
Definition: ring_buffer.h:439
void getInfo(uintptr_t val, int64_t &val_seqid, bool &val_isValueType, bool &val_isMarked)
This function is used to get information from a value read from the ring buffer.
Definition: ring_buffer_imp.h:96
static const uintptr_t oprec_lsb
Definition: ring_buffer.h:77
int64_t casHead(int64_t &expected, int64_t new_val)
Definition: ring_buffer_imp.h:329
int64_t casTail(int64_t &expected, int64_t new_val)
Definition: ring_buffer_imp.h:345
bool enqueue(T value)
Enqueues the passed value into the buffer.
Definition: ring_buffer_imp.h:223
static const uintptr_t emptytype_lsb
Definition: ring_buffer.h:76