| 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
|
|
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"
|
|
Me@19
|
17
|
|
Me@19
|
18
|
|
Me@19
|
19
|
|
Me@19
|
20 //===========================================================================
|
|
Me@19
|
21
|
|
Me@19
|
22 /*This kind of queue is private to a single core at a time -- has no
|
|
Me@19
|
23 * synchronizations
|
|
Me@19
|
24 */
|
|
Me@19
|
25
|
|
Me@19
|
26 PrivQueueStruc* makePrivQ()
|
|
Me@19
|
27 {
|
|
Me@19
|
28 PrivQueueStruc* retQ;
|
|
seanhalle@34
|
29 //This malloc is not safe to use inside VMS-language!
|
|
Me@19
|
30 retQ = (PrivQueueStruc *) malloc( sizeof( PrivQueueStruc ) );
|
|
Me@19
|
31
|
|
seanhalle@34
|
32 //This malloc is not safe to use inside VMS-language!
|
|
Me@19
|
33 retQ->startOfData = malloc( 1024 * sizeof(void *) );
|
|
Me@19
|
34 memset( retQ->startOfData, 0, 1024 * sizeof(void *) );
|
|
Me@19
|
35 retQ->extractPos = &(retQ->startOfData[0]); //side by side == empty
|
|
Me@19
|
36 retQ->insertPos = &(retQ->startOfData[1]); // so start pos's have to be
|
|
Me@19
|
37 retQ->endOfData = &(retQ->startOfData[1023]);
|
|
Me@19
|
38
|
|
Me@19
|
39 return retQ;
|
|
Me@19
|
40 }
|
|
Me@19
|
41
|
|
Me@19
|
42
|
|
Me@19
|
43 void
|
|
Me@19
|
44 enlargePrivQ( PrivQueueStruc *Q )
|
|
seanhalle@34
|
45 { int32 oldSize, newSize;
|
|
seanhalle@34
|
46 int8 *insertPos, *extractPos;
|
|
seanhalle@34
|
47 int8 *oldStartOfData, *oldEndOfData, *newStartOfData, *newEndOfData;
|
|
seanhalle@34
|
48 int8 *insertOffsetBytes, *extractOffsetBytes;
|
|
Me@19
|
49
|
|
seanhalle@34
|
50 oldStartOfData = (int8 *)Q->startOfData;
|
|
seanhalle@34
|
51 oldEndOfData = (int8 *)Q->endOfData;
|
|
seanhalle@34
|
52 insertPos = (int8 *)Q->insertPos;
|
|
seanhalle@34
|
53 extractPos = (int8 *)Q->extractPos;
|
|
Me@19
|
54
|
|
seanhalle@34
|
55 //TODO: verify these get number of bytes correct
|
|
seanhalle@34
|
56 insertOffsetBytes = insertPos - oldStartOfData;
|
|
seanhalle@34
|
57 extractOffsetBytes = extractPos - oldStartOfData);
|
|
seanhalle@34
|
58
|
|
seanhalle@34
|
59 oldSize = endOfData - startOfData + 1; //in bytes
|
|
seanhalle@34
|
60 newSize = 2 * oldSize;
|
|
seanhalle@34
|
61
|
|
seanhalle@34
|
62 //This malloc is not safe to use inside VMS-language!
|
|
seanhalle@34
|
63 Q->startOfData = (void **)malloc( newSize );
|
|
seanhalle@34
|
64 newStartOfData = (int8 *)Q->startOfData;
|
|
seanhalle@34
|
65 newEndOfData = newStartOfData + newSize; //all calcs in Bytes
|
|
seanhalle@34
|
66 Q->endOfData = (void **)newEndOfData;
|
|
seanhalle@34
|
67
|
|
seanhalle@34
|
68 //TODO: test all of this, for both cases
|
|
seanhalle@34
|
69
|
|
seanhalle@34
|
70 //Moving the data and pointers to the new array is
|
|
seanhalle@34
|
71 //a little trickier than at first it seems.. the top part
|
|
seanhalle@34
|
72 // of old queue must be moved to the top part of new queue, while
|
|
seanhalle@34
|
73 // bottom part of old to bottom part of new, then the new insert
|
|
seanhalle@34
|
74 // and extract positions calculated by offset from top and bottom
|
|
seanhalle@34
|
75 //UNLESS the one case where old extract was at bottom and insert
|
|
seanhalle@34
|
76 // was at top.
|
|
seanhalle@34
|
77 //TODO: check that this is correct!
|
|
seanhalle@34
|
78 if( extractPos == startOfData && insertPos == endOfData )
|
|
seanhalle@34
|
79 {
|
|
seanhalle@34
|
80 memcpy( newStartOfData, oldStartOfData, oldSize ); //oldSize is bytes
|
|
seanhalle@34
|
81 Q->extractPos = Q->startOfData; //start of valid data
|
|
seanhalle@34
|
82 Q->insertPos = Q->startOfData + oldSize - 1; //end of valid data
|
|
seanhalle@34
|
83 }
|
|
seanhalle@34
|
84 else //have to copy two parts separately, then calc positions
|
|
seanhalle@34
|
85 { //TODO: check end-addr, sizes, and new positions carefully
|
|
seanhalle@34
|
86
|
|
seanhalle@34
|
87 //copy top part, starting at extract up until end of data,
|
|
seanhalle@34
|
88 // into top of new array
|
|
seanhalle@34
|
89 topPartSize = oldEndOfData - extractPos + 1; //+1 includes extractPos
|
|
seanhalle@34
|
90 copyStartAddr = newEndOfData - topPartSize + 1;//+1 cancels other
|
|
seanhalle@34
|
91 memcpy( copyStartAddr, Q->extractPos, topPartSize );
|
|
seanhalle@34
|
92 Q->extractPos = (void **)copyStartAddr; //extract just-copied data
|
|
seanhalle@34
|
93
|
|
seanhalle@34
|
94 //copy bottom part, from old start up to old insert,
|
|
seanhalle@34
|
95 // into bottom of new array
|
|
seanhalle@34
|
96 bottPartSize = oldSize - topPartSize - 1; //-1 for empty insertPos
|
|
seanhalle@34
|
97 memcpy( newStartOfData, oldStartOfData, bottPartSize );
|
|
seanhalle@34
|
98 Q->insertPos = (void **)(newStartOfData + bottPartSize);
|
|
seanhalle@34
|
99 }
|
|
seanhalle@34
|
100 //This free is not safe to use inside VMS-language!
|
|
seanhalle@34
|
101 free(oldStartOfData);
|
|
Me@19
|
102 }
|
|
Me@19
|
103
|
|
Me@19
|
104
|
|
Me@19
|
105 /*Returns NULL when queue is empty
|
|
Me@19
|
106 */
|
|
Me@19
|
107 void* readPrivQ( PrivQueueStruc* Q )
|
|
Me@19
|
108 { void *out = 0;
|
|
Me@19
|
109 void **startOfData = Q->startOfData;
|
|
Me@19
|
110 void **endOfData = Q->endOfData;
|
|
Me@19
|
111
|
|
Me@19
|
112 void **insertPos = Q->insertPos;
|
|
Me@19
|
113 void **extractPos = Q->extractPos;
|
|
Me@19
|
114
|
|
Me@19
|
115 //if not empty -- (extract is just below insert when empty)
|
|
Me@19
|
116 if( insertPos - extractPos != 1 &&
|
|
Me@19
|
117 !(extractPos == endOfData && insertPos == startOfData))
|
|
Me@19
|
118 { //move before read
|
|
Me@19
|
119 if( extractPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
120 { Q->extractPos = startOfData; //can't overrun then fix it 'cause
|
|
Me@19
|
121 } // other thread might read bad pos
|
|
Me@19
|
122 else
|
|
Me@19
|
123 { Q->extractPos++;
|
|
Me@19
|
124 }
|
|
Me@19
|
125 out = *(Q->extractPos);
|
|
Me@19
|
126 return out;
|
|
Me@19
|
127 }
|
|
Me@19
|
128 //Q is empty
|
|
Me@19
|
129 return NULL;
|
|
Me@19
|
130 }
|
|
Me@19
|
131
|
|
Me@19
|
132
|
|
Me@19
|
133 /*Expands the queue size automatically when it's full
|
|
Me@19
|
134 */
|
|
Me@19
|
135 void
|
|
Me@19
|
136 writePrivQ( void * in, PrivQueueStruc* Q )
|
|
Me@19
|
137 {
|
|
Me@19
|
138 void **startOfData = Q->startOfData;
|
|
Me@19
|
139 void **endOfData = Q->endOfData;
|
|
Me@19
|
140
|
|
Me@19
|
141 void **insertPos = Q->insertPos;
|
|
Me@19
|
142 void **extractPos = Q->extractPos;
|
|
Me@19
|
143
|
|
Me@19
|
144 tryAgain:
|
|
Me@19
|
145 //Full? (insert is just below extract when full)
|
|
Me@19
|
146 if( extractPos - insertPos != 1 &&
|
|
Me@19
|
147 !(insertPos == endOfData && extractPos == startOfData))
|
|
Me@19
|
148 { *(Q->insertPos) = in; //insert before move
|
|
Me@19
|
149 if( insertPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
150 { Q->insertPos = startOfData;
|
|
Me@19
|
151 }
|
|
Me@19
|
152 else
|
|
Me@19
|
153 { Q->insertPos++;
|
|
Me@19
|
154 }
|
|
Me@19
|
155 return;
|
|
Me@19
|
156 }
|
|
Me@19
|
157 //Q is full
|
|
Me@19
|
158 enlargePrivQ( Q );
|
|
Me@19
|
159 goto tryAgain;
|
|
Me@19
|
160 }
|
|
Me@19
|
161
|
|
Me@19
|
162
|
|
Me@19
|
163 /*Returns false when the queue was full.
|
|
Me@19
|
164 * have option of calling make_larger_PrivQ to make more room, then try again
|
|
Me@19
|
165 */
|
|
Me@19
|
166 int writeIfSpacePrivQ( void * in, PrivQueueStruc* Q )
|
|
Me@19
|
167 {
|
|
Me@19
|
168 void **startOfData = Q->startOfData;
|
|
Me@19
|
169 void **endOfData = Q->endOfData;
|
|
Me@19
|
170
|
|
Me@19
|
171 void **insertPos = Q->insertPos;
|
|
Me@19
|
172 void **extractPos = Q->extractPos;
|
|
Me@19
|
173
|
|
Me@19
|
174 if( extractPos - insertPos != 1 &&
|
|
Me@19
|
175 !(insertPos == endOfData && extractPos == startOfData))
|
|
Me@19
|
176 { *(Q->insertPos) = in; //insert before move
|
|
Me@19
|
177 if( insertPos == endOfData ) //write new pos exactly once, correctly
|
|
Me@19
|
178 { Q->insertPos = startOfData;
|
|
Me@19
|
179 }
|
|
Me@19
|
180 else
|
|
Me@19
|
181 { Q->insertPos++;
|
|
Me@19
|
182 }
|
|
Me@19
|
183 return TRUE;
|
|
Me@19
|
184 }
|
|
Me@19
|
185 //Q is full
|
|
Me@19
|
186 return FALSE;
|
|
Me@19
|
187 }
|
|
seanhalle@34
|
188
|
|
seanhalle@34
|
189 int32
|
|
seanhalle@34
|
190 numInPrivQ( PrivQueueStruc *Q )
|
|
seanhalle@34
|
191 { int32 size, numIn;
|
|
seanhalle@34
|
192
|
|
seanhalle@34
|
193 if( Q->insertPos < Q->extractPos )
|
|
seanhalle@34
|
194 { //insert has wrapped around so numIn is:
|
|
seanhalle@34
|
195 // insertPos + size - extractPos -- Consider, is empty when
|
|
seanhalle@34
|
196 // extractPos = endOfData and insert = start -- correctly get zero
|
|
seanhalle@34
|
197 size = Q->endOfData - Q->startOfData + 1; //sz of 10 is 0..9
|
|
seanhalle@34
|
198 numIn = Q->insertPos - Q->extractPos + size - 1; //-1 bec insrt empty
|
|
seanhalle@34
|
199 }
|
|
seanhalle@34
|
200 else
|
|
seanhalle@34
|
201 {
|
|
seanhalle@34
|
202 numIn = Q->insertPos - Q->extractPos -1;//-1 bec insertPos empty
|
|
seanhalle@34
|
203 }
|
|
seanhalle@34
|
204 return numIn;
|
|
seanhalle@34
|
205 }
|
|
seanhalle@34
|
206
|
|
seanhalle@34
|
207
|
|
seanhalle@34
|
208 /*Treats queue as a stack -- no matter contents, if read done right after
|
|
seanhalle@34
|
209 * a push, then the pushed item is what comes out.
|
|
seanhalle@34
|
210 * Expands the queue size automatically when it's full.
|
|
seanhalle@34
|
211 */
|
|
seanhalle@34
|
212 void
|
|
seanhalle@34
|
213 pushPrivQ( void * in, PrivQueueStruc* Q )
|
|
seanhalle@34
|
214 {
|
|
seanhalle@34
|
215 while(1){
|
|
seanhalle@34
|
216 void **startOfData = Q->startOfData;
|
|
seanhalle@34
|
217 void **endOfData = Q->endOfData;
|
|
seanhalle@34
|
218
|
|
seanhalle@34
|
219 void **insertPos = Q->insertPos;
|
|
seanhalle@34
|
220 void **extractPos = Q->extractPos;
|
|
seanhalle@34
|
221
|
|
seanhalle@34
|
222 //Full? (insert is just below extract when full)
|
|
seanhalle@34
|
223 if( extractPos - insertPos != 1 &&
|
|
seanhalle@34
|
224 !(insertPos == endOfData && extractPos == startOfData))
|
|
seanhalle@34
|
225 { //insert -- but go backwards, inserting at read position then
|
|
seanhalle@34
|
226 // move read pos backwards
|
|
seanhalle@34
|
227 *(Q->extractPos) = in;
|
|
seanhalle@34
|
228 if( extractPos == startOfData ) //write new pos exactly once, correctly
|
|
seanhalle@34
|
229 { Q->extractPos = endOfData; //can't overrun then fix it 'cause
|
|
seanhalle@34
|
230 } // other thread might read bad pos
|
|
seanhalle@34
|
231 else
|
|
seanhalle@34
|
232 { Q->extractPos--;
|
|
seanhalle@34
|
233 }
|
|
seanhalle@34
|
234 return;
|
|
seanhalle@34
|
235 }
|
|
seanhalle@34
|
236 //Q is full
|
|
seanhalle@34
|
237 enlargePrivQ( Q );
|
|
seanhalle@34
|
238 }
|
|
seanhalle@34
|
239 }
|
|
seanhalle@34
|
240
|
|
seanhalle@34
|
241
|
|
seanhalle@34
|
242 void
|
|
seanhalle@34
|
243 freePrivQ( PrivQueueStruc *Q )
|
|
seanhalle@34
|
244 {
|
|
seanhalle@34
|
245 //This free is not safe to use inside VMS-language!
|
|
seanhalle@34
|
246 free( Q->startOfData );
|
|
seanhalle@34
|
247 free( Q );
|
|
seanhalle@34
|
248 } |