SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SingleProducerConsumer.h
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
19
20
21
22 #ifndef __SINGLE_PRODUCER_CONSUMER_H
23 #define __SINGLE_PRODUCER_CONSUMER_H
24
25 #include "assert.h"
26
27 static const int MINIMUM_LIST_SIZE=8;
28
29 #include "memoryoverride.h"
30 #include "Export.h"
31
34 namespace DataStructures
35 {
37 template <class SingleProducerConsumerType>
38 class RAK_DLL_EXPORT SingleProducerConsumer
39 {
40 public:
41 // Constructor
42 SingleProducerConsumer();
43
44 // Destructor
45 ~SingleProducerConsumer();
46
49 SingleProducerConsumerType* WriteLock(void);
50
54 void CancelWriteLock(SingleProducerConsumerType* cancelToLocation);
55
57 void WriteUnlock(void);
58
62 SingleProducerConsumerType* ReadLock(void);
63
64 // Cancelling locks cancels all locks back up to the data passed. So if you lock twice and cancel using the first lock, the second lock is ignored
66 void CancelReadLock(SingleProducerConsumerType* cancelToLocation);
67
70 void ReadUnlock(void);
71
73 void Clear(void);
74
77 int Size(void) const;
78
81 bool CheckReadUnlockOrder(const SingleProducerConsumerType* data) const;
82
85 bool ReadIsLocked(void) const;
86
87 private:
88 struct DataPlusPtr
89 {
90 DataPlusPtr () {readyToRead=false;}
91 SingleProducerConsumerType object;
92
93 // Ready to read is so we can use an equality boolean comparison, in case the writePointer var is trashed while context switching.
94 volatile bool readyToRead;
95 volatile DataPlusPtr *next;
96 };
97 volatile DataPlusPtr *readAheadPointer;
98 volatile DataPlusPtr *writeAheadPointer;
99 volatile DataPlusPtr *readPointer;
100 volatile DataPlusPtr *writePointer;
101 unsigned readCount, writeCount;
102 };
103
104 template <class SingleProducerConsumerType>
105 SingleProducerConsumer<SingleProducerConsumerType>::SingleProducerConsumer()
106 {
107 // Preallocate
108 readPointer = SLNet::OP_NEW<DataPlusPtr>( _FILE_AND_LINE_ );
109 writePointer=readPointer;
110 readPointer->next = SLNet::OP_NEW<DataPlusPtr>( _FILE_AND_LINE_ );
111 int listSize;
112 #ifdef _DEBUG
113 RakAssert(MINIMUM_LIST_SIZE>=3);
114 #endif
115 for (listSize=2; listSize < MINIMUM_LIST_SIZE; listSize++)
116 {
117 readPointer=readPointer->next;
118 readPointer->next = SLNet::OP_NEW<DataPlusPtr>( _FILE_AND_LINE_ );
119 }
120 readPointer->next->next=writePointer; // last to next = start
121 readPointer=writePointer;
122 readAheadPointer=readPointer;
123 writeAheadPointer=writePointer;
124 readCount=writeCount=0;
125 }
126
127 template <class SingleProducerConsumerType>
128 SingleProducerConsumer<SingleProducerConsumerType>::~SingleProducerConsumer()
129 {
130 volatile DataPlusPtr *next;
131 readPointer=writeAheadPointer->next;
132 while (readPointer!=writeAheadPointer)
133 {
134 next=readPointer->next;
135 SLNet::OP_DELETE((char*) readPointer, _FILE_AND_LINE_);
136 readPointer=next;
137 }
138 SLNet::OP_DELETE((char*) readPointer, _FILE_AND_LINE_);
139 }
140
141 template <class SingleProducerConsumerType>
142 SingleProducerConsumerType* SingleProducerConsumer<SingleProducerConsumerType>::WriteLock( void )
143 {
144 if (writeAheadPointer->next==readPointer ||
145 writeAheadPointer->next->readyToRead==true)
146 {
147 volatile DataPlusPtr *originalNext=writeAheadPointer->next;
148 writeAheadPointer->next= SLNet::OP_NEW<DataPlusPtr>(_FILE_AND_LINE_);
149 RakAssert(writeAheadPointer->next);
150 writeAheadPointer->next->next=originalNext;
151 }
152
153 volatile DataPlusPtr *last;
154 last=writeAheadPointer;
155 writeAheadPointer=writeAheadPointer->next;
156
157 return (SingleProducerConsumerType*) last;
158 }
159
160 template <class SingleProducerConsumerType>
161 void SingleProducerConsumer<SingleProducerConsumerType>::CancelWriteLock( SingleProducerConsumerType* cancelToLocation )
162 {
163 writeAheadPointer=(DataPlusPtr *)cancelToLocation;
164 }
165
166 template <class SingleProducerConsumerType>
167 void SingleProducerConsumer<SingleProducerConsumerType>::WriteUnlock( void )
168 {
169 // DataPlusPtr *dataContainer = (DataPlusPtr *)structure;
170
171 #ifdef _DEBUG
172 RakAssert(writePointer->next!=readPointer);
173 RakAssert(writePointer!=writeAheadPointer);
174 #endif
175
176 writeCount++;
177 // User is done with the data, allow send by updating the write pointer
178 writePointer->readyToRead=true;
179 writePointer=writePointer->next;
180 }
181
182 template <class SingleProducerConsumerType>
183 SingleProducerConsumerType* SingleProducerConsumer<SingleProducerConsumerType>::ReadLock( void )
184 {
185 if (readAheadPointer==writePointer ||
186 readAheadPointer->readyToRead==false)
187 {
188 return 0;
189 }
190
191 volatile DataPlusPtr *last;
192 last=readAheadPointer;
193 readAheadPointer=readAheadPointer->next;
194 return (SingleProducerConsumerType*)last;
195 }
196
197 template <class SingleProducerConsumerType>
198 void SingleProducerConsumer<SingleProducerConsumerType>::CancelReadLock( SingleProducerConsumerType* cancelToLocation )
199 {
200 #ifdef _DEBUG
201 RakAssert(readPointer!=writePointer);
202 #endif
203 readAheadPointer=(DataPlusPtr *)cancelToLocation;
204 }
205
206 template <class SingleProducerConsumerType>
207 void SingleProducerConsumer<SingleProducerConsumerType>::ReadUnlock( void )
208 {
209 #ifdef _DEBUG
210 RakAssert(readAheadPointer!=readPointer); // If hits, then called ReadUnlock before ReadLock
211 RakAssert(readPointer!=writePointer); // If hits, then called ReadUnlock when Read returns 0
212 #endif
213 readCount++;
214
215 // Allow writes to this memory block
216 readPointer->readyToRead=false;
217 readPointer=readPointer->next;
218 }
219
220 template <class SingleProducerConsumerType>
221 void SingleProducerConsumer<SingleProducerConsumerType>::Clear( void )
222 {
223 // Shrink the list down to MINIMUM_LIST_SIZE elements
224 volatile DataPlusPtr *next;
225 writePointer=readPointer->next;
226
227 int listSize=1;
228 next=readPointer->next;
229 while (next!=readPointer)
230 {
231 listSize++;
232 next=next->next;
233 }
234
235 while (listSize-- > MINIMUM_LIST_SIZE)
236 {
237 next=writePointer->next;
238 #ifdef _DEBUG
239 RakAssert(writePointer!=readPointer);
240 #endif
241 SLNet::OP_DELETE((char*) writePointer, _FILE_AND_LINE_);
242 writePointer=next;
243 }
244
245 readPointer->next=writePointer;
246 writePointer=readPointer;
247 readAheadPointer=readPointer;
248 writeAheadPointer=writePointer;
249 readCount=writeCount=0;
250 }
251
252 template <class SingleProducerConsumerType>
253 int SingleProducerConsumer<SingleProducerConsumerType>::Size( void ) const
254 {
255 return writeCount-readCount;
256 }
257
258 template <class SingleProducerConsumerType>
259 bool SingleProducerConsumer<SingleProducerConsumerType>::CheckReadUnlockOrder(const SingleProducerConsumerType* data) const
260 {
261 return const_cast<const SingleProducerConsumerType *>(&readPointer->object) == data;
262 }
263
264
265 template <class SingleProducerConsumerType>
266 bool SingleProducerConsumer<SingleProducerConsumerType>::ReadIsLocked(void) const
267 {
268 return readAheadPointer!=readPointer;
269 }
270 }
271
272 #endif