228 lines
6.0 KiB
C
228 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.
|
||
\*************************************************************************/
|
||
|
||
/* dbPvdLib.c */
|
||
|
||
#include <stddef.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.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"
|
||
|
||
typedef struct {
|
||
ELLLIST list;
|
||
epicsMutexId lock;
|
||
} dbPvdBucket;
|
||
|
||
typedef struct dbPvd {
|
||
unsigned int size;
|
||
unsigned int mask;
|
||
dbPvdBucket **buckets;
|
||
} dbPvd;
|
||
|
||
unsigned int dbPvdHashTableSize = 0;
|
||
|
||
#define MIN_SIZE 256
|
||
#define DEFAULT_SIZE 512
|
||
#define MAX_SIZE 65536
|
||
|
||
|
||
int dbPvdTableSize(int size)
|
||
{
|
||
if (size & (size - 1)) {
|
||
printf("dbPvdTableSize: %d is not a power of 2\n", size);
|
||
return -1;
|
||
}
|
||
|
||
if (size < MIN_SIZE)
|
||
size = MIN_SIZE;
|
||
|
||
if (size > MAX_SIZE)
|
||
size = MAX_SIZE;
|
||
|
||
dbPvdHashTableSize = size;
|
||
return 0;
|
||
}
|
||
|
||
void dbPvdInitPvt(dbBase *pdbbase)
|
||
{
|
||
dbPvd *ppvd;
|
||
|
||
if (pdbbase->ppvd) return;
|
||
|
||
if (dbPvdHashTableSize == 0) {
|
||
dbPvdHashTableSize = DEFAULT_SIZE;
|
||
}
|
||
|
||
ppvd = (dbPvd *)dbMalloc(sizeof(dbPvd));
|
||
ppvd->size = dbPvdHashTableSize;
|
||
ppvd->mask = dbPvdHashTableSize - 1;
|
||
ppvd->buckets = dbCalloc(ppvd->size, sizeof(dbPvdBucket *));
|
||
|
||
pdbbase->ppvd = ppvd;
|
||
return;
|
||
}
|
||
|
||
PVDENTRY *dbPvdFind(dbBase *pdbbase, const char *name, int lenName)
|
||
{
|
||
dbPvd *ppvd = pdbbase->ppvd;
|
||
dbPvdBucket *pbucket;
|
||
PVDENTRY *ppvdNode;
|
||
|
||
pbucket = ppvd->buckets[epicsMemHash(name, lenName, 0) & ppvd->mask];
|
||
if (pbucket == NULL) return NULL;
|
||
|
||
epicsMutexMustLock(pbucket->lock);
|
||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||
while (ppvdNode) {
|
||
const char *recordname = ppvdNode->precnode->recordname;
|
||
|
||
if (strncmp(name, recordname, lenName) == 0 &&
|
||
strlen(recordname) == lenName)
|
||
break;
|
||
ppvdNode = (PVDENTRY *) ellNext((ELLNODE *)ppvdNode);
|
||
}
|
||
epicsMutexUnlock(pbucket->lock);
|
||
return ppvdNode;
|
||
}
|
||
|
||
PVDENTRY *dbPvdAdd(dbBase *pdbbase, dbRecordType *precordType,
|
||
dbRecordNode *precnode)
|
||
{
|
||
dbPvd *ppvd = pdbbase->ppvd;
|
||
dbPvdBucket *pbucket;
|
||
PVDENTRY *ppvdNode;
|
||
char *name = precnode->recordname;
|
||
unsigned int h;
|
||
|
||
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;
|
||
}
|
||
|
||
epicsMutexMustLock(pbucket->lock);
|
||
ppvdNode = (PVDENTRY *) ellFirst(&pbucket->list);
|
||
while (ppvdNode) {
|
||
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(&pbucket->list, (ELLNODE *)ppvdNode);
|
||
epicsMutexUnlock(pbucket->lock);
|
||
return ppvdNode;
|
||
}
|
||
|
||
void dbPvdDelete(dbBase *pdbbase, dbRecordNode *precnode)
|
||
{
|
||
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)
|
||
{
|
||
dbPvd *ppvd = pdbbase->ppvd;
|
||
unsigned int h;
|
||
|
||
if (ppvd == NULL) return;
|
||
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)
|
||
{
|
||
unsigned int empty = 0;
|
||
dbPvd *ppvd;
|
||
unsigned int h;
|
||
|
||
if (!pdbbase) {
|
||
fprintf(stderr,"pdbbase not specified\n");
|
||
return;
|
||
}
|
||
ppvd = pdbbase->ppvd;
|
||
if (ppvd == NULL) return;
|
||
|
||
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("\n%u buckets empty.\n", empty);
|
||
}
|