| rev |
line source |
|
Me@19
|
1 /*
|
|
seanhalle@44
|
2 * Copyright 2009 OpenSourceResearchInstitute.org
|
|
Me@19
|
3 * Licensed under GNU General Public License version 2
|
|
Me@19
|
4 *
|
|
Me@19
|
5 * NOTE: this version of SRSW correct as of April 25, 2010
|
|
Me@19
|
6 *
|
|
Me@19
|
7 * Author: seanhalle@yahoo.com
|
|
Me@19
|
8 */
|
|
Me@19
|
9
|
|
Me@19
|
10
|
|
Me@19
|
11 #include <stdio.h>
|
|
Me@19
|
12 #include <string.h>
|
|
Me@19
|
13 #include <errno.h>
|
|
Me@19
|
14 #include <stdlib.h>
|
|
Me@19
|
15
|
|
Me@19
|
16 #include "PrivateQueue.h"
|
|
seanhalle@49
|
17 #include <PR__include/prqueue.h>
|
|
seanhalle@49
|
18 #include <PR__include/prmalloc.h>
|
|
Me@19
|
19
|
|
Me@19
|
20
|
|
Me@19
|
21
|
|
Me@19
|
22 //===========================================================================
|
|
Me@19
|
23
|
|
Me@19
|
24 /*This kind of queue is private to a single core at a time -- has no
|
|
Me@19
|
25 * synchronizations
|
|
Me@19
|
26 */
|
|
Me@19
|
27
|
|
Me@19
|
28 PrivQueueStruc* makePrivQ()
|
|
Me@19
|
29 {
|
|
Me@19
|
30 PrivQueueStruc* retQ;
|
|
seanhalle@32
|
31 //This malloc is not safe to use in wrapper lib nor app code!
|
|
seanhalle@48
|
32 retQ = (PrivQueueStruc *) PR__malloc( sizeof( PrivQueueStruc ) );
|
|
Me@19
|
33
|
|
seanhalle@32
|
34 //This malloc is not safe to use in wrapper lib nor app code!
|
|
seanhalle@48
|
35 retQ->startOfData = PR__malloc( 1024 * sizeof(void *) );
|
|
Me@19
|
36 memset( retQ->startOfData, 0, 1024 * sizeof(void *) );
|
|
Me@19
|
37 retQ->extractPos = &(retQ->startOfData[0]); //side by side == empty
|
|
Me@19
|
38 retQ->insertPos = &(retQ->startOfData[1]); // so start pos's have to be
|
|
Me@19
|
39 retQ->endOfData = &(retQ->startOfData[1023]);
|
|
Me@19
|
40
|
|
Me@19
|
41 return retQ;
|
|
Me@19
|
42 }
|
|
Me@19
|
43
|
|
Me@19
|
44
|
|
seanhalle@44
|
45 /*A bit tricky, 'cause have to copy in two halves, and be careful about case
|
|
seanhalle@44
|
46 * when insert is at top and extract at bottom..
|
|
seanhalle@44
|
47 */
|
|
Me@19
|
48 void
|
|
Me@19
|
49 enlargePrivQ( PrivQueueStruc *Q )
|
|
seanhalle@35
|
50 { int32 oldSize, newSize, topPartSize, bottPartSize;
|
|
seanhalle@32
|
51 int8 *insertPos, *extractPos;
|
|
seanhalle@32
|
52 int8 *oldStartOfData, *oldEndOfData, *newStartOfData, *newEndOfData;
|
|
seanhalle@35
|
53 int32 insertOffsetBytes, extractOffsetBytes;
|
|
seanhalle@35
|
54 int8 *copyStartAddr;
|
|
Me@19
|
55
|
|
seanhalle@32
|
56 oldStartOfData = (int8 *)Q->startOfData;
|
|
seanhalle@32
|
57 oldEndOfData = (int8 *)Q->endOfData;
|
|
seanhalle@32
|
58 insertPos = (int8 *)Q->insertPos;
|
|
seanhalle@32
|
59 extractPos = (int8 *)Q->extractPos;
|
|
Me@19
|
60
|
|
seanhalle@32
|
61 //TODO: verify these get number of bytes correct
|
|
seanhalle@35
|
62 insertOffsetBytes = (int32)(insertPos - oldStartOfData);
|
|
seanhalle@35
|
63 extractOffsetBytes = (int32)(extractPos - oldStartOfData);
|
|
seanhalle@32
|
64
|
|
seanhalle@35
|
65 oldSize = oldEndOfData - oldStartOfData + 1; //in bytes
|
|
seanhalle@32
|
66 newSize = 2 * oldSize;
|
|
seanhalle@32
|
67
|
|
seanhalle@32
|
68 //This malloc is not safe to use in wrapper lib nor app code!
|
|
seanhalle@48
|
69 Q->startOfData = (void **)PR__malloc( newSize );
|
|
seanhalle@32
|
70 newStartOfData = (int8 *)Q->startOfData;
|
|
seanhalle@32
|
71 newEndOfData = newStartOfData + newSize; //all calcs in Bytes
|
|
seanhalle@32
|
72 Q->endOfData = (void **)newEndOfData;
|
|
seanhalle@32
|
73
|
|
seanhalle@32
|
74 //TODO: test all of this, for both cases
|
|
seanhalle@32
|
75
|
|
seanhalle@32
|
76 //Moving the data and pointers to the new array is
|
|
seanhalle@32
|
77 //a little trickier than at first it seems.. the top part
|
|
seanhalle@32
|
78 // of old queue must be moved to the top part of new queue, while
|
|
seanhalle@32
|
79 // bottom part of old to bottom part of new, then the new insert
|
|
seanhalle@32
|
80 // and extract positions calculated by offset from top and bottom
|
|
seanhalle@32
|
81 //UNLESS the one case where old extract was at bottom and insert
|
|
seanhalle@32
|
82 // was at top.
|
|
seanhalle@32
|
83 //TODO: check that this is correct!
|
|
seanhalle@35
|
84 if( extractPos == oldStartOfData && insertPos == oldEndOfData )
|
|
seanhalle@32
|
85 {
|
|
seanhalle@32
|
86 memcpy( newStartOfData, oldStartOfData, oldSize ); //oldSize is bytes
|
|
seanhalle@32
|
87 Q->extractPos = Q->startOfData; //start of valid data
|
|
seanhalle@32
|
88 Q->insertPos = Q->startOfData + oldSize - 1; //end of valid data
|
|
seanhalle@32
|
89 }
|
|
seanhalle@32
|
90 else //have to copy two parts separately, then calc positions
|
|
seanhalle@32
|
91 { //TODO: check end-addr, sizes, and new positions carefully
|
|
seanhalle@35
|
92
|
|
seanhalle@32
|
93 //copy top part, starting at extract up until end of data,
|
|
seanhalle@35
|
94 // into top of new array
|
|
seanhalle@32
|
95 topPartSize = oldEndOfData - extractPos + 1; //+1 includes extractPos
|
|
seanhalle@35
|
96 copyStartAddr = newEndOfData - topPartSize + 1;//+1 cancels other
|
|
seanhalle@32
|
97 memcpy( copyStartAddr, Q->extractPos, topPartSize );
|
|
seanhalle@35
|
98 Q->extractPos = (void **)copyStartAddr; //extract just-copied data
|
|
seanhalle@35
|
99
|
|
seanhalle@32
|
100 //copy bottom part, from old start up to old insert,
|
|
seanhalle@35
|
101 // into bottom of new array
|
|
seanhalle@32
|
102 bottPartSize = oldSize - topPartSize - 1; //-1 for empty insertPos
|
|
seanhalle@32
|
103 memcpy( newStartOfData, oldStartOfData, bottPartSize );
|
|
seanhalle@32
|
104 Q->insertPos = (void **)(newStartOfData + bottPartSize);
|
|
seanhalle@32
|
105 }
|
|
seanhalle@32
|
106 //This free is not safe to use in wrapper lib nor app code!
|
|
seanhalle@48
|
107 PR__free(oldStartOfData);
|
|
Me@19
|
108 }
|
|
Me@19
|
109
|
|
Me@19
|
110
|
|
seanhalle@37
|
111 /*Returns TRUE when queue is empty
|
|
seanhalle@37
|
112 */
|
|
seanhalle@37
|
113 bool32 isEmptyPrivQ( PrivQueueStruc* Q )
|
|
seanhalle@37
|
114 { void *out = 0;
|
|
seanhalle@37
|
115 void **startOfData = Q->startOfData;
|
|
seanhalle@37
|
116 void **endOfData = Q->endOfData;
|
|
seanhalle@37
|
117
|
|
seanhalle@37
|
118 void **insertPos = Q->insertPos;
|
|
seanhalle@37
|
119 void **extractPos = Q->extractPos;
|
|
seanhalle@37
|
120
|
|
seanhalle@37
|
121 //if not empty -- (extract is just below insert when empty)
|
|
seanhalle@37
|
122 if( insertPos - extractPos != 1 &&
|
|
seanhalle@37
|
123 !(extractPos == endOfData && insertPos == startOfData))
|
|
seanhalle@37
|
124 {
|
|
seanhalle@37
|
125 return FALSE;
|
|
seanhalle@37
|
126 }
|
|
seanhalle@37
|
127 //Q is empty
|
|
seanhalle@37
|
128 return TRUE;
|
|
seanhalle@37
|
129 }
|
|
seanhalle@37
|
130
|
|
seanhalle@37
|
131 /*Returns NULL when queue is empty
|
|
seanhalle@37
|
132 */
|
|
seanhalle@37
|
133 void* peekPrivQ( PrivQueueStruc* Q )
|
|
seanhalle@37
|
134 { void *out = 0;
|
|
seanhalle@37
|
135 void **startOfData = Q->startOfData;
|
|
seanhalle@37
|
136 void **endOfData = Q->endOfData;
|
|
seanhalle@37
|
137
|
|
seanhalle@37
|
138 void **insertPos = Q->insertPos;
|
|
seanhalle@37
|
139 void **extractPos = Q->extractPos;
|
|
seanhalle@37
|
140
|
|
seanhalle@37
|
141 //if not empty -- (extract is just below insert when empty)
|
|
seanhalle@37
|
142 if( insertPos - extractPos != 1 &&
|
|
seanhalle@37
|
143 !(extractPos == endOfData && insertPos == startOfData))
|
|
seanhalle@37
|
144 {
|
|
seanhalle@37
|
145 out = *(Q->extractPos);
|
|
seanhalle@37
|
146 return out;
|
|
seanhalle@37
|
147 }
|
|
seanhalle@37
|
148 //Q is empty
|
|
seanhalle@37
|
149 return NULL;
|
|
seanhalle@37
|
150 }
|
|
seanhalle@37
|
151
|
|
seanhalle@37
|
152
|
|
Me@19
|
153 /*Returns NULL when queue is empty
|
|
Me@19
|
154 */
|
|
Me@19
|
155 void* readPrivQ( PrivQueueStruc* Q )
|
|
Me@19
|
156 { void *out = 0;
|
|
Me@19
|
157 void **startOfData = Q->startOfData;
|
|
Me@19
|
158 void **endOfData = Q->endOfData;
|
|
Me@19
|
159
|
|
Me@19
|
160 void **insertPos = Q->insertPos;
|
|
Me@19
|
161 void **extractPos = Q->extractPos;
|
|
Me@19
|
162
|
|
Me@19
|
163 //if not empty -- (extract is just below insert when empty)
|
|
Me@19
|
164 if( insertPos - extractPos != 1 &&
|
|
Me@19
|
165 !(extractPos == endOfData && insertPos == startOfData))
|
|
Me@19
|
166 { //move before read
|
|
Me@19
|
167 if( extractPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
168 { Q->extractPos = startOfData; //can't overrun then fix it 'cause
|
|
Me@19
|
169 } // other thread might read bad pos
|
|
Me@19
|
170 else
|
|
Me@19
|
171 { Q->extractPos++;
|
|
Me@19
|
172 }
|
|
Me@19
|
173 out = *(Q->extractPos);
|
|
Me@19
|
174 return out;
|
|
Me@19
|
175 }
|
|
Me@19
|
176 //Q is empty
|
|
Me@19
|
177 return NULL;
|
|
Me@19
|
178 }
|
|
Me@19
|
179
|
|
Me@19
|
180
|
|
Me@19
|
181 /*Expands the queue size automatically when it's full
|
|
Me@19
|
182 */
|
|
Me@19
|
183 void
|
|
Me@19
|
184 writePrivQ( void * in, PrivQueueStruc* Q )
|
|
Me@19
|
185 {
|
|
Me@19
|
186 void **startOfData = Q->startOfData;
|
|
Me@19
|
187 void **endOfData = Q->endOfData;
|
|
Me@19
|
188
|
|
Me@19
|
189 void **insertPos = Q->insertPos;
|
|
Me@19
|
190 void **extractPos = Q->extractPos;
|
|
Me@19
|
191
|
|
Me@19
|
192 tryAgain:
|
|
Me@19
|
193 //Full? (insert is just below extract when full)
|
|
Me@19
|
194 if( extractPos - insertPos != 1 &&
|
|
Me@19
|
195 !(insertPos == endOfData && extractPos == startOfData))
|
|
Me@19
|
196 { *(Q->insertPos) = in; //insert before move
|
|
Me@19
|
197 if( insertPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
198 { Q->insertPos = startOfData;
|
|
Me@19
|
199 }
|
|
Me@19
|
200 else
|
|
Me@19
|
201 { Q->insertPos++;
|
|
Me@19
|
202 }
|
|
Me@19
|
203 return;
|
|
Me@19
|
204 }
|
|
Me@19
|
205 //Q is full
|
|
Me@19
|
206 enlargePrivQ( Q );
|
|
Me@19
|
207 goto tryAgain;
|
|
Me@19
|
208 }
|
|
Me@19
|
209
|
|
Me@19
|
210
|
|
Me@19
|
211 /*Returns false when the queue was full.
|
|
Me@19
|
212 * have option of calling make_larger_PrivQ to make more room, then try again
|
|
Me@19
|
213 */
|
|
seanhalle@35
|
214 bool32
|
|
seanhalle@35
|
215 writeIfSpacePrivQ( void * in, PrivQueueStruc* Q )
|
|
Me@19
|
216 {
|
|
Me@19
|
217 void **startOfData = Q->startOfData;
|
|
Me@19
|
218 void **endOfData = Q->endOfData;
|
|
Me@19
|
219
|
|
Me@19
|
220 void **insertPos = Q->insertPos;
|
|
Me@19
|
221 void **extractPos = Q->extractPos;
|
|
Me@19
|
222
|
|
Me@19
|
223 if( extractPos - insertPos != 1 &&
|
|
Me@19
|
224 !(insertPos == endOfData && extractPos == startOfData))
|
|
Me@19
|
225 { *(Q->insertPos) = in; //insert before move
|
|
Me@19
|
226 if( insertPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
227 { Q->insertPos = startOfData;
|
|
Me@19
|
228 }
|
|
Me@19
|
229 else
|
|
Me@19
|
230 { Q->insertPos++;
|
|
Me@19
|
231 }
|
|
Me@19
|
232 return TRUE;
|
|
Me@19
|
233 }
|
|
Me@19
|
234 //Q is full
|
|
Me@19
|
235 return FALSE;
|
|
Me@19
|
236 }
|
|
seanhalle@27
|
237
|
|
seanhalle@32
|
238 int32
|
|
seanhalle@32
|
239 numInPrivQ( PrivQueueStruc *Q )
|
|
seanhalle@32
|
240 { int32 size, numIn;
|
|
seanhalle@32
|
241
|
|
seanhalle@32
|
242 if( Q->insertPos < Q->extractPos )
|
|
seanhalle@32
|
243 { //insert has wrapped around so numIn is:
|
|
seanhalle@32
|
244 // insertPos + size - extractPos -- Consider, is empty when
|
|
seanhalle@32
|
245 // extractPos = endOfData and insert = start -- correctly get zero
|
|
seanhalle@33
|
246 size = Q->endOfData - Q->startOfData + 1; //sz of 10 is 0..9
|
|
seanhalle@33
|
247 numIn = Q->insertPos - Q->extractPos + size - 1; //-1 bec insrt empty
|
|
seanhalle@32
|
248 }
|
|
seanhalle@32
|
249 else
|
|
seanhalle@32
|
250 {
|
|
seanhalle@33
|
251 numIn = Q->insertPos - Q->extractPos -1;//-1 bec insertPos empty
|
|
seanhalle@32
|
252 }
|
|
seanhalle@32
|
253 return numIn;
|
|
seanhalle@32
|
254 }
|
|
seanhalle@32
|
255
|
|
seanhalle@32
|
256
|
|
seanhalle@32
|
257 /*Treats queue as a stack -- no matter contents, if read done right after
|
|
seanhalle@32
|
258 * a push, then the pushed item is what comes out.
|
|
seanhalle@32
|
259 * Expands the queue size automatically when it's full.
|
|
seanhalle@32
|
260 */
|
|
seanhalle@32
|
261 void
|
|
seanhalle@32
|
262 pushPrivQ( void * in, PrivQueueStruc* Q )
|
|
seanhalle@32
|
263 {
|
|
seanhalle@32
|
264 while(1){
|
|
seanhalle@32
|
265 void **startOfData = Q->startOfData;
|
|
seanhalle@32
|
266 void **endOfData = Q->endOfData;
|
|
seanhalle@32
|
267
|
|
seanhalle@32
|
268 void **insertPos = Q->insertPos;
|
|
seanhalle@32
|
269 void **extractPos = Q->extractPos;
|
|
seanhalle@32
|
270
|
|
seanhalle@32
|
271 //Full? (insert is just below extract when full)
|
|
seanhalle@32
|
272 if( extractPos - insertPos != 1 &&
|
|
seanhalle@32
|
273 !(insertPos == endOfData && extractPos == startOfData))
|
|
seanhalle@32
|
274 { //insert -- but go backwards, inserting at read position then
|
|
seanhalle@32
|
275 // move read pos backwards
|
|
seanhalle@32
|
276 *(Q->extractPos) = in;
|
|
seanhalle@32
|
277 if( extractPos == startOfData ) //write new pos exactly once, correctly
|
|
seanhalle@32
|
278 { Q->extractPos = endOfData; //can't overrun then fix it 'cause
|
|
seanhalle@32
|
279 } // other thread might read bad pos
|
|
seanhalle@32
|
280 else
|
|
seanhalle@32
|
281 { Q->extractPos--;
|
|
seanhalle@32
|
282 }
|
|
seanhalle@32
|
283 return;
|
|
seanhalle@32
|
284 }
|
|
seanhalle@32
|
285 //Q is full
|
|
seanhalle@32
|
286 enlargePrivQ( Q );
|
|
seanhalle@32
|
287 }
|
|
seanhalle@32
|
288 }
|
|
seanhalle@32
|
289
|
|
seanhalle@32
|
290
|
|
seanhalle@44
|
291 /*NOTE: This free is not safe to use in wrapper lib nor app code
|
|
seanhalle@44
|
292 */
|
|
seanhalle@44
|
293 void
|
|
seanhalle@44
|
294 freePrivQ( PrivQueueStruc *Q )
|
|
seanhalle@44
|
295 {
|
|
seanhalle@44
|
296 //This free is not safe to use in wrapper lib nor app code!
|
|
seanhalle@48
|
297 PR__free( Q->startOfData );
|
|
seanhalle@48
|
298 PR__free( Q );
|
|
seanhalle@44
|
299 }
|