Replaced $Id$ and $Header$ keywords with $Revision-Id$ Deleted $Log$ keywords and any log messages
232 lines
6.0 KiB
C
232 lines
6.0 KiB
C
/*************************************************************************\
|
||
* 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 is distributed subject to a Software License Agreement found
|
||
* in file LICENSE that is included with this distribution.
|
||
\*************************************************************************/
|
||
/* $Revision-Id$ */
|
||
|
||
/* Author: Marty Kraimer Date: 04-07-94 */
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <stddef.h>
|
||
|
||
#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 size;
|
||
unsigned int mask;
|
||
ELLLIST **paplist; /*pointer to array of pointers to ELLLIST */
|
||
epicsMutexId lock;
|
||
} gphPvt;
|
||
|
||
#define MIN_SIZE 256
|
||
#define DEFAULT_SIZE 512
|
||
#define MAX_SIZE 65536
|
||
|
||
void epicsShareAPI gphInitPvt(gphPvt **ppvt, int size)
|
||
{
|
||
gphPvt *pgphPvt;
|
||
|
||
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->size = size;
|
||
pgphPvt->mask = size - 1;
|
||
pgphPvt->paplist = callocMustSucceed(size, sizeof(ELLLIST *), "gphInitPvt");
|
||
pgphPvt->lock = epicsMutexMustCreate();
|
||
*ppvt = pgphPvt;
|
||
return;
|
||
}
|
||
|
||
GPHENTRY * epicsShareAPI gphFind(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||
{
|
||
ELLLIST **paplist;
|
||
ELLLIST *gphlist;
|
||
GPHENTRY *pgphNode;
|
||
int hash;
|
||
|
||
if (pgphPvt == NULL) return NULL;
|
||
paplist = pgphPvt->paplist;
|
||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||
|
||
epicsMutexMustLock(pgphPvt->lock);
|
||
gphlist = paplist[hash];
|
||
if (gphlist == NULL) {
|
||
pgphNode = NULL;
|
||
} else {
|
||
pgphNode = (GPHENTRY *) ellFirst(gphlist);
|
||
}
|
||
|
||
while (pgphNode) {
|
||
if (pvtid == pgphNode->pvtid &&
|
||
strcmp(name, pgphNode->name) == 0) break;
|
||
pgphNode = (GPHENTRY *) ellNext((ELLNODE *)pgphNode);
|
||
}
|
||
|
||
epicsMutexUnlock(pgphPvt->lock);
|
||
return pgphNode;
|
||
}
|
||
|
||
GPHENTRY * epicsShareAPI gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||
{
|
||
ELLLIST **paplist;
|
||
ELLLIST *plist;
|
||
GPHENTRY *pgphNode;
|
||
int hash;
|
||
|
||
if (pgphPvt == NULL) return NULL;
|
||
paplist = pgphPvt->paplist;
|
||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||
|
||
epicsMutexMustLock(pgphPvt->lock);
|
||
plist = paplist[hash];
|
||
if (plist == NULL) {
|
||
plist = callocMustSucceed(1, sizeof(ELLLIST), "gphAdd");
|
||
ellInit(plist);
|
||
paplist[hash] = plist;
|
||
}
|
||
|
||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||
while (pgphNode) {
|
||
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(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||
{
|
||
ELLLIST **paplist;
|
||
ELLLIST *plist = NULL;
|
||
GPHENTRY *pgphNode;
|
||
int hash;
|
||
|
||
if (pgphPvt == NULL) return;
|
||
paplist = pgphPvt->paplist;
|
||
hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
|
||
hash = epicsStrHash(name, hash) & pgphPvt->mask;
|
||
|
||
epicsMutexMustLock(pgphPvt->lock);
|
||
if (paplist[hash] == NULL) {
|
||
pgphNode = NULL;
|
||
} else {
|
||
plist = paplist[hash];
|
||
pgphNode = (GPHENTRY *) ellFirst(plist);
|
||
}
|
||
|
||
while(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(gphPvt *pgphPvt)
|
||
{
|
||
ELLLIST **paplist;
|
||
int h;
|
||
|
||
/* Caller must ensure that no other thread is using *pvt */
|
||
if (pgphPvt == NULL) return;
|
||
|
||
paplist = pgphPvt->paplist;
|
||
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(paplist);
|
||
free(pgphPvt);
|
||
}
|
||
|
||
void epicsShareAPI gphDump(gphPvt *pgphPvt)
|
||
{
|
||
gphDumpFP(stdout, pgphPvt);
|
||
}
|
||
|
||
void epicsShareAPI gphDumpFP(FILE *fp, gphPvt *pgphPvt)
|
||
{
|
||
unsigned int empty = 0;
|
||
ELLLIST **paplist;
|
||
int h;
|
||
|
||
if (pgphPvt == NULL) return;
|
||
|
||
printf("Hash table has %d buckets", pgphPvt->size);
|
||
|
||
paplist = pgphPvt->paplist;
|
||
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%u buckets empty.\n", empty);
|
||
}
|