Improved bucketLib.c & portability changes
This commit is contained in:
+430
-239
@@ -29,12 +29,17 @@
|
||||
* -----------------
|
||||
* .01 091493 joh fixed overzealous parameter check
|
||||
* .02 121693 joh added bucketFree()
|
||||
*
|
||||
* NOTES:
|
||||
* .01 Storage for identifier must persist until an item is deleted
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <bucketLib.h>
|
||||
|
||||
@@ -48,142 +53,312 @@
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif /* FALSE */
|
||||
#ifndef LOCAL
|
||||
#define LOCAL static
|
||||
#endif /* LOCAL */
|
||||
#ifndef max
|
||||
#define max(A,B) ((A)>(B)?(A):(B))
|
||||
#endif /* max */
|
||||
|
||||
#define BUCKET_IX_WIDTH 12
|
||||
#define BUCKET_IX_N (1<<BUCKET_IX_WIDTH)
|
||||
#define BUCKET_IX_MASK (BUCKET_IX_N-1)
|
||||
/*
|
||||
* these data type dependent routines are
|
||||
* provided in the bucketLib.c
|
||||
*/
|
||||
typedef BUCKETID bucketHash(BUCKET *pb, const void *pId);
|
||||
typedef ITEM **bucketCompare(ITEM **ppi, const void *pId);
|
||||
|
||||
LOCAL bucketCompare bucketUnsignedCompare;
|
||||
LOCAL bucketCompare bucketPointerCompare;
|
||||
LOCAL bucketCompare bucketStringCompare;
|
||||
LOCAL bucketHash bucketUnsignedHash;
|
||||
LOCAL bucketHash bucketPointerHash;
|
||||
LOCAL bucketHash bucketStringHash;
|
||||
|
||||
typedef struct {
|
||||
bucketHash *pHash;
|
||||
bucketCompare *pCompare;
|
||||
buckTypeOfId type;
|
||||
}bucketSET;
|
||||
|
||||
LOCAL bucketSET BSET[] = {
|
||||
{bucketUnsignedHash, bucketUnsignedCompare, bidtUnsigned},
|
||||
{bucketPointerHash, bucketPointerCompare, bidtPointer},
|
||||
{bucketStringHash, bucketStringCompare, bidtString}
|
||||
};
|
||||
|
||||
LOCAL int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, void *pApp);
|
||||
LOCAL int bucketRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId);
|
||||
LOCAL void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucket id bit width
|
||||
*/
|
||||
#define BUCKETID_BIT_WIDTH (sizeof(BUCKETID)*NBBY)
|
||||
|
||||
/*
|
||||
* Maximum bucket size
|
||||
*/
|
||||
#define BUCKET_MAX_WIDTH 12
|
||||
|
||||
#ifdef DEBUG
|
||||
#error This is out of date
|
||||
main()
|
||||
{
|
||||
BUCKETID id;
|
||||
BUCKETID id1;
|
||||
BUCKETID id2;
|
||||
char *pValSave1;
|
||||
char *pValSave2;
|
||||
int s;
|
||||
BUCKET *pb;
|
||||
char *pValSave;
|
||||
char *pVal;
|
||||
unsigned i;
|
||||
clock_t start, finish;
|
||||
double duration;
|
||||
const int LOOPS = 500000;
|
||||
|
||||
pb = bucketCreate(NBBY*sizeof(BUCKETID));
|
||||
pb = bucketCreate(8);
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
id = 444;
|
||||
pValSave = "fred";
|
||||
s = bucketAddItem(pb, id, pValSave);
|
||||
if(s != BUCKET_SUCCESS){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
id1 = 0x1000a432;
|
||||
pValSave1 = "fred";
|
||||
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
|
||||
printf("Begin\n");
|
||||
for(i=0; i<500000; i++){
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pValSave2 = "jane";
|
||||
s = bucketAddItemStringId(pb, pValSave2, pValSave2);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id2);
|
||||
assert(pVal == pValSave2);
|
||||
}
|
||||
printf("End\n");
|
||||
finish = clock();
|
||||
|
||||
duration = finish-start;
|
||||
duration = duration/CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec\n", duration);
|
||||
duration = duration/LOOPS;
|
||||
duration = duration/10;
|
||||
duration = duration * 1e6;
|
||||
printf("It took %15.10f u sec per hash lookup\n", duration);
|
||||
|
||||
bucketShow(pb);
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedCompare()
|
||||
*/
|
||||
LOCAL ITEM **bucketUnsignedCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
unsigned id;
|
||||
unsigned *pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
id = * (unsigned *) pId;
|
||||
while (pi = *ppi) {
|
||||
if (bidtUnsigned == pi->type) {
|
||||
pItemId = (unsigned *) pi->pId;
|
||||
if (id == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerCompare()
|
||||
*/
|
||||
ITEM **bucketPointerCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
void *ptr;
|
||||
void **pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
ptr = * (void **) pId;
|
||||
while (pi = *ppi) {
|
||||
if (bidtPointer == pi->type ) {
|
||||
pItemId = (void **) pi->pId;
|
||||
if (ptr == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringCompare ()
|
||||
*/
|
||||
ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
ITEM *pi;
|
||||
int status;
|
||||
|
||||
while (pi = *ppi) {
|
||||
if (bidtString == pi->type) {
|
||||
status = strcmp (pStr, (char *)pi->pId);
|
||||
if (status == '\0') {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedHash ()
|
||||
*/
|
||||
BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const unsigned *pUId = pId;
|
||||
unsigned src;
|
||||
BUCKETID hashid;
|
||||
|
||||
src = *pUId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while (src) {
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerHash ()
|
||||
*
|
||||
*/
|
||||
BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
void * const *ppId = pId;
|
||||
unsigned long src;
|
||||
BUCKETID hashid;
|
||||
|
||||
/*
|
||||
* This makes the assumption that
|
||||
* a pointer will fit inside of a long
|
||||
* (this assumption may not port to all
|
||||
* CPU architectures)
|
||||
*/
|
||||
src = (unsigned long) *ppId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while(src){
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringHash ()
|
||||
*/
|
||||
BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
BUCKETID hashid;
|
||||
unsigned i;
|
||||
|
||||
hashid = 0;
|
||||
i = 1;
|
||||
while(*pStr){
|
||||
hashid += *pStr * i;
|
||||
pStr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
hashid = hashid % (pb->hashIdMask+1);
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketCreate()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
BUCKET *bucketCreate(unsigned indexWidth)
|
||||
#else
|
||||
BUCKET *bucketCreate(indexWidth)
|
||||
unsigned indexWidth;
|
||||
#endif
|
||||
BUCKET *bucketCreate (unsigned nHashTableEntries)
|
||||
{
|
||||
BUCKETID mask;
|
||||
unsigned nbits;
|
||||
BUCKET *pb;
|
||||
|
||||
if (nHashTableEntries==0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* count the number of bits in the bucket id
|
||||
*/
|
||||
for (nbits=0; nbits<BUCKETID_BIT_WIDTH; nbits++) {
|
||||
mask = (1<<nbits) - 1;
|
||||
if ( ((nHashTableEntries-1) & ~mask) == 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* indexWidth must be specified at least one
|
||||
* bit less than the bit size of type BUCKETID
|
||||
*/
|
||||
if(indexWidth>sizeof(BUCKETID)*NBBY){
|
||||
printf("%s at %d: Requested index width=%d is to large. max=%d\n" ,
|
||||
if (nbits>=BUCKETID_BIT_WIDTH) {
|
||||
printf("%s at %d: Requested index width=%d to large. max=%d\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
indexWidth,
|
||||
sizeof(BUCKETID)*NBBY-1);
|
||||
nbits,
|
||||
BUCKETID_BIT_WIDTH-1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pb = (BUCKET *) calloc(1, sizeof(*pb));
|
||||
if(!pb){
|
||||
if (!pb) {
|
||||
return pb;
|
||||
}
|
||||
|
||||
if(indexWidth>BUCKET_IX_WIDTH){
|
||||
pb->indexShift = indexWidth - BUCKET_IX_WIDTH;
|
||||
}
|
||||
else{
|
||||
pb->indexShift = 0;
|
||||
}
|
||||
pb->nextIndexMask = (1<<pb->indexShift)-1;
|
||||
pb->nEntries = 1<<(indexWidth-pb->indexShift);
|
||||
if(indexWidth == sizeof(BUCKETID)*NBBY){
|
||||
pb->indexMask = 0;
|
||||
pb->indexMask = ~pb->indexMask;
|
||||
}
|
||||
else{
|
||||
pb->indexMask = (1<<indexWidth)-1;
|
||||
}
|
||||
pb->hashIdMask = mask;
|
||||
pb->hashIdNBits = nbits;
|
||||
|
||||
pb->pTable = (ITEMPTR *) calloc(
|
||||
pb->nEntries,
|
||||
sizeof(ITEMPTR));
|
||||
pb->pTable = (ITEM **) calloc (mask+1, sizeof(*pb->pTable));
|
||||
if(!pb->pTable){
|
||||
free(pb);
|
||||
return NULL;
|
||||
@@ -202,14 +377,24 @@ int bucketFree(prb)
|
||||
BUCKET *prb;
|
||||
#endif
|
||||
{
|
||||
ITEM *pi;
|
||||
ITEM *pni;
|
||||
|
||||
/*
|
||||
* deleting a bucket with entries in use
|
||||
* will cause memory leaks and is not allowed
|
||||
*/
|
||||
if(prb->nInUse){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
assert(prb->nInUse==0);
|
||||
|
||||
/*
|
||||
* free the free list
|
||||
*/
|
||||
pi = prb->pFreeItems;
|
||||
while (pi) {
|
||||
pni = pi->pItem;
|
||||
free (pi);
|
||||
pi = pni;
|
||||
}
|
||||
free(prb->pTable);
|
||||
free(prb);
|
||||
|
||||
@@ -220,69 +405,49 @@ BUCKET *prb;
|
||||
/*
|
||||
* bucketAddItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int bucketAddItem(BUCKET *prb, BUCKETID id, void *pItem)
|
||||
#else
|
||||
int bucketAddItem(prb, id, pItem)
|
||||
BUCKET *prb;
|
||||
BUCKETID id;
|
||||
void *pItem;
|
||||
#endif
|
||||
int bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, void *pApp)
|
||||
{
|
||||
int s;
|
||||
ITEMPTR *pi;
|
||||
return bucketAddItem(prb, &BSET[bidtUnsigned], pId, pApp);
|
||||
}
|
||||
int bucketAddItemPointerId(BUCKET *prb, void * const *pId, void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtPointer], pId, pApp);
|
||||
}
|
||||
int bucketAddItemStringId(BUCKET *prb, const char *pId, void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtString], pId, pApp);
|
||||
}
|
||||
LOCAL int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, void *pApp)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM *pi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* try to get it off the free list first. If
|
||||
* that fails then malloc()
|
||||
*/
|
||||
if(id&~prb->indexMask){
|
||||
return BUCKET_FAILURE;
|
||||
pi = prb->pFreeItems;
|
||||
if (pi) {
|
||||
prb->pFreeItems = pi->pItem;
|
||||
}
|
||||
|
||||
if(prb->indexShift){
|
||||
int new;
|
||||
BUCKET *pb;
|
||||
|
||||
pi = &prb->pTable[id>>prb->indexShift];
|
||||
pb = pi->pBucket;
|
||||
|
||||
if(!pb){
|
||||
pb = bucketCreate(prb->indexShift);
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
pi->pBucket = pb;
|
||||
prb->nInUse++;
|
||||
new = TRUE;
|
||||
}
|
||||
else{
|
||||
new = FALSE;
|
||||
else {
|
||||
pi = (ITEM *) malloc(sizeof(ITEM));
|
||||
if(!pi){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
s = bucketAddItem(
|
||||
pb,
|
||||
id&prb->nextIndexMask,
|
||||
pItem);
|
||||
/*
|
||||
* if memory cant be allocated at a lower
|
||||
* level dont leak everything allocated for this new
|
||||
* item so far
|
||||
*/
|
||||
if(s != BUCKET_SUCCESS && new){
|
||||
s = bucketFree(pb);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
pi->pBucket = NULL;
|
||||
prb->nInUse--;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
pi = &prb->pTable[id];
|
||||
if(pi->pItem){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
pi->pItem = pItem;
|
||||
/*
|
||||
* create the hash index
|
||||
*/
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
pi->pApp = pApp;
|
||||
pi->pId = pId;
|
||||
pi->type = pBSET->type;
|
||||
assert((hashid & ~prb->hashIdMask) == 0);
|
||||
pi->pItem = prb->pTable[hashid];
|
||||
prb->pTable[hashid] = pi;
|
||||
prb->nInUse++;
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
@@ -292,97 +457,85 @@ void *pItem;
|
||||
/*
|
||||
* bucketRemoveItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int bucketRemoveItem (BUCKET *prb, BUCKETID id, void *pItem)
|
||||
#else
|
||||
int bucketRemoveItem (prb, id, pItem)
|
||||
BUCKET *prb;
|
||||
BUCKETID id;
|
||||
void *pItem;
|
||||
#endif
|
||||
int bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
ITEMPTR *ppi;
|
||||
return bucketRemoveItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
int bucketRemoveItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketRemoveItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
int bucketRemoveItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketRemoveItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
LOCAL int bucketRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* create the hash index
|
||||
*/
|
||||
if(id&~prb->indexMask){
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
assert((hashid & ~prb->hashIdMask) == 0);
|
||||
ppi = &prb->pTable[hashid];
|
||||
ppi = (*pBSET->pCompare) (ppi, pId);
|
||||
if(!ppi){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
if(prb->indexShift){
|
||||
BUCKET *pb;
|
||||
int s;
|
||||
|
||||
ppi = &prb->pTable[id>>prb->indexShift];
|
||||
pb = ppi->pBucket;
|
||||
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
s = bucketRemoveItem(
|
||||
pb,
|
||||
id&prb->nextIndexMask,
|
||||
pItem);
|
||||
if(s!=BUCKET_SUCCESS){
|
||||
return s;
|
||||
}
|
||||
|
||||
if(pb->nInUse==0){
|
||||
free(pb->pTable);
|
||||
free(pb);
|
||||
ppi->pBucket = NULL;
|
||||
prb->nInUse--;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
ppi = &prb->pTable[id];
|
||||
if(ppi->pItem != pItem){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
prb->nInUse--;
|
||||
ppi->pItem = NULL;
|
||||
pi = *ppi;
|
||||
*ppi = pi->pItem;
|
||||
|
||||
/*
|
||||
* stuff it on the free list
|
||||
*/
|
||||
pi->pItem = prb->pFreeItems;
|
||||
prb->pFreeItems = pi;
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketLookupItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
void *bucketLookupItem(BUCKET *pb, BUCKETID id)
|
||||
#else
|
||||
void *bucketLookupItem(pb, id)
|
||||
BUCKET *pb;
|
||||
BUCKETID id;
|
||||
#endif
|
||||
void *bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
unsigned shift;
|
||||
return bucketLookupItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
void *bucketLookupItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
void *bucketLookupItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
LOCAL void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* create the hash index
|
||||
*/
|
||||
if(id&~pb->indexMask){
|
||||
return NULL;
|
||||
hashid = (*pBSET->pHash) (pb, pId);
|
||||
assert((hashid & ~pb->hashIdMask) == 0);
|
||||
|
||||
/*
|
||||
* at the bottom level just
|
||||
* linear search for it.
|
||||
*/
|
||||
ppi = (*pBSET->pCompare) (&pb->pTable[hashid], pId);
|
||||
if(ppi){
|
||||
return (*ppi)->pApp;
|
||||
}
|
||||
|
||||
while(shift = pb->indexShift){
|
||||
BUCKETID nextId;
|
||||
|
||||
nextId = id & pb->nextIndexMask;
|
||||
|
||||
pb = pb->pTable[id>>shift].pBucket;
|
||||
if(!pb){
|
||||
return pb;
|
||||
}
|
||||
id = nextId;
|
||||
}
|
||||
|
||||
return pb->pTable[id].pItem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,24 +550,62 @@ int bucketShow(pb)
|
||||
BUCKET *pb;
|
||||
#endif
|
||||
{
|
||||
ITEMPTR *pi;
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
ITEM *pni;
|
||||
unsigned nElem;
|
||||
double X;
|
||||
double XX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
unsigned count;
|
||||
unsigned maxEntries;
|
||||
unsigned freeListCount;
|
||||
|
||||
pi = pb->pTable;
|
||||
|
||||
printf( "Bucket: mask=%x entries in use=%d bytes in use=%d\n",
|
||||
(pb->nEntries-1)<<pb->indexShift,
|
||||
pb->nInUse,
|
||||
sizeof(*pb)+pb->nEntries*sizeof(*pi));
|
||||
|
||||
if(pb->indexShift){
|
||||
for( pi = pb->pTable;
|
||||
pi<&pb->pTable[pb->nEntries];
|
||||
pi++){
|
||||
if(pi->pBucket){
|
||||
bucketShow(pi->pBucket);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* count bytes on the free list
|
||||
*/
|
||||
pi = pb->pFreeItems;
|
||||
freeListCount = 0;
|
||||
while (pi) {
|
||||
freeListCount++;
|
||||
pni = pi->pItem;
|
||||
pi = pni;
|
||||
}
|
||||
|
||||
printf( "Bucket entries in use = %d bytes in use = %d\n",
|
||||
pb->nInUse,
|
||||
sizeof(*pb)+(pb->hashIdMask+1)*
|
||||
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM));
|
||||
|
||||
printf( "Free list bytes in use = %d\n",
|
||||
freeListCount*sizeof(ITEM));
|
||||
|
||||
ppi = pb->pTable;
|
||||
nElem = pb->hashIdMask+1;
|
||||
X = 0.0;
|
||||
XX = 0.0;
|
||||
maxEntries = 0;
|
||||
while (ppi < &pb->pTable[nElem]) {
|
||||
pi = *ppi;
|
||||
count = 0;
|
||||
while (pi) {
|
||||
count++;
|
||||
pi = pi->pItem;
|
||||
}
|
||||
X += count;
|
||||
XX += count*count;
|
||||
maxEntries = max (count, maxEntries);
|
||||
ppi++;
|
||||
}
|
||||
|
||||
mean = X/nElem;
|
||||
stdDev = sqrt(XX/nElem - mean*mean);
|
||||
printf( "Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
|
||||
mean,
|
||||
stdDev,
|
||||
maxEntries);
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+430
-239
@@ -29,12 +29,17 @@
|
||||
* -----------------
|
||||
* .01 091493 joh fixed overzealous parameter check
|
||||
* .02 121693 joh added bucketFree()
|
||||
*
|
||||
* NOTES:
|
||||
* .01 Storage for identifier must persist until an item is deleted
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <bucketLib.h>
|
||||
|
||||
@@ -48,142 +53,312 @@
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif /* FALSE */
|
||||
#ifndef LOCAL
|
||||
#define LOCAL static
|
||||
#endif /* LOCAL */
|
||||
#ifndef max
|
||||
#define max(A,B) ((A)>(B)?(A):(B))
|
||||
#endif /* max */
|
||||
|
||||
#define BUCKET_IX_WIDTH 12
|
||||
#define BUCKET_IX_N (1<<BUCKET_IX_WIDTH)
|
||||
#define BUCKET_IX_MASK (BUCKET_IX_N-1)
|
||||
/*
|
||||
* these data type dependent routines are
|
||||
* provided in the bucketLib.c
|
||||
*/
|
||||
typedef BUCKETID bucketHash(BUCKET *pb, const void *pId);
|
||||
typedef ITEM **bucketCompare(ITEM **ppi, const void *pId);
|
||||
|
||||
LOCAL bucketCompare bucketUnsignedCompare;
|
||||
LOCAL bucketCompare bucketPointerCompare;
|
||||
LOCAL bucketCompare bucketStringCompare;
|
||||
LOCAL bucketHash bucketUnsignedHash;
|
||||
LOCAL bucketHash bucketPointerHash;
|
||||
LOCAL bucketHash bucketStringHash;
|
||||
|
||||
typedef struct {
|
||||
bucketHash *pHash;
|
||||
bucketCompare *pCompare;
|
||||
buckTypeOfId type;
|
||||
}bucketSET;
|
||||
|
||||
LOCAL bucketSET BSET[] = {
|
||||
{bucketUnsignedHash, bucketUnsignedCompare, bidtUnsigned},
|
||||
{bucketPointerHash, bucketPointerCompare, bidtPointer},
|
||||
{bucketStringHash, bucketStringCompare, bidtString}
|
||||
};
|
||||
|
||||
LOCAL int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, void *pApp);
|
||||
LOCAL int bucketRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId);
|
||||
LOCAL void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucket id bit width
|
||||
*/
|
||||
#define BUCKETID_BIT_WIDTH (sizeof(BUCKETID)*NBBY)
|
||||
|
||||
/*
|
||||
* Maximum bucket size
|
||||
*/
|
||||
#define BUCKET_MAX_WIDTH 12
|
||||
|
||||
#ifdef DEBUG
|
||||
#error This is out of date
|
||||
main()
|
||||
{
|
||||
BUCKETID id;
|
||||
BUCKETID id1;
|
||||
BUCKETID id2;
|
||||
char *pValSave1;
|
||||
char *pValSave2;
|
||||
int s;
|
||||
BUCKET *pb;
|
||||
char *pValSave;
|
||||
char *pVal;
|
||||
unsigned i;
|
||||
clock_t start, finish;
|
||||
double duration;
|
||||
const int LOOPS = 500000;
|
||||
|
||||
pb = bucketCreate(NBBY*sizeof(BUCKETID));
|
||||
pb = bucketCreate(8);
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
id = 444;
|
||||
pValSave = "fred";
|
||||
s = bucketAddItem(pb, id, pValSave);
|
||||
if(s != BUCKET_SUCCESS){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
id1 = 0x1000a432;
|
||||
pValSave1 = "fred";
|
||||
s = bucketAddItemUnsignedId(pb, &id1, pValSave1);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
|
||||
printf("Begin\n");
|
||||
for(i=0; i<500000; i++){
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pVal = bucketLookupItem(pb, id);
|
||||
if(pVal != pValSave){
|
||||
printf("failure\n");
|
||||
break;
|
||||
}
|
||||
pValSave2 = "jane";
|
||||
s = bucketAddItemStringId(pb, pValSave2, pValSave2);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
|
||||
start = clock();
|
||||
for(i=0; i<LOOPS; i++){
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id1);
|
||||
assert(pVal == pValSave1);
|
||||
pVal = bucketLookupItem(pb, id2);
|
||||
assert(pVal == pValSave2);
|
||||
}
|
||||
printf("End\n");
|
||||
finish = clock();
|
||||
|
||||
duration = finish-start;
|
||||
duration = duration/CLOCKS_PER_SEC;
|
||||
printf("It took %15.10f total sec\n", duration);
|
||||
duration = duration/LOOPS;
|
||||
duration = duration/10;
|
||||
duration = duration * 1e6;
|
||||
printf("It took %15.10f u sec per hash lookup\n", duration);
|
||||
|
||||
bucketShow(pb);
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedCompare()
|
||||
*/
|
||||
LOCAL ITEM **bucketUnsignedCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
unsigned id;
|
||||
unsigned *pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
id = * (unsigned *) pId;
|
||||
while (pi = *ppi) {
|
||||
if (bidtUnsigned == pi->type) {
|
||||
pItemId = (unsigned *) pi->pId;
|
||||
if (id == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerCompare()
|
||||
*/
|
||||
ITEM **bucketPointerCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
void *ptr;
|
||||
void **pItemId;
|
||||
ITEM *pi;
|
||||
|
||||
ptr = * (void **) pId;
|
||||
while (pi = *ppi) {
|
||||
if (bidtPointer == pi->type ) {
|
||||
pItemId = (void **) pi->pId;
|
||||
if (ptr == *pItemId) {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringCompare ()
|
||||
*/
|
||||
ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
ITEM *pi;
|
||||
int status;
|
||||
|
||||
while (pi = *ppi) {
|
||||
if (bidtString == pi->type) {
|
||||
status = strcmp (pStr, (char *)pi->pId);
|
||||
if (status == '\0') {
|
||||
return ppi;
|
||||
}
|
||||
}
|
||||
ppi = &pi->pItem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketUnsignedHash ()
|
||||
*/
|
||||
BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const unsigned *pUId = pId;
|
||||
unsigned src;
|
||||
BUCKETID hashid;
|
||||
|
||||
src = *pUId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while (src) {
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketPointerHash ()
|
||||
*
|
||||
*/
|
||||
BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
void * const *ppId = pId;
|
||||
unsigned long src;
|
||||
BUCKETID hashid;
|
||||
|
||||
/*
|
||||
* This makes the assumption that
|
||||
* a pointer will fit inside of a long
|
||||
* (this assumption may not port to all
|
||||
* CPU architectures)
|
||||
*/
|
||||
src = (unsigned long) *ppId;
|
||||
hashid = src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
while(src){
|
||||
hashid = hashid ^ src;
|
||||
src = src >> pb->hashIdNBits;
|
||||
}
|
||||
hashid = hashid & pb->hashIdMask;
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bucketStringHash ()
|
||||
*/
|
||||
BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
|
||||
{
|
||||
const char *pStr = pId;
|
||||
BUCKETID hashid;
|
||||
unsigned i;
|
||||
|
||||
hashid = 0;
|
||||
i = 1;
|
||||
while(*pStr){
|
||||
hashid += *pStr * i;
|
||||
pStr++;
|
||||
i++;
|
||||
}
|
||||
|
||||
hashid = hashid % (pb->hashIdMask+1);
|
||||
|
||||
return hashid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketCreate()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
BUCKET *bucketCreate(unsigned indexWidth)
|
||||
#else
|
||||
BUCKET *bucketCreate(indexWidth)
|
||||
unsigned indexWidth;
|
||||
#endif
|
||||
BUCKET *bucketCreate (unsigned nHashTableEntries)
|
||||
{
|
||||
BUCKETID mask;
|
||||
unsigned nbits;
|
||||
BUCKET *pb;
|
||||
|
||||
if (nHashTableEntries==0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* count the number of bits in the bucket id
|
||||
*/
|
||||
for (nbits=0; nbits<BUCKETID_BIT_WIDTH; nbits++) {
|
||||
mask = (1<<nbits) - 1;
|
||||
if ( ((nHashTableEntries-1) & ~mask) == 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* indexWidth must be specified at least one
|
||||
* bit less than the bit size of type BUCKETID
|
||||
*/
|
||||
if(indexWidth>sizeof(BUCKETID)*NBBY){
|
||||
printf("%s at %d: Requested index width=%d is to large. max=%d\n" ,
|
||||
if (nbits>=BUCKETID_BIT_WIDTH) {
|
||||
printf("%s at %d: Requested index width=%d to large. max=%d\n",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
indexWidth,
|
||||
sizeof(BUCKETID)*NBBY-1);
|
||||
nbits,
|
||||
BUCKETID_BIT_WIDTH-1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pb = (BUCKET *) calloc(1, sizeof(*pb));
|
||||
if(!pb){
|
||||
if (!pb) {
|
||||
return pb;
|
||||
}
|
||||
|
||||
if(indexWidth>BUCKET_IX_WIDTH){
|
||||
pb->indexShift = indexWidth - BUCKET_IX_WIDTH;
|
||||
}
|
||||
else{
|
||||
pb->indexShift = 0;
|
||||
}
|
||||
pb->nextIndexMask = (1<<pb->indexShift)-1;
|
||||
pb->nEntries = 1<<(indexWidth-pb->indexShift);
|
||||
if(indexWidth == sizeof(BUCKETID)*NBBY){
|
||||
pb->indexMask = 0;
|
||||
pb->indexMask = ~pb->indexMask;
|
||||
}
|
||||
else{
|
||||
pb->indexMask = (1<<indexWidth)-1;
|
||||
}
|
||||
pb->hashIdMask = mask;
|
||||
pb->hashIdNBits = nbits;
|
||||
|
||||
pb->pTable = (ITEMPTR *) calloc(
|
||||
pb->nEntries,
|
||||
sizeof(ITEMPTR));
|
||||
pb->pTable = (ITEM **) calloc (mask+1, sizeof(*pb->pTable));
|
||||
if(!pb->pTable){
|
||||
free(pb);
|
||||
return NULL;
|
||||
@@ -202,14 +377,24 @@ int bucketFree(prb)
|
||||
BUCKET *prb;
|
||||
#endif
|
||||
{
|
||||
ITEM *pi;
|
||||
ITEM *pni;
|
||||
|
||||
/*
|
||||
* deleting a bucket with entries in use
|
||||
* will cause memory leaks and is not allowed
|
||||
*/
|
||||
if(prb->nInUse){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
assert(prb->nInUse==0);
|
||||
|
||||
/*
|
||||
* free the free list
|
||||
*/
|
||||
pi = prb->pFreeItems;
|
||||
while (pi) {
|
||||
pni = pi->pItem;
|
||||
free (pi);
|
||||
pi = pni;
|
||||
}
|
||||
free(prb->pTable);
|
||||
free(prb);
|
||||
|
||||
@@ -220,69 +405,49 @@ BUCKET *prb;
|
||||
/*
|
||||
* bucketAddItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int bucketAddItem(BUCKET *prb, BUCKETID id, void *pItem)
|
||||
#else
|
||||
int bucketAddItem(prb, id, pItem)
|
||||
BUCKET *prb;
|
||||
BUCKETID id;
|
||||
void *pItem;
|
||||
#endif
|
||||
int bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, void *pApp)
|
||||
{
|
||||
int s;
|
||||
ITEMPTR *pi;
|
||||
return bucketAddItem(prb, &BSET[bidtUnsigned], pId, pApp);
|
||||
}
|
||||
int bucketAddItemPointerId(BUCKET *prb, void * const *pId, void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtPointer], pId, pApp);
|
||||
}
|
||||
int bucketAddItemStringId(BUCKET *prb, const char *pId, void *pApp)
|
||||
{
|
||||
return bucketAddItem(prb, &BSET[bidtString], pId, pApp);
|
||||
}
|
||||
LOCAL int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, void *pApp)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM *pi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* try to get it off the free list first. If
|
||||
* that fails then malloc()
|
||||
*/
|
||||
if(id&~prb->indexMask){
|
||||
return BUCKET_FAILURE;
|
||||
pi = prb->pFreeItems;
|
||||
if (pi) {
|
||||
prb->pFreeItems = pi->pItem;
|
||||
}
|
||||
|
||||
if(prb->indexShift){
|
||||
int new;
|
||||
BUCKET *pb;
|
||||
|
||||
pi = &prb->pTable[id>>prb->indexShift];
|
||||
pb = pi->pBucket;
|
||||
|
||||
if(!pb){
|
||||
pb = bucketCreate(prb->indexShift);
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
pi->pBucket = pb;
|
||||
prb->nInUse++;
|
||||
new = TRUE;
|
||||
}
|
||||
else{
|
||||
new = FALSE;
|
||||
else {
|
||||
pi = (ITEM *) malloc(sizeof(ITEM));
|
||||
if(!pi){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
s = bucketAddItem(
|
||||
pb,
|
||||
id&prb->nextIndexMask,
|
||||
pItem);
|
||||
/*
|
||||
* if memory cant be allocated at a lower
|
||||
* level dont leak everything allocated for this new
|
||||
* item so far
|
||||
*/
|
||||
if(s != BUCKET_SUCCESS && new){
|
||||
s = bucketFree(pb);
|
||||
assert(s == BUCKET_SUCCESS);
|
||||
pi->pBucket = NULL;
|
||||
prb->nInUse--;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
pi = &prb->pTable[id];
|
||||
if(pi->pItem){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
pi->pItem = pItem;
|
||||
/*
|
||||
* create the hash index
|
||||
*/
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
pi->pApp = pApp;
|
||||
pi->pId = pId;
|
||||
pi->type = pBSET->type;
|
||||
assert((hashid & ~prb->hashIdMask) == 0);
|
||||
pi->pItem = prb->pTable[hashid];
|
||||
prb->pTable[hashid] = pi;
|
||||
prb->nInUse++;
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
@@ -292,97 +457,85 @@ void *pItem;
|
||||
/*
|
||||
* bucketRemoveItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int bucketRemoveItem (BUCKET *prb, BUCKETID id, void *pItem)
|
||||
#else
|
||||
int bucketRemoveItem (prb, id, pItem)
|
||||
BUCKET *prb;
|
||||
BUCKETID id;
|
||||
void *pItem;
|
||||
#endif
|
||||
int bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
ITEMPTR *ppi;
|
||||
return bucketRemoveItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
int bucketRemoveItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketRemoveItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
int bucketRemoveItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketRemoveItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
LOCAL int bucketRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* create the hash index
|
||||
*/
|
||||
if(id&~prb->indexMask){
|
||||
hashid = (*pBSET->pHash) (prb, pId);
|
||||
|
||||
assert((hashid & ~prb->hashIdMask) == 0);
|
||||
ppi = &prb->pTable[hashid];
|
||||
ppi = (*pBSET->pCompare) (ppi, pId);
|
||||
if(!ppi){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
if(prb->indexShift){
|
||||
BUCKET *pb;
|
||||
int s;
|
||||
|
||||
ppi = &prb->pTable[id>>prb->indexShift];
|
||||
pb = ppi->pBucket;
|
||||
|
||||
if(!pb){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
s = bucketRemoveItem(
|
||||
pb,
|
||||
id&prb->nextIndexMask,
|
||||
pItem);
|
||||
if(s!=BUCKET_SUCCESS){
|
||||
return s;
|
||||
}
|
||||
|
||||
if(pb->nInUse==0){
|
||||
free(pb->pTable);
|
||||
free(pb);
|
||||
ppi->pBucket = NULL;
|
||||
prb->nInUse--;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
ppi = &prb->pTable[id];
|
||||
if(ppi->pItem != pItem){
|
||||
return BUCKET_FAILURE;
|
||||
}
|
||||
|
||||
prb->nInUse--;
|
||||
ppi->pItem = NULL;
|
||||
pi = *ppi;
|
||||
*ppi = pi->pItem;
|
||||
|
||||
/*
|
||||
* stuff it on the free list
|
||||
*/
|
||||
pi->pItem = prb->pFreeItems;
|
||||
prb->pFreeItems = pi;
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* bucketLookupItem()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
void *bucketLookupItem(BUCKET *pb, BUCKETID id)
|
||||
#else
|
||||
void *bucketLookupItem(pb, id)
|
||||
BUCKET *pb;
|
||||
BUCKETID id;
|
||||
#endif
|
||||
void *bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId)
|
||||
{
|
||||
unsigned shift;
|
||||
return bucketLookupItem(prb, &BSET[bidtUnsigned], pId);
|
||||
}
|
||||
void *bucketLookupItemPointerId (BUCKET *prb, void * const *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtPointer], pId);
|
||||
}
|
||||
void *bucketLookupItemStringId (BUCKET *prb, const char *pId)
|
||||
{
|
||||
return bucketLookupItem(prb, &BSET[bidtString], pId);
|
||||
}
|
||||
LOCAL void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId)
|
||||
{
|
||||
BUCKETID hashid;
|
||||
ITEM **ppi;
|
||||
|
||||
/*
|
||||
* is the id to big ?
|
||||
* create the hash index
|
||||
*/
|
||||
if(id&~pb->indexMask){
|
||||
return NULL;
|
||||
hashid = (*pBSET->pHash) (pb, pId);
|
||||
assert((hashid & ~pb->hashIdMask) == 0);
|
||||
|
||||
/*
|
||||
* at the bottom level just
|
||||
* linear search for it.
|
||||
*/
|
||||
ppi = (*pBSET->pCompare) (&pb->pTable[hashid], pId);
|
||||
if(ppi){
|
||||
return (*ppi)->pApp;
|
||||
}
|
||||
|
||||
while(shift = pb->indexShift){
|
||||
BUCKETID nextId;
|
||||
|
||||
nextId = id & pb->nextIndexMask;
|
||||
|
||||
pb = pb->pTable[id>>shift].pBucket;
|
||||
if(!pb){
|
||||
return pb;
|
||||
}
|
||||
id = nextId;
|
||||
}
|
||||
|
||||
return pb->pTable[id].pItem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,24 +550,62 @@ int bucketShow(pb)
|
||||
BUCKET *pb;
|
||||
#endif
|
||||
{
|
||||
ITEMPTR *pi;
|
||||
ITEM **ppi;
|
||||
ITEM *pi;
|
||||
ITEM *pni;
|
||||
unsigned nElem;
|
||||
double X;
|
||||
double XX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
unsigned count;
|
||||
unsigned maxEntries;
|
||||
unsigned freeListCount;
|
||||
|
||||
pi = pb->pTable;
|
||||
|
||||
printf( "Bucket: mask=%x entries in use=%d bytes in use=%d\n",
|
||||
(pb->nEntries-1)<<pb->indexShift,
|
||||
pb->nInUse,
|
||||
sizeof(*pb)+pb->nEntries*sizeof(*pi));
|
||||
|
||||
if(pb->indexShift){
|
||||
for( pi = pb->pTable;
|
||||
pi<&pb->pTable[pb->nEntries];
|
||||
pi++){
|
||||
if(pi->pBucket){
|
||||
bucketShow(pi->pBucket);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* count bytes on the free list
|
||||
*/
|
||||
pi = pb->pFreeItems;
|
||||
freeListCount = 0;
|
||||
while (pi) {
|
||||
freeListCount++;
|
||||
pni = pi->pItem;
|
||||
pi = pni;
|
||||
}
|
||||
|
||||
printf( "Bucket entries in use = %d bytes in use = %d\n",
|
||||
pb->nInUse,
|
||||
sizeof(*pb)+(pb->hashIdMask+1)*
|
||||
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM));
|
||||
|
||||
printf( "Free list bytes in use = %d\n",
|
||||
freeListCount*sizeof(ITEM));
|
||||
|
||||
ppi = pb->pTable;
|
||||
nElem = pb->hashIdMask+1;
|
||||
X = 0.0;
|
||||
XX = 0.0;
|
||||
maxEntries = 0;
|
||||
while (ppi < &pb->pTable[nElem]) {
|
||||
pi = *ppi;
|
||||
count = 0;
|
||||
while (pi) {
|
||||
count++;
|
||||
pi = pi->pItem;
|
||||
}
|
||||
X += count;
|
||||
XX += count*count;
|
||||
maxEntries = max (count, maxEntries);
|
||||
ppi++;
|
||||
}
|
||||
|
||||
mean = X/nElem;
|
||||
stdDev = sqrt(XX/nElem - mean*mean);
|
||||
printf( "Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
|
||||
mean,
|
||||
stdDev,
|
||||
maxEntries);
|
||||
|
||||
return BUCKET_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+175
-224
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
* share/src/libCom/%W% %G%
|
||||
*
|
||||
* A file descriptor manager for use with the UNIX system call select
|
||||
*
|
||||
@@ -62,7 +62,6 @@
|
||||
* if we are in fdmgr_pend_event()
|
||||
* .15 joh 011993 Created fdmgr header file
|
||||
* .16 joh 011993 Converted to ANSI C
|
||||
* .17 pg 050494 HPUX cpp changes (elif converted to else & if)
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
@@ -90,12 +89,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static char *pSccsId = "$Id$";
|
||||
static char *pSccsId = "%W%\t%G%";
|
||||
|
||||
/*
|
||||
* ANSI
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <taskLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <tickLib.h>
|
||||
#include <logLib.h>
|
||||
#include <selectLib.h>
|
||||
#endif
|
||||
|
||||
#include <fdmgr.h>
|
||||
#ifdef vxWorks
|
||||
#include <taskLib.h>
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
@@ -113,6 +126,10 @@ static char *pSccsId = "$Id$";
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef LOCAL
|
||||
#define LOCAL static
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(x, y) (((x) < (y)) ? (y) : (x))
|
||||
#endif
|
||||
@@ -130,9 +147,6 @@ typedef struct{
|
||||
#if defined(vxWorks)
|
||||
# define LOCK(PFDCTX) FASTLOCK(&(PFDCTX)->lock)
|
||||
# define UNLOCK(PFDCTX) FASTUNLOCK(&(PFDCTX)->lock)
|
||||
# define LOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
FASTLOCK(&(PFDCTX)->fdmgr_pend_event_lock) \
|
||||
(PFDCTX)->fdmgr_pend_event_tid = taskIdCurrent
|
||||
# define UNLOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
FASTUNLOCK(&(PFDCTX)->fdmgr_pend_event_lock) \
|
||||
(PFDCTX)->fdmgr_pend_event_tid = NULL;
|
||||
@@ -144,109 +158,55 @@ typedef struct{
|
||||
FASTLOCK(&(PFDCTX)->fd_handler_lock)
|
||||
# define UNLOCK_FD_HANDLER(PFDCTX) \
|
||||
FASTUNLOCK(&(PFDCTX)->fd_handler_lock)
|
||||
# define printf logMsg
|
||||
# define fdmgr_gettimeval fdmgr_vxWorks_gettimeval
|
||||
# define memset(D,V,N) bfill(D,N,V)
|
||||
#else
|
||||
#if defined(UNIX)
|
||||
#elif defined(UNIX) || defined(VMS) || defined(_WIN32)
|
||||
# define LOCK(PFDCTX)
|
||||
# define UNLOCK(PFDCTX)
|
||||
# define LOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
{ \
|
||||
if((PFDCTX)->fdmgr_pend_event_in_use){ \
|
||||
printf("Double invocation of fdmgr_pend_event()\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
(PFDCTX)->fdmgr_pend_event_in_use++; \
|
||||
}
|
||||
# define UNLOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
{(PFDCTX)->fdmgr_pend_event_in_use--;}
|
||||
# define fdmgr_gettimeval fdmgr_UNIX_gettimeval
|
||||
# define LOCK_EXPIRED(PFDCTX)
|
||||
# define UNLOCK_EXPIRED(PFDCTX)
|
||||
# define LOCK_FD_HANDLER(PFDCTX)
|
||||
# define UNLOCK_FD_HANDLER(PFDCTX)
|
||||
#else
|
||||
#if defined(VMS)
|
||||
# define LOCK(PFDCTX)
|
||||
# define UNLOCK(PFDCTX)
|
||||
# define LOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
{ \
|
||||
if((PFDCTX)->fdmgr_pend_event_in_use){ \
|
||||
printf("Double invocation of fdmgr_pend_event()\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
(PFDCTX)->fdmgr_pend_event_in_use++; \
|
||||
}
|
||||
# define UNLOCK_FDMGR_PEND_EVENT(PFDCTX) \
|
||||
{(PFDCTX)->fdmgr_pend_event_in_use--;}
|
||||
# define fdmgr_gettimeval fdmgr_VMS_gettimeval
|
||||
# define LOCK_EXPIRED(PFDCTX)
|
||||
# define UNLOCK_EXPIRED(PFDCTX)
|
||||
# define LOCK_FD_HANDLER(PFDCTX)
|
||||
# define UNLOCK_FD_HANDLER(PFDCTX)
|
||||
#else
|
||||
@@@@ dont compile in this case @@@@
|
||||
#endif
|
||||
#endif
|
||||
#error Please define the host OS type
|
||||
#endif
|
||||
|
||||
|
||||
#define USEC_PER_SEC 1000000
|
||||
|
||||
#ifdef __STDC__
|
||||
#define printf @@@@ Please dont use printf in this source @@@@
|
||||
LOCAL int fdmgrPrintf(char *pformat, ...);
|
||||
|
||||
static int fdmgr_vxWorks_gettimeval(
|
||||
LOCAL int fdmgr_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
);
|
||||
|
||||
static int fdmgr_UNIX_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
);
|
||||
|
||||
static void select_alarm(
|
||||
LOCAL void select_alarm(
|
||||
fdctx *pfdctx
|
||||
);
|
||||
|
||||
|
||||
static int fdmgr_select(
|
||||
LOCAL int fdmgr_select(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *ptimeout
|
||||
);
|
||||
|
||||
static void fdmgr_finish_off_fdentry(
|
||||
LOCAL void fdmgr_finish_off_fdentry(
|
||||
fdctx *pfdctx,
|
||||
register fdentry *pfdentry
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
static int fdmgr_vxWorks_gettimeval();
|
||||
static int fdmgr_UNIX_gettimeval();
|
||||
static void select_alarm();
|
||||
static int fdmgr_select();
|
||||
static void fdmgr_finish_off_fdentry();
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(vxWorks)
|
||||
# define abort(A) taskSuspend(taskIdSelf())
|
||||
#endif
|
||||
LOCAL void lockFDMGRPendEvent (fdctx *pfdctx);
|
||||
|
||||
/*
|
||||
* This routine is to be only called from fdmgr_pend_event()
|
||||
* If other uses are needed then locking issues must be
|
||||
* reinvestigated
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static void process_alarm_queue(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *poffset
|
||||
);
|
||||
#else
|
||||
static void process_alarm_queue();
|
||||
#endif
|
||||
LOCAL void process_alarm_queue(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *poffset
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
@@ -254,11 +214,7 @@ static void fdmgr_finish_off_fdentry();
|
||||
* fdmgr_init()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
fdctx *fdmgr_init(void)
|
||||
#else
|
||||
fdctx *fdmgr_init()
|
||||
#endif
|
||||
{
|
||||
fdctx *pfdctx;
|
||||
|
||||
@@ -284,29 +240,41 @@ fdctx *fdmgr_init()
|
||||
return pfdctx;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* fdmgr_delete()
|
||||
*
|
||||
*/
|
||||
int fdmgr_delete(fdctx *pfdctx)
|
||||
{
|
||||
if(!pfdctx){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
# if defined(vxWorks)
|
||||
FASTLOCKFREE(&pfdctx->lock);
|
||||
FASTLOCKFREE(&pfdctx->fdmgr_pend_event_lock);
|
||||
FASTLOCKFREE(&pfdctx->expired_alarm_lock);
|
||||
FASTLOCKFREE(&pfdctx->fd_handler_lock);
|
||||
# endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fdmgr_add_timeout()
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
alarm *fdmgr_add_timeout(
|
||||
fdmgrAlarm *fdmgr_add_timeout(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *ptimeout,
|
||||
void (*func)(),
|
||||
void *param
|
||||
)
|
||||
#else
|
||||
alarm *fdmgr_add_timeout(pfdctx,ptimeout,func,param)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *ptimeout;
|
||||
void (*func)();
|
||||
void *param;
|
||||
#endif
|
||||
{
|
||||
alarm *palarm=NULL;
|
||||
alarm *pa;
|
||||
fdmgrAlarm *palarm=NULL;
|
||||
fdmgrAlarm *pa;
|
||||
struct timeval t;
|
||||
int status;
|
||||
|
||||
@@ -320,10 +288,10 @@ void *param;
|
||||
return NULL;
|
||||
|
||||
LOCK(pfdctx);
|
||||
palarm = (alarm *) ellGet(&pfdctx->free_alarm_list);
|
||||
palarm = (fdmgrAlarm *) ellGet(&pfdctx->free_alarm_list);
|
||||
UNLOCK(pfdctx);
|
||||
if(!palarm){
|
||||
palarm = (alarm *) malloc(sizeof(alarm));
|
||||
palarm = (fdmgrAlarm *) malloc(sizeof(fdmgrAlarm));
|
||||
if(!palarm){
|
||||
return NULL;
|
||||
}
|
||||
@@ -332,7 +300,7 @@ void *param;
|
||||
/*
|
||||
* force all fields to a known state
|
||||
*/
|
||||
memset(palarm, 0, sizeof(*palarm));
|
||||
memset((char *)palarm, 0, sizeof(*palarm));
|
||||
|
||||
ptimeout->tv_sec += ptimeout->tv_usec/USEC_PER_SEC;
|
||||
ptimeout->tv_usec = ptimeout->tv_usec%USEC_PER_SEC;
|
||||
@@ -347,9 +315,9 @@ void *param;
|
||||
palarm->t.tv_usec = (t.tv_usec + ptimeout->tv_usec)%USEC_PER_SEC;
|
||||
|
||||
LOCK(pfdctx);
|
||||
for( pa=(alarm *)pfdctx->alarm_list.node.next;
|
||||
for( pa=(fdmgrAlarm *)pfdctx->alarm_list.node.next;
|
||||
pa;
|
||||
pa=(alarm *)pa->node.next){
|
||||
pa=(fdmgrAlarm *)pa->node.next){
|
||||
if(pa->t.tv_sec > palarm->t.tv_sec){
|
||||
break;
|
||||
}
|
||||
@@ -379,16 +347,10 @@ void *param;
|
||||
* fdmgr_clear_timeout()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int fdmgr_clear_timeout(
|
||||
fdctx *pfdctx,
|
||||
alarm *palarm
|
||||
fdmgrAlarm *palarm
|
||||
)
|
||||
#else
|
||||
int fdmgr_clear_timeout(pfdctx, palarm)
|
||||
fdctx *pfdctx;
|
||||
alarm *palarm;
|
||||
#endif
|
||||
{
|
||||
int status;
|
||||
enum alarm_list_type alt;
|
||||
@@ -458,20 +420,12 @@ alarm *palarm;
|
||||
* this rouitine is supplied solely for compatibility
|
||||
* with earlier versions of this software
|
||||
*/
|
||||
#if __STDC__
|
||||
int fdmgr_add_fd(
|
||||
fdctx *pfdctx,
|
||||
int fd,
|
||||
void (*pfunc)(),
|
||||
void *param
|
||||
)
|
||||
#else
|
||||
int fdmgr_add_fd(pfdctx,fd,pfunc,param)
|
||||
fdctx *pfdctx;
|
||||
int fd;
|
||||
void (*pfunc)();
|
||||
void *param;
|
||||
#endif
|
||||
{
|
||||
int status;
|
||||
|
||||
@@ -491,7 +445,6 @@ void *param;
|
||||
* fdmgr_add_fd_callback()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int fdmgr_add_callback(
|
||||
fdctx *pfdctx,
|
||||
int fd,
|
||||
@@ -499,14 +452,6 @@ enum fdi_type fdi,
|
||||
void (*pfunc)(),
|
||||
void *param
|
||||
)
|
||||
#else
|
||||
int fdmgr_add_callback(pfdctx,fd,fdi,pfunc,param)
|
||||
fdctx *pfdctx;
|
||||
int fd;
|
||||
enum fdi_type fdi;
|
||||
void (*pfunc)();
|
||||
void *param;
|
||||
#endif
|
||||
{
|
||||
fdentry *pfdentry;
|
||||
fd_set *pfds;
|
||||
@@ -540,7 +485,7 @@ void *param;
|
||||
/*
|
||||
* force all fields to a known state
|
||||
*/
|
||||
memset(pfdentry, 0, sizeof(*pfdentry));
|
||||
memset((char *)pfdentry, 0, sizeof(*pfdentry));
|
||||
|
||||
pfdentry->fd = fd;
|
||||
pfdentry->fdi = fdi;
|
||||
@@ -564,16 +509,10 @@ void *param;
|
||||
* included solely for compatibility with previous release
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int fdmgr_clear_fd(
|
||||
fdctx *pfdctx,
|
||||
int fd
|
||||
)
|
||||
#else
|
||||
int fdmgr_clear_fd(pfdctx,fd)
|
||||
fdctx *pfdctx;
|
||||
int fd;
|
||||
#endif
|
||||
{
|
||||
return fdmgr_clear_callback(pfdctx, fd, fdi_read);
|
||||
}
|
||||
@@ -584,18 +523,11 @@ int fd;
|
||||
* fdmgr_clear_callback()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int fdmgr_clear_callback(
|
||||
fdctx *pfdctx,
|
||||
int fd,
|
||||
enum fdi_type fdi
|
||||
)
|
||||
#else
|
||||
int fdmgr_clear_callback(pfdctx,fd,fdi)
|
||||
fdctx *pfdctx;
|
||||
int fd;
|
||||
enum fdi_type fdi;
|
||||
#endif
|
||||
{
|
||||
register fdentry *pfdentry;
|
||||
int status;
|
||||
@@ -641,6 +573,7 @@ enum fdi_type fdi;
|
||||
*/
|
||||
# ifdef vxWorks
|
||||
if(delete_pending == TRUE){
|
||||
@@@@ review all of this delete pending stuff
|
||||
LOCK_FD_HANDLER(pfdctx);
|
||||
UNLOCK_FD_HANDLER(pfdctx);
|
||||
}
|
||||
@@ -650,7 +583,7 @@ enum fdi_type fdi;
|
||||
* If it is an ukn fd its a problem worth printing out
|
||||
*/
|
||||
if(status != OK){
|
||||
printf("fdmg: delete of ukn fd failed\n");
|
||||
fdmgrPrintf("fdmg: delete of ukn fd failed\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -664,16 +597,10 @@ enum fdi_type fdi;
|
||||
* !! LOCK(pfdctx) must be applied !!
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static void fdmgr_finish_off_fdentry(
|
||||
LOCAL void fdmgr_finish_off_fdentry(
|
||||
fdctx *pfdctx,
|
||||
register fdentry *pfdentry
|
||||
)
|
||||
#else
|
||||
static void fdmgr_finish_off_fdentry(pfdctx,pfdentry)
|
||||
fdctx *pfdctx;
|
||||
register fdentry *pfdentry;
|
||||
#endif
|
||||
{
|
||||
FD_CLR(pfdentry->fd, pfdentry->pfds);
|
||||
ellAdd(&pfdctx->fdentry_free_list, (ELLNODE*)pfdentry);
|
||||
@@ -685,24 +612,18 @@ register fdentry *pfdentry;
|
||||
* fdmgr_pend_event()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int fdmgr_pend_event(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *ptimeout
|
||||
)
|
||||
#else
|
||||
int fdmgr_pend_event(pfdctx,ptimeout)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *ptimeout;
|
||||
#endif
|
||||
{
|
||||
int status;
|
||||
extern errno;
|
||||
struct timeval t;
|
||||
alarm *palarm;
|
||||
fdmgrAlarm *palarm;
|
||||
|
||||
|
||||
LOCK_FDMGR_PEND_EVENT(pfdctx);
|
||||
lockFDMGRPendEvent(pfdctx);
|
||||
|
||||
/*
|
||||
* If its a poll dont add a timeout
|
||||
@@ -757,21 +678,14 @@ struct timeval *ptimeout;
|
||||
* returns TRUE if any labor was performed, otherwise FALSE
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static int fdmgr_select(
|
||||
LOCAL int fdmgr_select(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *ptimeout
|
||||
)
|
||||
#else
|
||||
static int fdmgr_select(pfdctx,ptimeout)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *ptimeout;
|
||||
#endif
|
||||
{
|
||||
register fdentry *pfdentry;
|
||||
int labor_performed;
|
||||
int status;
|
||||
int s;
|
||||
|
||||
labor_performed = FALSE;
|
||||
|
||||
@@ -790,8 +704,8 @@ struct timeval *ptimeout;
|
||||
* it is in select() so I am turning
|
||||
* on task delete disable to be safe
|
||||
*/
|
||||
# ifdef vxWorks
|
||||
TASK_SAFE();
|
||||
# ifdef vxWorks
|
||||
taskSafe();
|
||||
# endif
|
||||
status = select(
|
||||
pfdctx->maxfd,
|
||||
@@ -799,8 +713,8 @@ struct timeval *ptimeout;
|
||||
&pfdctx->writech,
|
||||
&pfdctx->excpch,
|
||||
ptimeout);
|
||||
# ifdef vxWorks
|
||||
TASK_UNSAFE();
|
||||
# ifdef vxWorks
|
||||
taskUnsafe();
|
||||
# endif
|
||||
if(status == 0){
|
||||
return labor_performed;
|
||||
@@ -809,12 +723,14 @@ struct timeval *ptimeout;
|
||||
if(errno == EINTR)
|
||||
;
|
||||
else if(errno == EINVAL)
|
||||
printf( "fdmgr: bad select args ? %d %d %d\n",
|
||||
fdmgrPrintf(
|
||||
"fdmgr: bad select args ? %d %d %d\n",
|
||||
pfdctx->maxfd,
|
||||
ptimeout->tv_sec,
|
||||
ptimeout->tv_usec);
|
||||
else
|
||||
printf( "fdmgr: error from select %d\n",
|
||||
fdmgrPrintf(
|
||||
"fdmgr: error from select %d\n",
|
||||
errno);
|
||||
|
||||
return labor_performed;
|
||||
@@ -822,7 +738,6 @@ struct timeval *ptimeout;
|
||||
|
||||
pfdentry = (fdentry *) &pfdctx->fdentry_list.node;
|
||||
while(TRUE){
|
||||
void *pfunc;
|
||||
|
||||
LOCK(pfdctx)
|
||||
pfdentry = (fdentry *) pfdentry->node.next;
|
||||
@@ -896,36 +811,28 @@ struct timeval *ptimeout;
|
||||
* only to be called by fdmgr_pend_event(). If other uses
|
||||
* come up then the locking must be revisited
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static void process_alarm_queue(
|
||||
LOCAL void process_alarm_queue(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *poffset
|
||||
)
|
||||
#else
|
||||
static void process_alarm_queue(pfdctx,poffset)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *poffset;
|
||||
#endif
|
||||
{
|
||||
struct timeval t;
|
||||
int status;
|
||||
alarm *pa;
|
||||
alarm *nextpa;
|
||||
fdmgrAlarm *pa;
|
||||
fdmgrAlarm *nextpa;
|
||||
|
||||
status = fdmgr_gettimeval(pfdctx, &t);
|
||||
if(status < 0){
|
||||
abort();
|
||||
}
|
||||
assert (status >= 0);
|
||||
|
||||
LOCK(pfdctx);
|
||||
for(pa = (alarm*)pfdctx->alarm_list.node.next; pa; pa = nextpa){
|
||||
for(pa = (fdmgrAlarm*)pfdctx->alarm_list.node.next; pa; pa = nextpa){
|
||||
if(pa->t.tv_sec > t.tv_sec)
|
||||
break;
|
||||
else if(pa->t.tv_sec == t.tv_sec)
|
||||
if(pa->t.tv_usec > t.tv_usec)
|
||||
break;
|
||||
|
||||
nextpa = (alarm*)pa->node.next;
|
||||
nextpa = (fdmgrAlarm*)pa->node.next;
|
||||
ellDelete(&pfdctx->alarm_list, (ELLNODE*)pa);
|
||||
ellAdd(&pfdctx->expired_alarm_list, (ELLNODE*)pa);
|
||||
pa->alt = alt_expired;
|
||||
@@ -954,7 +861,7 @@ struct timeval *poffset;
|
||||
* on multithreaded OS
|
||||
*/
|
||||
LOCK_EXPIRED(pfdctx);
|
||||
pa = (alarm*) pfdctx->expired_alarm_list.node.next;
|
||||
pa = (fdmgrAlarm*) pfdctx->expired_alarm_list.node.next;
|
||||
while(pa){
|
||||
void (*pfunc)();
|
||||
|
||||
@@ -966,7 +873,7 @@ struct timeval *poffset;
|
||||
if(pfunc){
|
||||
(*pfunc)(pa->param);
|
||||
}
|
||||
pa = (alarm*)pa->node.next;
|
||||
pa = (fdmgrAlarm*)pa->node.next;
|
||||
}
|
||||
UNLOCK_EXPIRED(pfdctx);
|
||||
|
||||
@@ -976,14 +883,14 @@ struct timeval *poffset;
|
||||
* expired list onto the free list
|
||||
*/
|
||||
LOCK(pfdctx);
|
||||
pa = (alarm*) pfdctx->expired_alarm_list.node.next;
|
||||
pa = (fdmgrAlarm*) pfdctx->expired_alarm_list.node.next;
|
||||
while(pa){
|
||||
pa->alt = alt_free;
|
||||
pa = (alarm *) pa->node.next;
|
||||
pa = (fdmgrAlarm *) pa->node.next;
|
||||
}
|
||||
ellConcat(&pfdctx->free_alarm_list, &pfdctx->expired_alarm_list);
|
||||
|
||||
pa = (alarm *)pfdctx->alarm_list.node.next;
|
||||
pa = (fdmgrAlarm *)pfdctx->alarm_list.node.next;
|
||||
if(pa){
|
||||
if(pa->t.tv_usec >= t.tv_usec){
|
||||
poffset->tv_sec = pa->t.tv_sec - t.tv_sec;
|
||||
@@ -1007,14 +914,9 @@ struct timeval *poffset;
|
||||
* select_alarm()
|
||||
*
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
static void select_alarm(
|
||||
LOCAL void select_alarm(
|
||||
fdctx *pfdctx
|
||||
)
|
||||
#else
|
||||
static void select_alarm(pfdctx)
|
||||
fdctx *pfdctx;
|
||||
#endif
|
||||
{
|
||||
pfdctx->select_tmo = TRUE;
|
||||
}
|
||||
@@ -1024,21 +926,15 @@ fdctx *pfdctx;
|
||||
|
||||
/*
|
||||
*
|
||||
* fdmgr_UNIX_gettimeval
|
||||
*
|
||||
* UNIX & VMS
|
||||
* fdmgr_gettimeval
|
||||
*
|
||||
*/
|
||||
#ifdef UNIX
|
||||
#ifdef __STDC__
|
||||
static int fdmgr_UNIX_gettimeval(
|
||||
#if defined(UNIX) || defined(VMS)
|
||||
LOCAL int fdmgr_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
)
|
||||
#else
|
||||
static int fdmgr_UNIX_gettimeval(pfdctx,pt)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *pt;
|
||||
#endif
|
||||
{
|
||||
struct timezone tz;
|
||||
|
||||
@@ -1049,46 +945,38 @@ struct timeval *pt;
|
||||
|
||||
/*
|
||||
*
|
||||
* fdmgr_VMS_gettimeval
|
||||
* WIN32
|
||||
* fdmgr_gettimeval
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifdef VMS
|
||||
#ifdef __STDC__
|
||||
static int fdmgr_VMS_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
#ifdef _WIN32
|
||||
LOCAL int fdmgr_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
)
|
||||
#else
|
||||
static int fdmgr_VMS_gettimeval(pfdctx,pt)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *pt;
|
||||
#endif
|
||||
{
|
||||
struct timezone tz;
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
pt->tv_sec = (long)st.wSecond + (long)st.wMinute*60 + (long)st.wHour*360
|
||||
0;
|
||||
pt->tv_usec = st.wMilliseconds*1000;
|
||||
|
||||
return gettimeofday(pt, &tz);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* fdmgr_vxWorks_gettimeval
|
||||
*
|
||||
* vxWorks
|
||||
* fdmgr_gettimeval
|
||||
*
|
||||
*/
|
||||
#ifdef vxWorks
|
||||
#ifdef __STDC__
|
||||
static int fdmgr_vxWorks_gettimeval(
|
||||
LOCAL int fdmgr_gettimeval(
|
||||
fdctx *pfdctx,
|
||||
struct timeval *pt
|
||||
)
|
||||
#else
|
||||
static int fdmgr_vxWorks_gettimeval(pfdctx,pt)
|
||||
fdctx *pfdctx;
|
||||
struct timeval *pt;
|
||||
#endif
|
||||
{
|
||||
unsigned long current;
|
||||
|
||||
@@ -1108,3 +996,66 @@ struct timeval *pt;
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* lockFDMGRPendEvent()
|
||||
*/
|
||||
LOCAL void lockFDMGRPendEvent (fdctx *pfdctx)
|
||||
{
|
||||
# if defined(vxWorks)
|
||||
FASTLOCK(&pfdctx->fdmgr_pend_event_lock);
|
||||
pfdctx->fdmgr_pend_event_tid = taskIdCurrent;
|
||||
# else
|
||||
assert (pfdctx->fdmgr_pend_event_in_use==0);
|
||||
pfdctx->fdmgr_pend_event_in_use++;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* fdmgrPrintf()
|
||||
*
|
||||
* Dump error messages to the appropriate place
|
||||
*
|
||||
*/
|
||||
LOCAL int fdmgrPrintf(char *pformat, ...)
|
||||
{
|
||||
va_list args;
|
||||
int status;
|
||||
|
||||
va_start(args, pformat);
|
||||
|
||||
#ifndef vxWorks
|
||||
status = vfprintf(
|
||||
stderr,
|
||||
pformat,
|
||||
args);
|
||||
#else /*vxWorks*/
|
||||
{
|
||||
int logMsgArgs[6];
|
||||
int i;
|
||||
|
||||
for(i=0; i< NELEMENTS(logMsgArgs); i++){
|
||||
logMsgArgs[i] = va_arg(args, int);
|
||||
}
|
||||
|
||||
status = logMsg(
|
||||
pformat,
|
||||
logMsgArgs[0],
|
||||
logMsgArgs[1],
|
||||
logMsgArgs[2],
|
||||
logMsgArgs[3],
|
||||
logMsgArgs[4],
|
||||
logMsgArgs[5]);
|
||||
|
||||
}
|
||||
#endif /*vxWorks*/
|
||||
|
||||
va_end(args);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user