Reworked various hash tables, using the faster epicsStrHash() routines;
added per-bucket locks to the PV Directory, needed for run-time alias creation; speed up gpHash lookups; improved the output of both Dump routines.
This commit is contained in:
@@ -126,12 +126,14 @@ epicsShareExtern int asActive;
|
||||
/* definition of access rights*/
|
||||
typedef enum{asNOACCESS,asREAD,asWRITE} asAccessRights;
|
||||
|
||||
struct gphPvt;
|
||||
|
||||
/*Base pointers for access security*/
|
||||
typedef struct asBase{
|
||||
ELLLIST uagList;
|
||||
ELLLIST hagList;
|
||||
ELLLIST asgList;
|
||||
void *phash;
|
||||
struct gphPvt *phash;
|
||||
} ASBASE;
|
||||
|
||||
epicsShareExtern volatile ASBASE *pasbase;
|
||||
|
||||
@@ -113,7 +113,7 @@ long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction)
|
||||
pasg->pavalue = asCalloc(CALCPERFORM_NARGS, sizeof(double));
|
||||
pasg = (ASG *)ellNext((ELLNODE *)pasg);
|
||||
}
|
||||
gphInitPvt(&((ASBASE *)pasbasenew)->phash,256);
|
||||
gphInitPvt(&pasbasenew->phash, 256);
|
||||
/*Hash each uagname and each hagname*/
|
||||
puag = (UAG *)ellFirst(&pasbasenew->uagList);
|
||||
while(puag) {
|
||||
|
||||
@@ -140,7 +140,7 @@ typedef struct dbRecordType {
|
||||
short no_fields; /* number of fields defined */
|
||||
short no_prompt; /* number of fields to configure*/
|
||||
short no_links; /* number of links */
|
||||
short no_aliases;
|
||||
short no_aliases; /* number of aliases in recList */
|
||||
short *link_ind; /* addr of array of ind in papFldDes*/
|
||||
char **papsortFldName;/* ptr to array of ptr to fld names*/
|
||||
short *sortFldInd; /* addr of array of ind in papFldDes*/
|
||||
@@ -152,6 +152,9 @@ typedef struct dbRecordType {
|
||||
int rec_size; /*record size in bytes */
|
||||
}dbRecordType;
|
||||
|
||||
struct dbPvd; /* Contents private to dbPvdLib code */
|
||||
struct gphPvt; /* Contents private to gpHashLib code */
|
||||
|
||||
typedef struct dbBase {
|
||||
ELLLIST menuList;
|
||||
ELLLIST recordTypeList;
|
||||
@@ -159,10 +162,10 @@ typedef struct dbBase {
|
||||
ELLLIST registrarList;
|
||||
ELLLIST functionList;
|
||||
ELLLIST variableList;
|
||||
ELLLIST bptList; /*Break Point Table Head*/
|
||||
ELLLIST bptList;
|
||||
void *pathPvt;
|
||||
void *ppvd; /* pointer to process variable directory*/
|
||||
void *pgpHash; /*General purpose Hash Table*/
|
||||
struct dbPvd *ppvd;
|
||||
struct gphPvt *pgpHash;
|
||||
short ignoreMissingMenus;
|
||||
short loadCdefs;
|
||||
}dbBase;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
|
||||
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
@@ -13,241 +13,215 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "dbBase.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsMutex.h"
|
||||
#define epicsExportSharedSymbols
|
||||
#include "dbStaticLib.h"
|
||||
#include "dbStaticPvt.h"
|
||||
|
||||
int dbPvdHashTableSize = 512;
|
||||
static int dbPvdHashTableShift;
|
||||
#define NTABLESIZES 9
|
||||
static struct {
|
||||
unsigned int tablesize;
|
||||
int shift;
|
||||
}hashTableParms[9] = {
|
||||
{256,0},
|
||||
{512,1},
|
||||
{1024,2},
|
||||
{2048,3},
|
||||
{4096,4},
|
||||
{8192,5},
|
||||
{16384,6},
|
||||
{32768,7},
|
||||
{65536,8}
|
||||
};
|
||||
typedef struct {
|
||||
ELLLIST list;
|
||||
epicsMutexId lock;
|
||||
} dbPvdBucket;
|
||||
|
||||
/*The hash algorithm is a modification of the algorithm described in */
|
||||
/* Fast Hashing of Variable Length Text Strings, Peter K. Pearson, */
|
||||
/* Communications of the ACM, June 1990 */
|
||||
/* The modifications were designed by Marty Kraimer */
|
||||
typedef struct dbPvd {
|
||||
unsigned int size;
|
||||
unsigned int mask;
|
||||
dbPvdBucket **buckets;
|
||||
} dbPvd;
|
||||
|
||||
static unsigned char T[256] = {
|
||||
39,159,180,252, 71, 6, 13,164,232, 35,226,155, 98,120,154, 69,
|
||||
157, 24,137, 29,147, 78,121, 85,112, 8,248,130, 55,117,190,160,
|
||||
176,131,228, 64,211,106, 38, 27,140, 30, 88,210,227,104, 84, 77,
|
||||
75,107,169,138,195,184, 70, 90, 61,166, 7,244,165,108,219, 51,
|
||||
9,139,209, 40, 31,202, 58,179,116, 33,207,146, 76, 60,242,124,
|
||||
254,197, 80,167,153,145,129,233,132, 48,246, 86,156,177, 36,187,
|
||||
45, 1, 96, 18, 19, 62,185,234, 99, 16,218, 95,128,224,123,253,
|
||||
42,109, 4,247, 72, 5,151,136, 0,152,148,127,204,133, 17, 14,
|
||||
182,217, 54,199,119,174, 82, 57,215, 41,114,208,206,110,239, 23,
|
||||
189, 15, 3, 22,188, 79,113,172, 28, 2,222, 21,251,225,237,105,
|
||||
102, 32, 56,181,126, 83,230, 53,158, 52, 59,213,118,100, 67,142,
|
||||
220,170,144,115,205, 26,125,168,249, 66,175, 97,255, 92,229, 91,
|
||||
214,236,178,243, 46, 44,201,250,135,186,150,221,163,216,162, 43,
|
||||
11,101, 34, 37,194, 25, 50, 12, 87,198,173,240,193,171,143,231,
|
||||
111,141,191,103, 74,245,223, 20,161,235,122, 63, 89,149, 73,238,
|
||||
134, 68, 93,183,241, 81,196, 49,192, 65,212, 94,203, 10,200, 47
|
||||
};
|
||||
unsigned int dbPvdHashTableSize = 0;
|
||||
|
||||
|
||||
static unsigned short hash( const char *pname, int length)
|
||||
#define MIN_SIZE 256
|
||||
#define DEFAULT_SIZE 512
|
||||
#define MAX_SIZE 65536
|
||||
|
||||
|
||||
int dbPvdTableSize(int size)
|
||||
{
|
||||
unsigned char h0=0;
|
||||
unsigned char h1=0;
|
||||
unsigned short ind0,ind1;
|
||||
int isOdd;
|
||||
int i,n;
|
||||
|
||||
isOdd = length%2; /*See if length is odd number of chanacters*/
|
||||
n = (isOdd ? (length-1) : length);
|
||||
if(isOdd) h0 = T[h0^*(pname + length -1)];
|
||||
for(i=0; i<n; i+=2, pname+=2) {
|
||||
h0 = T[h0^*pname];
|
||||
h1 = T[h1^*(pname+1)];
|
||||
if (size & (size - 1)) {
|
||||
printf("dbPvdTableSize: %d is not a power of 2\n", size);
|
||||
return -1;
|
||||
}
|
||||
ind0 = (unsigned short)h0;
|
||||
ind1 = (unsigned short)h1;
|
||||
return((ind1<<dbPvdHashTableShift) ^ ind0);
|
||||
|
||||
if (size < MIN_SIZE)
|
||||
size = MIN_SIZE;
|
||||
|
||||
if (size > MAX_SIZE)
|
||||
size = MAX_SIZE;
|
||||
|
||||
dbPvdHashTableSize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int epicsShareAPI dbPvdTableSize(int size)
|
||||
void dbPvdInitPvt(dbBase *pdbbase)
|
||||
{
|
||||
int i;
|
||||
dbPvd *ppvd;
|
||||
|
||||
for(i=0; i< NTABLESIZES; i++) {
|
||||
if(size==hashTableParms[i].tablesize) {
|
||||
dbPvdHashTableSize = hashTableParms[i].tablesize;
|
||||
dbPvdHashTableShift = hashTableParms[i].shift;
|
||||
return(0);
|
||||
}
|
||||
if (pdbbase->ppvd) return;
|
||||
|
||||
if (dbPvdHashTableSize == 0) {
|
||||
dbPvdHashTableSize = DEFAULT_SIZE;
|
||||
}
|
||||
printf("Illegal Size for Process Variable Directory\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
ppvd = (dbPvd *)dbMalloc(sizeof(dbPvd));
|
||||
ppvd->size = dbPvdHashTableSize;
|
||||
ppvd->mask = dbPvdHashTableSize - 1;
|
||||
ppvd->buckets = dbCalloc(ppvd->size, sizeof(dbPvdBucket *));
|
||||
|
||||
void dbPvdInitPvt(dbBase *pdbbase)
|
||||
{
|
||||
ELLLIST **ppvd;
|
||||
int i;
|
||||
|
||||
for(i=0; i< NTABLESIZES; i++) {
|
||||
if((i==NTABLESIZES-1)
|
||||
||((dbPvdHashTableSize>=hashTableParms[i].tablesize)
|
||||
&& (dbPvdHashTableSize<hashTableParms[i+1].tablesize))) {
|
||||
dbPvdHashTableSize = hashTableParms[i].tablesize;
|
||||
dbPvdHashTableShift = hashTableParms[i].shift;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ppvd = dbCalloc(dbPvdHashTableSize, sizeof(ELLLIST *));
|
||||
pdbbase->ppvd = (void *) ppvd;
|
||||
pdbbase->ppvd = ppvd;
|
||||
return;
|
||||
}
|
||||
|
||||
PVDENTRY *dbPvdFind(dbBase *pdbbase, const char *name, int lenName)
|
||||
{
|
||||
unsigned short hashInd;
|
||||
ELLLIST **ppvd = (ELLLIST **) pdbbase->ppvd;
|
||||
ELLLIST *pvdlist;
|
||||
PVDENTRY *ppvdNode;
|
||||
dbPvd *ppvd = pdbbase->ppvd;
|
||||
dbPvdBucket *pbucket;
|
||||
PVDENTRY *ppvdNode;
|
||||
|
||||
hashInd = hash(name, lenName);
|
||||
pvdlist = ppvd[hashInd];
|
||||
if (pvdlist == NULL) return NULL;
|
||||
ppvdNode = (PVDENTRY *) ellFirst(pvdlist);
|
||||
pbucket = ppvd->buckets[epicsMemHash(name, lenName, 0) & ppvd->mask];
|
||||
if (pbucket == NULL) return NULL;
|
||||
|
||||
epicsMutexMustLock(pbucket->lock);
|
||||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||||
while (ppvdNode) {
|
||||
if (strncmp(name, ppvdNode->precnode->recordname, lenName) == 0)
|
||||
return ppvdNode;
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE*)ppvdNode);
|
||||
const char *recordname = ppvdNode->precnode->recordname;
|
||||
|
||||
if (strncmp(name, recordname, lenName) == 0 &&
|
||||
strlen(recordname) == lenName)
|
||||
break;
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE *)ppvdNode);
|
||||
}
|
||||
return NULL;
|
||||
epicsMutexUnlock(pbucket->lock);
|
||||
return ppvdNode;
|
||||
}
|
||||
|
||||
PVDENTRY *dbPvdAdd(dbBase *pdbbase, dbRecordType *precordType, dbRecordNode *precnode)
|
||||
PVDENTRY *dbPvdAdd(dbBase *pdbbase, dbRecordType *precordType,
|
||||
dbRecordNode *precnode)
|
||||
{
|
||||
unsigned short hashInd;
|
||||
ELLLIST **ppvd = (ELLLIST **) pdbbase->ppvd;
|
||||
ELLLIST *ppvdlist;
|
||||
PVDENTRY *ppvdNode;
|
||||
int lenName;
|
||||
char *name = precnode->recordname;
|
||||
dbPvd *ppvd = pdbbase->ppvd;
|
||||
dbPvdBucket *pbucket;
|
||||
PVDENTRY *ppvdNode;
|
||||
char *name = precnode->recordname;
|
||||
unsigned int h;
|
||||
|
||||
lenName = strlen(name);
|
||||
hashInd = hash(name, lenName);
|
||||
ppvdlist = ppvd[hashInd];
|
||||
if (ppvdlist == NULL) {
|
||||
ppvdlist = dbCalloc(1, sizeof(ELLLIST));
|
||||
ellInit(ppvdlist);
|
||||
ppvd[hashInd] = ppvdlist;
|
||||
h = epicsStrHash(name, 0) & ppvd->mask;
|
||||
pbucket = ppvd->buckets[h];
|
||||
if (pbucket == NULL) {
|
||||
pbucket = dbCalloc(1, sizeof(dbPvdBucket));
|
||||
ellInit(&pbucket->list);
|
||||
pbucket->lock = epicsMutexCreate();
|
||||
ppvd->buckets[h] = pbucket;
|
||||
}
|
||||
ppvdNode = (PVDENTRY *) ellFirst(ppvdlist);
|
||||
|
||||
epicsMutexMustLock(pbucket->lock);
|
||||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||||
while (ppvdNode) {
|
||||
if (strcmp(name, ppvdNode->precnode->recordname) == 0) return NULL;
|
||||
if (strcmp(name, ppvdNode->precnode->recordname) == 0) {
|
||||
epicsMutexUnlock(pbucket->lock);
|
||||
return NULL;
|
||||
}
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE *)ppvdNode);
|
||||
}
|
||||
ppvdNode = dbCalloc(1, sizeof(PVDENTRY));
|
||||
ppvdNode->precordType = precordType;
|
||||
ppvdNode->precnode = precnode;
|
||||
ellAdd(ppvdlist, (ELLNODE *)ppvdNode);
|
||||
ellAdd(&pbucket->list, (ELLNODE *)ppvdNode);
|
||||
epicsMutexUnlock(pbucket->lock);
|
||||
return ppvdNode;
|
||||
}
|
||||
|
||||
void dbPvdDelete(dbBase *pdbbase,dbRecordNode *precnode)
|
||||
void dbPvdDelete(dbBase *pdbbase, dbRecordNode *precnode)
|
||||
{
|
||||
char *name=precnode->recordname;
|
||||
unsigned short hashInd;
|
||||
ELLLIST **ppvd = (ELLLIST **) pdbbase->ppvd;
|
||||
ELLLIST *ppvdlist;
|
||||
PVDENTRY *ppvdNode;
|
||||
int lenName;
|
||||
|
||||
lenName=strlen(name);
|
||||
hashInd = hash(name, lenName);
|
||||
if (ppvd[hashInd] == NULL)return;
|
||||
ppvdlist=ppvd[hashInd];
|
||||
ppvdNode = (PVDENTRY *) ellFirst(ppvdlist);
|
||||
while(ppvdNode) {
|
||||
if(ppvdNode->precnode && ppvdNode->precnode->recordname
|
||||
&& strcmp(name,(char *)ppvdNode->precnode->recordname) == 0) {
|
||||
ellDelete(ppvdlist, (ELLNODE*)ppvdNode);
|
||||
free((void *)ppvdNode);
|
||||
return;
|
||||
}
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE*)ppvdNode);
|
||||
dbPvd *ppvd = pdbbase->ppvd;
|
||||
dbPvdBucket *pbucket;
|
||||
PVDENTRY *ppvdNode;
|
||||
char *name = precnode->recordname;
|
||||
|
||||
pbucket = ppvd->buckets[epicsStrHash(name, 0) & ppvd->mask];
|
||||
if (pbucket == NULL) return;
|
||||
|
||||
epicsMutexMustLock(pbucket->lock);
|
||||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||||
while (ppvdNode) {
|
||||
if (ppvdNode->precnode &&
|
||||
ppvdNode->precnode->recordname &&
|
||||
strcmp(name, ppvdNode->precnode->recordname) == 0) {
|
||||
ellDelete(&pbucket->list, (ELLNODE *)ppvdNode);
|
||||
free(ppvdNode);
|
||||
break;
|
||||
}
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE *)ppvdNode);
|
||||
}
|
||||
epicsMutexUnlock(pbucket->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void dbPvdFreeMem(dbBase *pdbbase)
|
||||
{
|
||||
unsigned short hashInd;
|
||||
ELLLIST **ppvd = (ELLLIST **) pdbbase->ppvd;
|
||||
ELLLIST *ppvdlist;
|
||||
PVDENTRY *ppvdNode;
|
||||
PVDENTRY *next;
|
||||
|
||||
dbPvd *ppvd = pdbbase->ppvd;
|
||||
unsigned int h;
|
||||
|
||||
if (ppvd == NULL) return;
|
||||
for (hashInd=0; hashInd<(unsigned short)dbPvdHashTableSize; hashInd++) {
|
||||
if(ppvd[hashInd] == NULL) continue;
|
||||
ppvdlist=ppvd[hashInd];
|
||||
ppvdNode = (PVDENTRY *) ellFirst(ppvdlist);
|
||||
while(ppvdNode) {
|
||||
next = (PVDENTRY *) ellNext((ELLNODE*)ppvdNode);
|
||||
ellDelete(ppvdlist,(ELLNODE*)ppvdNode);
|
||||
free((void *)ppvdNode);
|
||||
ppvdNode = next;
|
||||
}
|
||||
free((void *)ppvd[hashInd]);
|
||||
}
|
||||
free((void *)ppvd);
|
||||
pdbbase->ppvd = NULL;
|
||||
|
||||
for (h = 0; h < ppvd->size; h++) {
|
||||
dbPvdBucket *pbucket = ppvd->buckets[h];
|
||||
PVDENTRY *ppvdNode;
|
||||
|
||||
if (pbucket == NULL) continue;
|
||||
epicsMutexMustLock(pbucket->lock);
|
||||
ppvd->buckets[h] = NULL;
|
||||
while ((ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list))) {
|
||||
ellDelete(&pbucket->list, (ELLNODE *)ppvdNode);
|
||||
free(ppvdNode);
|
||||
}
|
||||
epicsMutexDestroy(pbucket->lock);
|
||||
free(pbucket);
|
||||
}
|
||||
free(ppvd->buckets);
|
||||
free(ppvd);
|
||||
}
|
||||
|
||||
void epicsShareAPI dbPvdDump(dbBase *pdbbase,int verbose)
|
||||
void dbPvdDump(dbBase *pdbbase, int verbose)
|
||||
{
|
||||
unsigned short hashInd;
|
||||
ELLLIST **ppvd;
|
||||
ELLLIST *ppvdlist;
|
||||
PVDENTRY *ppvdNode;
|
||||
int number;
|
||||
|
||||
if(!pdbbase) {
|
||||
unsigned int empty = 0;
|
||||
dbPvd *ppvd;
|
||||
unsigned int h;
|
||||
|
||||
if (!pdbbase) {
|
||||
fprintf(stderr,"pdbbase not specified\n");
|
||||
return;
|
||||
}
|
||||
ppvd = (ELLLIST **)pdbbase->ppvd;
|
||||
ppvd = pdbbase->ppvd;
|
||||
if (ppvd == NULL) return;
|
||||
printf("Process Variable Directory\n");
|
||||
printf("dbPvdHashTableSize %d dbPvdHashTableShift %d\n",
|
||||
dbPvdHashTableSize,dbPvdHashTableShift);
|
||||
for (hashInd=0; hashInd<(unsigned short)dbPvdHashTableSize; hashInd++) {
|
||||
if(ppvd[hashInd] == NULL) continue;
|
||||
ppvdlist=ppvd[hashInd];
|
||||
ppvdNode = (PVDENTRY *) ellFirst(ppvdlist);
|
||||
printf("\n%3.3hd=%3.3d ",hashInd,ellCount(ppvdlist));
|
||||
number=0;
|
||||
while(ppvdNode && verbose) {
|
||||
printf(" %s",(char *)ppvdNode->precnode->recordname);
|
||||
if(number++ ==2) {number=0;printf("\n ");}
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE*)ppvdNode);
|
||||
}
|
||||
|
||||
printf("Process Variable Directory has %u buckets", ppvd->size);
|
||||
|
||||
for (h = 0; h < ppvd->size; h++) {
|
||||
dbPvdBucket *pbucket = ppvd->buckets[h];
|
||||
PVDENTRY *ppvdNode;
|
||||
int i = 1;
|
||||
|
||||
if (pbucket == NULL) {
|
||||
empty++;
|
||||
continue;
|
||||
}
|
||||
epicsMutexMustLock(pbucket->lock);
|
||||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||||
printf("\n [%4u] %4d ", h, ellCount(&pbucket->list));
|
||||
while (ppvdNode && verbose) {
|
||||
if (!(++i % 4))
|
||||
printf("\n ");
|
||||
printf(" %s", ppvdNode->precnode->recordname);
|
||||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE*)ppvdNode);
|
||||
}
|
||||
epicsMutexUnlock(pbucket->lock);
|
||||
}
|
||||
printf("\nEnd of Process Variable Directory\n");
|
||||
printf("\n%u buckets empty.\n", empty);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* gpHash.h */
|
||||
/* share/epicsH $Id$ */
|
||||
/* $Id$ */
|
||||
/* Author: Marty Kraimer Date: 04-07-94 */
|
||||
|
||||
/* gph provides a general purpose directory accessed via a hash table*/
|
||||
#ifndef INCgpHashh
|
||||
#define INCgpHashh 1
|
||||
|
||||
#ifndef INC_gpHash_H
|
||||
#define INC_gpHash_H
|
||||
|
||||
#include "shareLib.h"
|
||||
|
||||
@@ -26,24 +26,27 @@ typedef struct{
|
||||
void *userPvt; /*private for user*/
|
||||
} GPHENTRY;
|
||||
|
||||
struct gphPvt;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*tableSize must be power of 2 in range 256 to 65536*/
|
||||
epicsShareFunc void epicsShareAPI gphInitPvt(void **ppvt,int tableSize);
|
||||
epicsShareFunc GPHENTRY * epicsShareAPI
|
||||
gphFind(void *pvt,const char *name,void *pvtid);
|
||||
epicsShareFunc GPHENTRY * epicsShareAPI
|
||||
gphAdd(void *pvt,const char *name,void *pvtid);
|
||||
epicsShareFunc void epicsShareAPI
|
||||
gphDelete(void *pvt,const char *name,void *pvtid);
|
||||
epicsShareFunc void epicsShareAPI gphFreeMem(void *pvt);
|
||||
epicsShareFunc void epicsShareAPI gphDump(void *pvt);
|
||||
epicsShareFunc void epicsShareAPI gphDumpFP(FILE *fp,void *pvt);
|
||||
gphInitPvt(struct gphPvt **ppvt, int tableSize);
|
||||
epicsShareFunc GPHENTRY * epicsShareAPI
|
||||
gphFind(struct gphPvt *pvt, const char *name, void *pvtid);
|
||||
epicsShareFunc GPHENTRY * epicsShareAPI
|
||||
gphAdd(struct gphPvt *pvt, const char *name, void *pvtid);
|
||||
epicsShareFunc void epicsShareAPI
|
||||
gphDelete(struct gphPvt *pvt, const char *name, void *pvtid);
|
||||
epicsShareFunc void epicsShareAPI gphFreeMem(struct gphPvt *pvt);
|
||||
epicsShareFunc void epicsShareAPI gphDump(struct gphPvt *pvt);
|
||||
epicsShareFunc void epicsShareAPI gphDumpFP(FILE *fp, struct gphPvt *pvt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCgpHashh*/
|
||||
#endif /* INC_gpHash_H */
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* $Id$ */
|
||||
|
||||
/* Author: Marty Kraimer Date: 04-07-94 */
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -18,240 +18,214 @@
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsString.h"
|
||||
#include "dbDefs.h"
|
||||
#include "ellLib.h"
|
||||
#include "epicsPrint.h"
|
||||
#include "gpHash.h"
|
||||
|
||||
typedef struct gphPvt {
|
||||
int tableSize;
|
||||
int nShift;
|
||||
ELLLIST **paplist; /*pointer to array of pointers to ELLLIST */
|
||||
int size;
|
||||
unsigned int mask;
|
||||
ELLLIST **paplist; /*pointer to array of pointers to ELLLIST */
|
||||
epicsMutexId lock;
|
||||
}gphPvt;
|
||||
} gphPvt;
|
||||
|
||||
#define MIN_SIZE 256
|
||||
#define DEFAULT_SIZE 512
|
||||
#define MAX_SIZE 65536
|
||||
|
||||
/*The hash algorithm is the algorithm described in */
|
||||
/* Fast Hashing of Variable Length Text Strings, Peter K. Pearson, */
|
||||
/* Communications of the ACM, June 1990 */
|
||||
|
||||
static unsigned char T[256] = {
|
||||
39,159,180,252, 71, 6, 13,164,232, 35,226,155, 98,120,154, 69,
|
||||
157, 24,137, 29,147, 78,121, 85,112, 8,248,130, 55,117,190,160,
|
||||
176,131,228, 64,211,106, 38, 27,140, 30, 88,210,227,104, 84, 77,
|
||||
75,107,169,138,195,184, 70, 90, 61,166, 7,244,165,108,219, 51,
|
||||
9,139,209, 40, 31,202, 58,179,116, 33,207,146, 76, 60,242,124,
|
||||
254,197, 80,167,153,145,129,233,132, 48,246, 86,156,177, 36,187,
|
||||
45, 1, 96, 18, 19, 62,185,234, 99, 16,218, 95,128,224,123,253,
|
||||
42,109, 4,247, 72, 5,151,136, 0,152,148,127,204,133, 17, 14,
|
||||
182,217, 54,199,119,174, 82, 57,215, 41,114,208,206,110,239, 23,
|
||||
189, 15, 3, 22,188, 79,113,172, 28, 2,222, 21,251,225,237,105,
|
||||
102, 32, 56,181,126, 83,230, 53,158, 52, 59,213,118,100, 67,142,
|
||||
220,170,144,115,205, 26,125,168,249, 66,175, 97,255, 92,229, 91,
|
||||
214,236,178,243, 46, 44,201,250,135,186,150,221,163,216,162, 43,
|
||||
11,101, 34, 37,194, 25, 50, 12, 87,198,173,240,193,171,143,231,
|
||||
111,141,191,103, 74,245,223, 20,161,235,122, 63, 89,149, 73,238,
|
||||
134, 68, 93,183,241, 81,196, 49,192, 65,212, 94,203, 10,200, 47
|
||||
};
|
||||
|
||||
#define NSIZES 9
|
||||
static int allowSize[NSIZES] = {256,512,1024,2048,4096,8192,16384,32768,65536};
|
||||
|
||||
static int hash(const char *pname,int nShift)
|
||||
{
|
||||
unsigned char h0=0;
|
||||
unsigned char h1=0;
|
||||
unsigned short ind0,ind1;
|
||||
int even = TRUE;
|
||||
unsigned char c;
|
||||
|
||||
while(*pname) {
|
||||
c = *pname;
|
||||
if(even) {h0 = T[h0^c]; even = FALSE;}
|
||||
else {h1 = T[h1^c]; even = TRUE;}
|
||||
pname++;
|
||||
}
|
||||
ind0 = (unsigned short)h0;
|
||||
ind1 = (unsigned short)h1;
|
||||
return((ind1<<nShift) ^ ind0);
|
||||
}
|
||||
|
||||
void epicsShareAPI gphInitPvt(void **ppvt,int size)
|
||||
void epicsShareAPI gphInitPvt(gphPvt **ppvt, int size)
|
||||
{
|
||||
gphPvt *pgphPvt;
|
||||
int i;
|
||||
int tableSize=0;
|
||||
int nShift=0;
|
||||
|
||||
for(i=0; i<NSIZES; i++) {
|
||||
if(size==allowSize[i]) {
|
||||
tableSize = size;
|
||||
nShift = i;
|
||||
}
|
||||
}
|
||||
if(tableSize==0) {
|
||||
epicsPrintf("gphInitPvt: Illegal size\n");
|
||||
return;
|
||||
if (size & (size - 1)) {
|
||||
printf("gphInitPvt: %d is not a power of 2\n", size);
|
||||
size = DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
if (size < MIN_SIZE)
|
||||
size = MIN_SIZE;
|
||||
|
||||
if (size > MAX_SIZE)
|
||||
size = MAX_SIZE;
|
||||
|
||||
pgphPvt = callocMustSucceed(1, sizeof(gphPvt), "gphInitPvt");
|
||||
pgphPvt->tableSize = tableSize;
|
||||
pgphPvt->nShift = nShift;
|
||||
pgphPvt->paplist = callocMustSucceed(tableSize, sizeof(ELLLIST *), "gphInitPvt");
|
||||
pgphPvt->size = size;
|
||||
pgphPvt->mask = size - 1;
|
||||
pgphPvt->paplist = callocMustSucceed(size, sizeof(ELLLIST *), "gphInitPvt");
|
||||
pgphPvt->lock = epicsMutexMustCreate();
|
||||
*ppvt = (void *)pgphPvt;
|
||||
*ppvt = pgphPvt;
|
||||
return;
|
||||
}
|
||||
|
||||
GPHENTRY * epicsShareAPI gphFind(void *pvt, const char *name, void *pvtid)
|
||||
GPHENTRY * epicsShareAPI gphFind(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
{
|
||||
int hashInd;
|
||||
gphPvt *pgphPvt = (gphPvt *)pvt;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *gphlist;
|
||||
GPHENTRY *pgphNode;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *gphlist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
hashInd = hash(name, pgphPvt->nShift);
|
||||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||||
|
||||
epicsMutexMustLock(pgphPvt->lock);
|
||||
gphlist = paplist[hashInd];
|
||||
gphlist = paplist[hash];
|
||||
if (gphlist == NULL) {
|
||||
pgphNode = NULL;
|
||||
} else {
|
||||
pgphNode = (GPHENTRY *) ellFirst(gphlist);
|
||||
}
|
||||
|
||||
while (pgphNode) {
|
||||
if (strcmp(name, pgphNode->name) == 0) {
|
||||
if (pvtid == pgphNode->pvtid) break;
|
||||
}
|
||||
if (pvtid == pgphNode->pvtid &&
|
||||
strcmp(name, pgphNode->name) == 0) break;
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE *)pgphNode);
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pgphPvt->lock);
|
||||
return pgphNode;
|
||||
}
|
||||
|
||||
GPHENTRY * epicsShareAPI gphAdd(void *pvt,const char *name,void *pvtid)
|
||||
GPHENTRY * epicsShareAPI gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
{
|
||||
int hashInd;
|
||||
gphPvt *pgphPvt = (gphPvt *)pvt;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
|
||||
if (pgphPvt==NULL) return NULL;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
hashInd = hash(name,pgphPvt->nShift);
|
||||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||||
|
||||
epicsMutexMustLock(pgphPvt->lock);
|
||||
plist = paplist[hashInd];
|
||||
plist = paplist[hash];
|
||||
if (plist == NULL) {
|
||||
plist = callocMustSucceed(1, sizeof(ELLLIST), "gphAdd");
|
||||
ellInit(plist);
|
||||
paplist[hashInd] = plist;
|
||||
paplist[hash] = plist;
|
||||
}
|
||||
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
while (pgphNode) {
|
||||
if ((strcmp(name, pgphNode->name) == 0) &&
|
||||
(pvtid == pgphNode->pvtid)) {
|
||||
if (pvtid == pgphNode->pvtid &&
|
||||
strcmp(name, pgphNode->name) == 0) {
|
||||
epicsMutexUnlock(pgphPvt->lock);
|
||||
return NULL;
|
||||
}
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE *)pgphNode);
|
||||
}
|
||||
|
||||
pgphNode = callocMustSucceed(1, sizeof(GPHENTRY), "gphAdd");
|
||||
pgphNode->name = name;
|
||||
pgphNode->pvtid = pvtid;
|
||||
ellAdd(plist, (ELLNODE *)pgphNode);
|
||||
|
||||
epicsMutexUnlock(pgphPvt->lock);
|
||||
return (pgphNode);
|
||||
}
|
||||
|
||||
void epicsShareAPI gphDelete(void *pvt,const char *name,void *pvtid)
|
||||
void epicsShareAPI gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
{
|
||||
int hashInd;
|
||||
gphPvt *pgphPvt = (gphPvt *)pvt;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist = NULL;
|
||||
GPHENTRY *pgphNode;
|
||||
|
||||
if(pgphPvt==NULL) return;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist = NULL;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
|
||||
if (pgphPvt == NULL) return;
|
||||
paplist = pgphPvt->paplist;
|
||||
hashInd = hash(name,pgphPvt->nShift);
|
||||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||||
|
||||
epicsMutexMustLock(pgphPvt->lock);
|
||||
if(paplist[hashInd] == NULL) {
|
||||
pgphNode = NULL;
|
||||
if (paplist[hash] == NULL) {
|
||||
pgphNode = NULL;
|
||||
} else {
|
||||
plist=paplist[hashInd];
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
plist = paplist[hash];
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
}
|
||||
|
||||
while(pgphNode) {
|
||||
if((strcmp(name,(char *)pgphNode->name) == 0)
|
||||
&&(pvtid == pgphNode->pvtid)) {
|
||||
ellDelete(plist, (ELLNODE*)pgphNode);
|
||||
free((void *)pgphNode);
|
||||
break;
|
||||
}
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
if (pvtid == pgphNode->pvtid &&
|
||||
strcmp(name, pgphNode->name) == 0) {
|
||||
ellDelete(plist, (ELLNODE*)pgphNode);
|
||||
free((void *)pgphNode);
|
||||
break;
|
||||
}
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pgphPvt->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
void epicsShareAPI gphFreeMem(void *pvt)
|
||||
void epicsShareAPI gphFreeMem(gphPvt *pgphPvt)
|
||||
{
|
||||
int hashInd;
|
||||
gphPvt *pgphPvt = (gphPvt *)pvt;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
GPHENTRY *next;;
|
||||
|
||||
/*caller must ensure that no other thread is using *pvt */
|
||||
if(pgphPvt==NULL) return;
|
||||
ELLLIST **paplist;
|
||||
int h;
|
||||
|
||||
/* Caller must ensure that no other thread is using *pvt */
|
||||
if (pgphPvt == NULL) return;
|
||||
|
||||
paplist = pgphPvt->paplist;
|
||||
for (hashInd=0; hashInd<pgphPvt->tableSize; hashInd++) {
|
||||
if(paplist[hashInd] == NULL) continue;
|
||||
plist=paplist[hashInd];
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
while(pgphNode) {
|
||||
next = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
ellDelete(plist,(ELLNODE*)pgphNode);
|
||||
free((void *)pgphNode);
|
||||
pgphNode = next;
|
||||
}
|
||||
free((void *)paplist[hashInd]);
|
||||
for (h = 0; h < pgphPvt->size; h++) {
|
||||
ELLLIST *plist = paplist[h];
|
||||
GPHENTRY *pgphNode;
|
||||
GPHENTRY *next;
|
||||
|
||||
if (plist == NULL) continue;
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
|
||||
while (pgphNode) {
|
||||
next = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
ellDelete(plist, (ELLNODE*)pgphNode);
|
||||
free(pgphNode);
|
||||
pgphNode = next;
|
||||
}
|
||||
free(paplist[h]);
|
||||
}
|
||||
epicsMutexDestroy(pgphPvt->lock);
|
||||
free((void *)paplist);
|
||||
free((void *)pgphPvt);
|
||||
free(paplist);
|
||||
free(pgphPvt);
|
||||
}
|
||||
|
||||
void epicsShareAPI gphDump(void *pvt)
|
||||
void epicsShareAPI gphDump(gphPvt *pgphPvt)
|
||||
{
|
||||
gphDumpFP(stdout,pvt);
|
||||
gphDumpFP(stdout, pgphPvt);
|
||||
}
|
||||
|
||||
void epicsShareAPI gphDumpFP(FILE *fp,void *pvt)
|
||||
void epicsShareAPI gphDumpFP(FILE *fp, gphPvt *pgphPvt)
|
||||
{
|
||||
int hashInd;
|
||||
gphPvt *pgphPvt = (gphPvt *)pvt;
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
int number;
|
||||
|
||||
if(pgphPvt==NULL) return;
|
||||
unsigned int empty = 0;
|
||||
ELLLIST **paplist;
|
||||
int h;
|
||||
|
||||
if (pgphPvt == NULL) return;
|
||||
|
||||
printf("Hash table has %d buckets", pgphPvt->size);
|
||||
|
||||
paplist = pgphPvt->paplist;
|
||||
for (hashInd=0; hashInd<pgphPvt->tableSize; hashInd++) {
|
||||
if(paplist[hashInd] == NULL) continue;
|
||||
plist=paplist[hashInd];
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
fprintf(fp,"\n %3.3hd=%3.3d",hashInd,ellCount(plist));
|
||||
number=0;
|
||||
while(pgphNode) {
|
||||
fprintf(fp," %s %p",pgphNode->name,pgphNode->pvtid);
|
||||
if(number++ ==2) {number=0;fprintf(fp,"\n ");}
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
}
|
||||
for (h = 0; h < pgphPvt->size; h++) {
|
||||
ELLLIST *plist = paplist[h];
|
||||
GPHENTRY *pgphNode;
|
||||
int i = 0;
|
||||
|
||||
if (plist == NULL) {
|
||||
empty++;
|
||||
continue;
|
||||
}
|
||||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||||
|
||||
fprintf(fp, "\n [%3d] %3d ", h, ellCount(plist));
|
||||
while (pgphNode) {
|
||||
if (!(++i % 3))
|
||||
fprintf(fp, "\n ");
|
||||
fprintf(fp, " %s %p", pgphNode->name, pgphNode->pvtid);
|
||||
pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
|
||||
}
|
||||
}
|
||||
fprintf(fp,"\n End of General Purpose Hash\n");
|
||||
fprintf(fp, "\n%u buckets empty.\n", empty);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user