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