Me@0: /* Me@8: * Copyright 2009 OpenSourceStewardshipFoundation.org Me@0: * Licensed under GNU General Public License version 2 Me@0: * Me@0: * Author: seanhalle@yahoo.com Me@0: */ Me@0: Me@0: Me@0: #include Me@0: #include Me@0: #include Me@0: #include Me@0: Me@0: #include "PrivateQueue.h" msach@17: #include "../vmalloc.h" Me@0: Me@0: Me@0: Me@0: //=========================================================================== Me@0: Me@0: /*This kind of queue is private to a single core at a time -- has no Me@0: * synchronizations Me@0: */ Me@0: Me@16: PrivQueueStruc* makeVMSPrivQ() Me@0: { msach@17: PrivQueueStruc *retQ; msach@17: retQ = VMS__malloc( sizeof( PrivQueueStruc ) ); msach@17: retQ->startOfData = (void*)VMS__malloc( 1024 * sizeof(void *) ); Me@14: memset( retQ->startOfData, 0, 1024 ); Me@14: Me@0: retQ->extractPos = &(retQ->startOfData[0]); //side by side == empty Me@0: retQ->insertPos = &(retQ->startOfData[1]); // so start pos's have to be Me@0: retQ->endOfData = &(retQ->startOfData[1023]); Me@0: Me@0: return retQ; Me@0: } Me@0: Me@2: Me@2: void Me@2: enlargePrivQ( PrivQueueStruc *Q ) msach@18: { size_t oldSize, newSize; Me@0: void **oldStartOfData; Me@0: msach@18: oldSize = Q->endOfData - Q->startOfData + 1; Me@0: newSize = 2 * oldSize; Me@6: oldStartOfData = Q->startOfData; msach@18: Q->startOfData = VMS__malloc( newSize * sizeof(void*)); msach@18: //copy second half msach@18: size_t secondHalfSize = Q->endOfData - Q->extractPos + 1; msach@18: memcpy(Q->startOfData,Q->extractPos, secondHalfSize * sizeof(void*)); msach@18: //copy first half msach@18: memcpy(Q->startOfData + secondHalfSize, oldStartOfData, msach@18: (oldSize-secondHalfSize) * sizeof(void*)); Me@9: VMS__free(oldStartOfData); Me@0: msach@18: Q->extractPos = Q->startOfData; msach@18: Q->insertPos = Q->startOfData + oldSize - 1; Me@0: Q->endOfData = &(Q->startOfData[newSize - 1]); Me@0: } Me@0: Me@0: Me@0: /*Returns NULL when queue is empty Me@0: */ Me@0: void* readPrivQ( PrivQueueStruc* Q ) Me@0: { void *out = 0; Me@2: void **startOfData = Q->startOfData; Me@2: void **endOfData = Q->endOfData; Me@0: Me@2: void **insertPos = Q->insertPos; Me@2: void **extractPos = Q->extractPos; Me@0: Me@6: //if not empty -- (extract is just below insert when empty) Me@0: if( insertPos - extractPos != 1 && Me@0: !(extractPos == endOfData && insertPos == startOfData)) Me@0: { //move before read Me@0: if( extractPos == endOfData ) //write new pos exactly once, correctly Me@0: { Q->extractPos = startOfData; //can't overrun then fix it 'cause Me@0: } // other thread might read bad pos Me@0: else Me@0: { Q->extractPos++; Me@0: } Me@0: out = *(Q->extractPos); Me@0: return out; Me@0: } Me@0: //Q is empty Me@0: return NULL; Me@0: } Me@0: Me@11: int32 Me@11: numInPrivQ( PrivQueueStruc *Q ) Me@11: { int32 size, numIn; Me@11: Me@11: if( Q->insertPos < Q->extractPos ) Me@11: { //insert has wrapped around so numIn is: Me@11: // insertPos + size - extractPos -- Consider, is empty when Me@11: // extractPos = endOfData and insert = start -- correctly get zero Me@11: size = Q->endOfData - Q->startOfData; Me@11: numIn = Q->insertPos + size - Q->extractPos; Me@11: } Me@11: else Me@11: { Me@11: numIn = Q->insertPos - Q->extractPos -1;//-1 bec empty @ side-by-side Me@11: } Me@11: return numIn; Me@11: } Me@11: Me@2: Me@2: /*Expands the queue size automatically when it's full Me@2: */ Me@2: void Me@6: writePrivQ( void * in, PrivQueueStruc* Q ) Me@2: { msach@18: while(1){ msach@18: void **startOfData = Q->startOfData; msach@18: void **endOfData = Q->endOfData; Me@2: msach@18: void **insertPos = Q->insertPos; msach@18: void **extractPos = Q->extractPos; msach@18: msach@18: //Full? (insert is just below extract when full) msach@18: if( extractPos - insertPos != 1 && msach@18: !(insertPos == endOfData && extractPos == startOfData)) msach@18: { *(Q->insertPos) = in; //insert before move msach@18: if( insertPos == endOfData ) //write new pos exactly once, correctly msach@18: { Q->insertPos = startOfData; msach@18: } msach@18: else msach@18: { Q->insertPos++; msach@18: } msach@18: return; msach@18: } msach@18: //Q is full msach@18: enlargePrivQ( Q ); msach@18: } Me@2: } Me@2: Me@2: Me@0: /*Returns false when the queue was full. Me@0: * have option of calling make_larger_PrivQ to make more room, then try again Me@0: */ Me@6: int writeIfSpacePrivQ( void * in, PrivQueueStruc* Q ) Me@0: { Me@2: void **startOfData = Q->startOfData; Me@2: void **endOfData = Q->endOfData; Me@2: Me@2: void **insertPos = Q->insertPos; Me@2: void **extractPos = Q->extractPos; Me@0: Me@0: if( extractPos - insertPos != 1 && Me@0: !(insertPos == endOfData && extractPos == startOfData)) Me@2: { *(Q->insertPos) = in; //insert before move Me@0: if( insertPos == endOfData ) //write new pos exactly once, correctly Me@0: { Q->insertPos = startOfData; Me@0: } Me@0: else Me@0: { Q->insertPos++; Me@0: } Me@0: return TRUE; Me@0: } Me@0: //Q is full Me@0: return FALSE; Me@0: } Me@9: SeanHalle@12: /*Treats queue as a stack -- no matter contents, if read done right after SeanHalle@12: * a push, then the pushed item is what comes out. SeanHalle@12: * Expands the queue size automatically when it's full. SeanHalle@12: */ SeanHalle@12: void SeanHalle@12: pushPrivQ( void * in, PrivQueueStruc* Q ) SeanHalle@12: { msach@18: while(1){ msach@18: void **startOfData = Q->startOfData; msach@18: void **endOfData = Q->endOfData; SeanHalle@12: msach@18: void **insertPos = Q->insertPos; msach@18: void **extractPos = Q->extractPos; SeanHalle@12: msach@18: //Full? (insert is just below extract when full) msach@18: if( extractPos - insertPos != 1 && msach@18: !(insertPos == endOfData && extractPos == startOfData)) msach@18: { //insert -- but go backwards, inserting at read position then msach@18: // move read pos backwards msach@18: *(Q->extractPos) = in; msach@18: if( extractPos == startOfData ) //write new pos exactly once, correctly msach@18: { Q->extractPos = endOfData; //can't overrun then fix it 'cause msach@18: } // other thread might read bad pos msach@18: else msach@18: { Q->extractPos--; msach@18: } msach@18: return; msach@18: } msach@18: //Q is full msach@18: enlargePrivQ( Q ); msach@18: } SeanHalle@12: } SeanHalle@12: Me@9: void Me@9: freePrivQ( PrivQueueStruc *Q ) Me@9: { Me@9: VMS__free( Q->startOfData ); Me@9: VMS__free( Q ); Me@9: }