OSVR-Core
IPCRingBufferSharedObjects.h
Go to the documentation of this file.
1 
12 // Copyright 2015 Sensics, Inc.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 // See the License for the specific language governing permissions and
24 // limitations under the License.
25 
26 #ifndef INCLUDED_IPCRingBufferSharedObjects_h_GUID_890394B4_253B_4BAF_C813_E0E54D159128
27 #define INCLUDED_IPCRingBufferSharedObjects_h_GUID_890394B4_253B_4BAF_C813_E0E54D159128
28 
29 // Internal Includes
31 #include "IPCRingBufferResults.h"
33 #include <osvr/Util/StdInt.h>
34 #include <osvr/Util/Verbosity.h>
35 
36 // Library/third-party includes
37 #include <boost/noncopyable.hpp>
38 
39 // Standard includes
40 #include <utility>
41 
42 namespace osvr {
43 namespace common {
44 
45  namespace detail {
46  namespace bip = boost::interprocess;
47 
48  class ElementData : public ipc::ObjectWithMutex, boost::noncopyable {
49  public:
50  typedef IPCRingBuffer::value_type BufferType;
51 
52  ElementData() : m_buf(nullptr) {}
53 
54  template <typename LockType>
55  BufferType *getBuf(LockType &lock) const {
56  verifyReaderLock(lock);
57  return m_buf.get();
58  }
59 
60  template <typename ManagedMemory>
61  void allocateBuf(ManagedMemory &shm,
63  freeBuf(shm);
64  m_buf = static_cast<BufferType *>(shm.allocate_aligned(
65  opts.getEntrySize(), opts.getAlignment()));
66  }
67 
68  template <typename ManagedMemory> void freeBuf(ManagedMemory &shm) {
69  if (nullptr != m_buf) {
70  shm.deallocate(m_buf.get());
71  }
72  m_buf = nullptr;
73  }
74 
75  private:
76  ipc_offset_ptr<BufferType> m_buf;
77  };
78 
79  class Bookkeeping : public ipc::ObjectWithMutex, boost::noncopyable {
80  public:
81  typedef IPCRingBuffer::sequence_type sequence_type;
82  typedef uint16_t raw_index_type;
83 
84  template <typename ManagedMemory>
85  static Bookkeeping *find(ManagedMemory &shm) {
86  auto self =
87  shm.template find<Bookkeeping>(bip::unique_instance);
88  return self.first;
89  }
90 
91  template <typename ManagedMemory>
92  static Bookkeeping *construct(ManagedMemory &shm,
94  return shm.template construct<Bookkeeping>(
95  bip::unique_instance)(shm, opts);
96  }
97 
98  template <typename ManagedMemory>
99  static void destroy(ManagedMemory &shm) {
100  auto self = find(shm);
101  if (nullptr == self) {
102  return;
103  }
104  self->freeBufs(shm);
105  shm.template destroy<Bookkeeping>(bip::unique_instance);
106  }
107 
108  template <typename ManagedMemory>
109  Bookkeeping(ManagedMemory &shm, IPCRingBuffer::Options const &opts)
110  : m_capacity(opts.getEntries()),
111  elementArray(shm.template construct<ElementData>(
112  bip::unique_instance)[m_capacity]()),
113  m_beginSequenceNumber(0), m_nextSequenceNumber(0), m_begin(0),
114  m_size(0), m_bufLen(opts.getEntrySize()) {
115 
116  auto lock = getExclusiveLock();
117  {
118  for (raw_index_type i = 0; i < m_capacity; ++i) {
119  try {
120  getByRawIndex(i, lock).allocateBuf(shm, opts);
121  } catch (std::bad_alloc &) {
122  OSVR_DEV_VERBOSE("Couldn't allocate buffer #"
123  << i
124  << ", truncating the ring buffer");
125  m_capacity = i;
126  break;
127  }
128  }
129  }
130  }
131 
132  template <typename ManagedMemory>
133  void freeBufs(ManagedMemory &shm) {
134  auto lock = getExclusiveLock();
135  {
136  for (raw_index_type i = 0; i < m_capacity; ++i) {
137  getByRawIndex(i, lock).freeBuf(shm);
138  }
139  shm.template destroy<ElementData>(bip::unique_instance);
140  }
141  }
142 
144  raw_index_type getCapacity() const { return m_capacity; }
145 
147  uint32_t getBufferLength() const { return m_bufLen; }
148 
149  template <typename LockType>
150  ElementData &getByRawIndex(raw_index_type index, LockType &lock) {
151  verifyReaderLock(lock);
152  return *(elementArray + (index % m_capacity));
153  }
154  template <typename LockType>
155  ElementData *getBySequenceNumber(sequence_type num,
156  LockType &lock) {
157  verifyReaderLock(lock);
158  auto sequenceRelativeToBegin = num - m_beginSequenceNumber;
159  if (sequenceRelativeToBegin < m_size) {
160  raw_index_type idx((m_begin + sequenceRelativeToBegin) %
161  m_capacity);
162  return &getByRawIndex(idx, lock);
163  }
164  return nullptr; // out of bounds request -> nullptr return.
165  }
166 
167  template <typename LockType> bool empty(LockType &lock) const {
168  verifyReaderLock(lock);
169  return m_size == 0;
170  }
171  template <typename LockType>
172  sequence_type backSequenceNumber(LockType &lock) {
173  verifyReaderLock(lock);
174  return m_nextSequenceNumber - 1;
175  }
176 
177  template <typename LockType> ElementData *back(LockType &lock) {
178  verifyReaderLock(lock);
179  if (empty(lock)) {
180  return nullptr;
181  }
182  return &getByRawIndex(m_begin + m_size - 1, lock);
183  }
184 
185  IPCPutResultPtr produceElement() {
186  auto lock = getExclusiveLock();
187  auto sequenceNumber = m_nextSequenceNumber;
188  m_nextSequenceNumber++;
189  if (m_size == m_capacity) {
190  m_begin++;
191  m_beginSequenceNumber++;
192  } else {
193  m_size++;
194  }
195 #ifdef OSVR_SHM_LOCK_DEBUGGING
196  OSVR_DEV_VERBOSE(
197  "Attempting to get an exclusive lock on sequence "
198  << sequenceNumber << " aka index " << back(lock));
199 #endif
200  auto elementLock = back(lock)->getExclusiveLock();
202  IPCPutResultPtr ret(new IPCPutResult{
203  back(lock)->getBuf(elementLock), sequenceNumber,
204  std::move(elementLock), std::move(lock), nullptr});
205  return ret;
206  }
207 
208  private:
209  raw_index_type m_capacity;
210  ipc_offset_ptr<ElementData> elementArray;
211  IPCRingBuffer::sequence_type m_beginSequenceNumber;
212  IPCRingBuffer::sequence_type m_nextSequenceNumber;
213  raw_index_type m_begin;
214  raw_index_type m_size;
215  uint32_t m_bufLen;
216  };
217  } // namespace detail
218 
219 } // namespace common
220 } // namespace osvr
221 #endif // INCLUDED_IPCRingBufferSharedObjects_h_GUID_890394B4_253B_4BAF_C813_E0E54D159128
Definition: IPCRingBufferSharedObjects.h:48
Handles spatial transformations.
Definition: SerializationTraitExample_Complicated.h:40
uint32_t getBufferLength() const
Get capacity of elements.
Definition: IPCRingBufferSharedObjects.h:147
Header wrapping the C99 standard stdint header.
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
void verifyReaderLock(LockType &lock) const
Checks to make sure we at least have a reader (sharable) lock.
Definition: SharedMemoryObjectWithMutex.h:72
Definition: IPCRingBuffer.h:72
Definition: IPCRingBufferResults.h:43
uint32_t sequence_type
The sequence number is automatically incremented with each "put" into the buffer. ...
Definition: IPCRingBuffer.h:149
Definition: newuoa.h:1888
Definition: IPCRingBufferSharedObjects.h:79
raw_index_type getCapacity() const
Get number of elements.
Definition: IPCRingBufferSharedObjects.h:144
Definition: SharedMemoryObjectWithMutex.h:51
Definition: ProjectionMatrix.h:77
IPCPutResultPtr produceElement()
Definition: IPCRingBufferSharedObjects.h:185