/*************************************************************************\ * 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 #include #include #include #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); }