Mercurial > cgi-bin > hgwebdir.cgi > VMS > C_Libraries > Queue_impl
comparison PrivateQueue.c @ 41:8fcbe46de60a
bugfixes - peek and enlarge now working properly
| author | Nina Engelhardt <nengel@mailbox.tu-berlin.de> |
|---|---|
| date | Wed, 19 Dec 2012 15:38:08 +0100 |
| parents | b9cb01d8ce56 |
| children | c54f7e0a9d11 |
comparison
equal
deleted
inserted
replaced
| 23:f63ccb59d744 | 24:8b6ec6c1dea5 |
|---|---|
| 6 * | 6 * |
| 7 * Author: seanhalle@yahoo.com | 7 * Author: seanhalle@yahoo.com |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 | 10 |
| 11 #include <string.h> | |
| 12 #include <stdlib.h> | |
| 11 #include <stdio.h> | 13 #include <stdio.h> |
| 12 #include <string.h> | |
| 13 #include <errno.h> | |
| 14 #include <stdlib.h> | |
| 15 | 14 |
| 16 #include "PrivateQueue.h" | 15 #include "PrivateQueue.h" |
| 17 | 16 |
| 18 | 17 |
| 19 | 18 |
| 34 memset( retQ->startOfData, 0, 1024 * sizeof(void *) ); | 33 memset( retQ->startOfData, 0, 1024 * sizeof(void *) ); |
| 35 retQ->extractPos = &(retQ->startOfData[0]); //side by side == empty | 34 retQ->extractPos = &(retQ->startOfData[0]); //side by side == empty |
| 36 retQ->insertPos = &(retQ->startOfData[1]); // so start pos's have to be | 35 retQ->insertPos = &(retQ->startOfData[1]); // so start pos's have to be |
| 37 retQ->endOfData = &(retQ->startOfData[1023]); | 36 retQ->endOfData = &(retQ->startOfData[1023]); |
| 38 | 37 |
| 38 #ifdef DEBUG_PRIVATE_Q | |
| 39 retQ->numReads = 0; | |
| 40 retQ->numWrites =0; | |
| 41 #endif | |
| 42 | |
| 39 return retQ; | 43 return retQ; |
| 40 } | 44 } |
| 41 | 45 |
| 42 | 46 |
| 43 void | 47 void |
| 44 enlargePrivQ( PrivQueueStruc *Q ) | 48 enlargePrivQ( PrivQueueStruc *Q ) |
| 45 { int32 oldSize, newSize, topPartSize, bottPartSize; | 49 { size_t oldSize, newSize, topPartSize, bottPartSize; |
| 46 int8 *insertPos, *extractPos; | 50 char *insertPos, *extractPos; |
| 47 int8 *oldStartOfData, *oldEndOfData, *newStartOfData, *newEndOfData; | 51 char *oldStartOfData, *oldEndOfData, *newStartOfData, *newEndOfData; |
| 48 int32 insertOffsetBytes, extractOffsetBytes; | 52 size_t insertOffsetBytes, extractOffsetBytes; |
| 49 int8 *copyStartAddr; | 53 char* copyStartAddr; |
| 50 | 54 |
| 51 oldStartOfData = (int8 *)Q->startOfData; | 55 #ifdef DEBUG_PRIVATE_Q |
| 52 oldEndOfData = (int8 *)Q->endOfData; | 56 printf("Enlarging queue Q = %p\nnumReads = %d; numWrites = %d\n",Q,Q->numReads,Q->numWrites); |
| 53 insertPos = (int8 *)Q->insertPos; | 57 #endif |
| 54 extractPos = (int8 *)Q->extractPos; | 58 |
| 59 oldStartOfData = (char*)Q->startOfData; | |
| 60 oldEndOfData = (char*)(Q->endOfData + 1); | |
| 61 insertPos = (char*)Q->insertPos; | |
| 62 extractPos = (char*)Q->extractPos; | |
| 55 | 63 |
| 56 //TODO: verify these get number of bytes correct | 64 //TODO: verify these get number of bytes correct |
| 57 insertOffsetBytes = (int32)(insertPos - oldStartOfData); | 65 insertOffsetBytes = (insertPos - oldStartOfData); |
| 58 extractOffsetBytes = (int32)(extractPos - oldStartOfData); | 66 extractOffsetBytes = (extractPos - oldStartOfData); |
| 59 | 67 |
| 60 oldSize = oldEndOfData - oldStartOfData + 1; //in bytes | 68 oldSize = oldEndOfData - oldStartOfData; //in bytes |
| 61 newSize = 2 * oldSize; | 69 newSize = 2 * oldSize; |
| 62 | 70 |
| 71 #ifdef DEBUG_PRIVATE_Q | |
| 72 printf("Old size = %d, new size = %d\n",(int)oldSize,(int)newSize); | |
| 73 #endif | |
| 74 | |
| 63 //This malloc is not safe to use in wrapper lib nor app code! | 75 //This malloc is not safe to use in wrapper lib nor app code! |
| 64 Q->startOfData = (void **)VMS_int__malloc( newSize ); | 76 newStartOfData = (char *) VMS_int__malloc( newSize ); |
| 65 newStartOfData = (int8 *)Q->startOfData; | 77 if(newStartOfData == NULL){ |
| 78 perror("malloc"); exit(1); | |
| 79 } | |
| 66 newEndOfData = newStartOfData + newSize; //all calcs in Bytes | 80 newEndOfData = newStartOfData + newSize; //all calcs in Bytes |
| 67 Q->endOfData = (void **)newEndOfData; | 81 |
| 68 | |
| 69 //TODO: test all of this, for both cases | 82 //TODO: test all of this, for both cases |
| 70 | 83 Q->startOfData = newStartOfData; |
| 84 Q->endOfData = ((void **)newEndOfData) - 1; | |
| 85 | |
| 71 //Moving the data and pointers to the new array is | 86 //Moving the data and pointers to the new array is |
| 72 //a little trickier than at first it seems.. the top part | 87 //a little trickier than at first it seems.. the top part |
| 73 // of old queue must be moved to the top part of new queue, while | 88 // of old queue must be moved to the top part of new queue, while |
| 74 // bottom part of old to bottom part of new, then the new insert | 89 // bottom part of old to bottom part of new, then the new insert |
| 75 // and extract positions calculated by offset from top and bottom | 90 // and extract positions calculated by offset from top and bottom |
| 76 //UNLESS the one case where old extract was at bottom and insert | 91 //UNLESS the one case where old extract was at bottom and insert |
| 77 // was at top. | 92 // was at top. |
| 78 //TODO: check that this is correct! | 93 //TODO: check that this is correct! |
| 79 if( extractPos == oldStartOfData && insertPos == oldEndOfData ) | 94 if( extractPos == oldStartOfData ) |
| 80 { | 95 { |
| 81 memcpy( newStartOfData, oldStartOfData, oldSize ); //oldSize is bytes | 96 memcpy( newStartOfData, oldStartOfData, oldSize ); //oldSize is bytes |
| 82 Q->extractPos = Q->startOfData; //start of valid data | 97 Q->extractPos = Q->startOfData; //start of valid data |
| 83 Q->insertPos = Q->startOfData + oldSize - 1; //end of valid data | 98 Q->insertPos = (void**)(newStartOfData + insertOffsetBytes); //end of valid data |
| 84 } | 99 } |
| 85 else //have to copy two parts separately, then calc positions | 100 else //have to copy two parts separately, then calc positions |
| 86 { //TODO: check end-addr, sizes, and new positions carefully | 101 { //TODO: check end-addr, sizes, and new positions carefully |
| 87 | 102 |
| 88 //copy top part, starting at extract up until end of data, | 103 //copy top part, starting at extract up until end of data, |
| 89 // into top of new array | 104 // into top of new array |
| 90 topPartSize = oldEndOfData - extractPos + 1; //+1 includes extractPos | 105 topPartSize = oldEndOfData - extractPos; |
| 91 copyStartAddr = newEndOfData - topPartSize + 1;//+1 cancels other | 106 copyStartAddr = newEndOfData - topPartSize; |
| 92 memcpy( copyStartAddr, Q->extractPos, topPartSize ); | 107 memcpy( copyStartAddr, extractPos, topPartSize ); |
| 93 Q->extractPos = (void **)copyStartAddr; //extract just-copied data | 108 Q->extractPos = (void **)copyStartAddr; //extract just-copied data |
| 94 | 109 |
| 95 //copy bottom part, from old start up to old insert, | 110 //copy bottom part, from old start up to old insert, |
| 96 // into bottom of new array | 111 // into bottom of new array |
| 97 bottPartSize = oldSize - topPartSize - 1; //-1 for empty insertPos | 112 bottPartSize = insertPos - oldStartOfData; //-1 for empty insertPos |
| 98 memcpy( newStartOfData, oldStartOfData, bottPartSize ); | 113 memcpy( newStartOfData, oldStartOfData, bottPartSize ); |
| 99 Q->insertPos = (void **)(newStartOfData + bottPartSize); | 114 Q->insertPos = (void **)(newStartOfData + bottPartSize); |
| 100 } | 115 } |
| 101 //This free is not safe to use in wrapper lib nor app code! | 116 //This free is not safe to use in wrapper lib nor app code! |
| 102 VMS_int__free(oldStartOfData); | 117 VMS_int__free(oldStartOfData); |
| 135 | 150 |
| 136 //if not empty -- (extract is just below insert when empty) | 151 //if not empty -- (extract is just below insert when empty) |
| 137 if( insertPos - extractPos != 1 && | 152 if( insertPos - extractPos != 1 && |
| 138 !(extractPos == endOfData && insertPos == startOfData)) | 153 !(extractPos == endOfData && insertPos == startOfData)) |
| 139 { | 154 { |
| 140 out = *(Q->extractPos); | 155 out = *(Q->extractPos + 1); |
| 141 return out; | 156 return out; |
| 142 } | 157 } |
| 143 //Q is empty | 158 //Q is empty |
| 144 return NULL; | 159 return NULL; |
| 145 } | 160 } |
| 146 | 161 |
| 147 | |
| 148 /*Returns NULL when queue is empty | 162 /*Returns NULL when queue is empty |
| 149 */ | 163 */ |
| 150 void* readPrivQ( PrivQueueStruc* Q ) | 164 void* readPrivQ(PrivQueueStruc* Q) { |
| 151 { void *out = 0; | 165 #ifdef DEBUG_PRIVATE_Q |
| 152 void **startOfData = Q->startOfData; | 166 Q->numReads++; |
| 153 void **endOfData = Q->endOfData; | 167 #endif |
| 154 | 168 |
| 155 void **insertPos = Q->insertPos; | 169 void *out = 0; |
| 156 void **extractPos = Q->extractPos; | 170 void **startOfData = Q->startOfData; |
| 157 | 171 void **endOfData = Q->endOfData; |
| 158 //if not empty -- (extract is just below insert when empty) | 172 |
| 159 if( insertPos - extractPos != 1 && | 173 void **insertPos = Q->insertPos; |
| 160 !(extractPos == endOfData && insertPos == startOfData)) | 174 void **extractPos = Q->extractPos; |
| 161 { //move before read | 175 |
| 162 if( extractPos == endOfData ) //write new pos exactly once, correctly | 176 //if not empty -- (extract is just below insert when empty) |
| 163 { Q->extractPos = startOfData; //can't overrun then fix it 'cause | 177 if (insertPos - extractPos != 1 && |
| 164 } // other thread might read bad pos | 178 !(extractPos == endOfData && insertPos == startOfData)) { //move before read |
| 165 else | 179 if (extractPos == endOfData) //write new pos exactly once, correctly |
| 166 { Q->extractPos++; | 180 { |
| 167 } | 181 Q->extractPos = startOfData; //can't overrun then fix it 'cause |
| 168 out = *(Q->extractPos); | 182 }// other thread might read bad pos |
| 169 return out; | 183 else { |
| 170 } | 184 Q->extractPos++; |
| 171 //Q is empty | 185 } |
| 172 return NULL; | 186 out = *(Q->extractPos); |
| 173 } | 187 return out; |
| 174 | 188 } |
| 175 | 189 //Q is empty |
| 190 return NULL; | |
| 191 } | |
| 176 /*Expands the queue size automatically when it's full | 192 /*Expands the queue size automatically when it's full |
| 177 */ | 193 */ |
| 178 void | 194 void |
| 179 writePrivQ( void * in, PrivQueueStruc* Q ) | 195 writePrivQ(void * in, PrivQueueStruc* Q) { |
| 196 | |
| 197 #ifdef DEBUG_PRIVATE_Q | |
| 198 Q->numWrites++; | |
| 199 #endif | |
| 200 | |
| 201 //tryAgain: | |
| 202 //Full? (insert is just below extract when full) | |
| 203 if ((Q->extractPos - Q->insertPos) == 1 || | |
| 204 (Q->insertPos == Q->endOfData && Q->extractPos == Q->startOfData)) { | |
| 205 enlargePrivQ(Q); | |
| 206 } | |
| 207 | |
| 208 *(Q->insertPos) = in; //insert before move | |
| 209 if (Q->insertPos == Q->endOfData) //write new pos exactly once, correctly | |
| 210 { | |
| 211 Q->insertPos = Q->startOfData; | |
| 212 } else { | |
| 213 Q->insertPos++; | |
| 214 } | |
| 215 return; | |
| 216 | |
| 217 //Q is full | |
| 218 | |
| 219 //goto tryAgain; | |
| 220 } | |
| 221 | |
| 222 | |
| 223 /*Returns false when the queue was full. | |
| 224 * have option of calling make_larger_PrivQ to make more room, then try again | |
| 225 */ | |
| 226 bool32 | |
| 227 writeIfSpacePrivQ( void * in, PrivQueueStruc* Q ) | |
| 180 { | 228 { |
| 181 void **startOfData = Q->startOfData; | 229 void **startOfData = Q->startOfData; |
| 182 void **endOfData = Q->endOfData; | 230 void **endOfData = Q->endOfData; |
| 183 | 231 |
| 184 void **insertPos = Q->insertPos; | 232 void **insertPos = Q->insertPos; |
| 185 void **extractPos = Q->extractPos; | 233 void **extractPos = Q->extractPos; |
| 186 | 234 |
| 187 tryAgain: | |
| 188 //Full? (insert is just below extract when full) | |
| 189 if( extractPos - insertPos != 1 && | 235 if( extractPos - insertPos != 1 && |
| 190 !(insertPos == endOfData && extractPos == startOfData)) | 236 !(insertPos == endOfData && extractPos == startOfData)) |
| 191 { *(Q->insertPos) = in; //insert before move | 237 { *(Q->insertPos) = in; //insert before move |
| 192 if( insertPos == endOfData ) //write new pos exactly once, correctly | 238 if( insertPos == endOfData ) //write new pos exactly once, correctly |
| 193 { Q->insertPos = startOfData; | 239 { Q->insertPos = startOfData; |
| 194 } | 240 } |
| 195 else | 241 else |
| 196 { Q->insertPos++; | 242 { Q->insertPos++; |
| 197 } | 243 } |
| 198 return; | 244 #ifdef DEBUG_PRIVATE_Q |
| 199 } | 245 Q->numWrites++; |
| 200 //Q is full | 246 #endif |
| 201 enlargePrivQ( Q ); | |
| 202 goto tryAgain; | |
| 203 } | |
| 204 | |
| 205 | |
| 206 /*Returns false when the queue was full. | |
| 207 * have option of calling make_larger_PrivQ to make more room, then try again | |
| 208 */ | |
| 209 bool32 | |
| 210 writeIfSpacePrivQ( void * in, PrivQueueStruc* Q ) | |
| 211 { | |
| 212 void **startOfData = Q->startOfData; | |
| 213 void **endOfData = Q->endOfData; | |
| 214 | |
| 215 void **insertPos = Q->insertPos; | |
| 216 void **extractPos = Q->extractPos; | |
| 217 | |
| 218 if( extractPos - insertPos != 1 && | |
| 219 !(insertPos == endOfData && extractPos == startOfData)) | |
| 220 { *(Q->insertPos) = in; //insert before move | |
| 221 if( insertPos == endOfData ) //write new pos exactly once, correctly | |
| 222 { Q->insertPos = startOfData; | |
| 223 } | |
| 224 else | |
| 225 { Q->insertPos++; | |
| 226 } | |
| 227 return TRUE; | 247 return TRUE; |
| 228 } | 248 } |
| 229 //Q is full | 249 //Q is full |
| 230 return FALSE; | 250 return FALSE; |
| 231 } | 251 } |
| 254 * Expands the queue size automatically when it's full. | 274 * Expands the queue size automatically when it's full. |
| 255 */ | 275 */ |
| 256 void | 276 void |
| 257 pushPrivQ( void * in, PrivQueueStruc* Q ) | 277 pushPrivQ( void * in, PrivQueueStruc* Q ) |
| 258 { | 278 { |
| 279 #ifdef DEBUG_PRIVATE_Q | |
| 280 Q->numWrites++; | |
| 281 #endif | |
| 259 while(1){ | 282 while(1){ |
| 260 void **startOfData = Q->startOfData; | 283 void **startOfData = Q->startOfData; |
| 261 void **endOfData = Q->endOfData; | 284 void **endOfData = Q->endOfData; |
| 262 | 285 |
| 263 void **insertPos = Q->insertPos; | 286 void **insertPos = Q->insertPos; |
