This is Unofficial EPICS BASE Doxygen Site
gpHashLib.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /* Author: Marty Kraimer Date: 04-07-94 */
11 
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 
16 #include "cantProceed.h"
17 #include "epicsMutex.h"
18 #include "epicsStdioRedirect.h"
19 #include "epicsString.h"
20 #include "dbDefs.h"
21 #include "ellLib.h"
22 #include "epicsPrint.h"
23 #include "gpHash.h"
24 
25 typedef struct gphPvt {
26  int size;
27  unsigned int mask;
28  ELLLIST **paplist; /*pointer to array of pointers to ELLLIST */
30 } gphPvt;
31 
32 #define MIN_SIZE 256
33 #define DEFAULT_SIZE 512
34 #define MAX_SIZE 65536
35 
36 
37 void epicsStdCall gphInitPvt(gphPvt **ppvt, int size)
38 {
39  gphPvt *pgphPvt;
40 
41  if (size & (size - 1)) {
42  fprintf(stderr, "gphInitPvt: %d is not a power of 2\n", size);
43  size = DEFAULT_SIZE;
44  }
45 
46  if (size < MIN_SIZE)
47  size = MIN_SIZE;
48 
49  if (size > MAX_SIZE)
50  size = MAX_SIZE;
51 
52  pgphPvt = callocMustSucceed(1, sizeof(gphPvt), "gphInitPvt");
53  pgphPvt->size = size;
54  pgphPvt->mask = size - 1;
55  pgphPvt->paplist = callocMustSucceed(size, sizeof(ELLLIST *), "gphInitPvt");
56  pgphPvt->lock = epicsMutexMustCreate();
57  *ppvt = pgphPvt;
58  return;
59 }
60 
61 GPHENTRY * epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t len, void *pvtid)
62 {
63  ELLLIST **paplist;
64  ELLLIST *gphlist;
65  GPHENTRY *pgphNode;
66  int hash;
67 
68  if (pgphPvt == NULL) return NULL;
69  paplist = pgphPvt->paplist;
70  hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
71  hash = epicsMemHash(name, len, hash) & pgphPvt->mask;
72 
73  epicsMutexMustLock(pgphPvt->lock);
74  gphlist = paplist[hash];
75  if (gphlist == NULL) {
76  pgphNode = NULL;
77  } else {
78  pgphNode = (GPHENTRY *) ellFirst(gphlist);
79  }
80 
81  while (pgphNode) {
82  if (pvtid == pgphNode->pvtid &&
83  strlen(pgphNode->name) == len &&
84  strncmp(name, pgphNode->name, len) == 0) break;
85  pgphNode = (GPHENTRY *) ellNext((ELLNODE *)pgphNode);
86  }
87 
88  epicsMutexUnlock(pgphPvt->lock);
89  return pgphNode;
90 }
91 
92 GPHENTRY * epicsStdCall gphFind(gphPvt *pgphPvt, const char *name, void *pvtid)
93 {
94  return gphFindParse(pgphPvt, name, strlen(name), pvtid);
95 }
96 
97 GPHENTRY * epicsStdCall gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
98 {
99  ELLLIST **paplist;
100  ELLLIST *plist;
101  GPHENTRY *pgphNode;
102  int hash;
103 
104  if (pgphPvt == NULL) return NULL;
105  paplist = pgphPvt->paplist;
106  hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
107  hash = epicsStrHash(name, hash) & pgphPvt->mask;
108 
109  epicsMutexMustLock(pgphPvt->lock);
110  plist = paplist[hash];
111  if (plist == NULL) {
112  plist = calloc(1, sizeof(ELLLIST));
113  if(!plist){
114  epicsMutexUnlock(pgphPvt->lock);
115  return NULL;
116  }
117  ellInit(plist);
118  paplist[hash] = plist;
119  }
120 
121  pgphNode = (GPHENTRY *) ellFirst(plist);
122  while (pgphNode) {
123  if (pvtid == pgphNode->pvtid &&
124  strcmp(name, pgphNode->name) == 0) {
125  epicsMutexUnlock(pgphPvt->lock);
126  return NULL;
127  }
128  pgphNode = (GPHENTRY *) ellNext((ELLNODE *)pgphNode);
129  }
130 
131  pgphNode = calloc(1, sizeof(GPHENTRY));
132  if(pgphNode) {
133  pgphNode->name = name;
134  pgphNode->pvtid = pvtid;
135  ellAdd(plist, (ELLNODE *)pgphNode);
136  }
137 
138  epicsMutexUnlock(pgphPvt->lock);
139  return (pgphNode);
140 }
141 
142 void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
143 {
144  ELLLIST **paplist;
145  ELLLIST *plist = NULL;
146  GPHENTRY *pgphNode;
147  int hash;
148 
149  if (pgphPvt == NULL) return;
150  paplist = pgphPvt->paplist;
151  hash = epicsMemHash((char *)&pvtid, sizeof(void *), 0);
152  hash = epicsStrHash(name, hash) & pgphPvt->mask;
153 
154  epicsMutexMustLock(pgphPvt->lock);
155  if (paplist[hash] == NULL) {
156  pgphNode = NULL;
157  } else {
158  plist = paplist[hash];
159  pgphNode = (GPHENTRY *) ellFirst(plist);
160  }
161 
162  while(pgphNode) {
163  if (pvtid == pgphNode->pvtid &&
164  strcmp(name, pgphNode->name) == 0) {
165  ellDelete(plist, (ELLNODE*)pgphNode);
166  free((void *)pgphNode);
167  break;
168  }
169  pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
170  }
171 
172  epicsMutexUnlock(pgphPvt->lock);
173  return;
174 }
175 
176 void epicsStdCall gphFreeMem(gphPvt *pgphPvt)
177 {
178  ELLLIST **paplist;
179  int h;
180 
181  /* Caller must ensure that no other thread is using *pvt */
182  if (pgphPvt == NULL) return;
183 
184  paplist = pgphPvt->paplist;
185  for (h = 0; h < pgphPvt->size; h++) {
186  ELLLIST *plist = paplist[h];
187  GPHENTRY *pgphNode;
188  GPHENTRY *next;
189 
190  if (plist == NULL) continue;
191  pgphNode = (GPHENTRY *) ellFirst(plist);
192 
193  while (pgphNode) {
194  next = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
195  ellDelete(plist, (ELLNODE*)pgphNode);
196  free(pgphNode);
197  pgphNode = next;
198  }
199  free(paplist[h]);
200  }
201  epicsMutexDestroy(pgphPvt->lock);
202  free(paplist);
203  free(pgphPvt);
204 }
205 
206 void epicsStdCall gphDump(gphPvt *pgphPvt)
207 {
208  gphDumpFP(stdout, pgphPvt);
209 }
210 
211 void epicsStdCall gphDumpFP(FILE *fp, gphPvt *pgphPvt)
212 {
213  unsigned int empty = 0;
214  ELLLIST **paplist;
215  int h;
216 
217  if (pgphPvt == NULL)
218  return;
219 
220  fprintf(fp, "Hash table has %d buckets", pgphPvt->size);
221 
222  paplist = pgphPvt->paplist;
223  for (h = 0; h < pgphPvt->size; h++) {
224  ELLLIST *plist = paplist[h];
225  GPHENTRY *pgphNode;
226  int i = 0;
227 
228  if (plist == NULL) {
229  empty++;
230  continue;
231  }
232  pgphNode = (GPHENTRY *) ellFirst(plist);
233 
234  fprintf(fp, "\n [%3d] %3d ", h, ellCount(plist));
235  while (pgphNode) {
236  if (!(++i % 3))
237  fprintf(fp, "\n ");
238  fprintf(fp, " %s %p", pgphNode->name, pgphNode->pvtid);
239  pgphNode = (GPHENTRY *) ellNext((ELLNODE*)pgphNode);
240  }
241  }
242  fprintf(fp, "\n%u buckets empty.\n", empty);
243 }
epicsMutexId lock
Definition: gpHashLib.c:29
unsigned int epicsStrHash(const char *str, unsigned int seed)
Definition: epicsString.c:356
epics::pvData::BitSetPtr empty
Definition: pvAccess.cpp:135
void epicsStdCall gphFreeMem(gphPvt *pgphPvt)
Definition: gpHashLib.c:176
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
ELLLIST ** paplist
Definition: gpHashLib.c:28
void epicsStdCall epicsMutexDestroy(epicsMutexId pmutexNode)
Destroy an epicsMutex semaphore.
Definition: epicsMutex.cpp:127
int i
Definition: scan.c:967
GPHENTRY *epicsStdCall gphFind(gphPvt *pgphPvt, const char *name, void *pvtid)
Definition: gpHashLib.c:92
int size
Definition: gpHashLib.c:26
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
#define NULL
Definition: catime.c:38
void epicsStdCall gphInitPvt(gphPvt **ppvt, int size)
Definition: gpHashLib.c:37
#define MAX_SIZE
Definition: gpHashLib.c:34
void epicsStdCall gphDumpFP(FILE *fp, gphPvt *pgphPvt)
Definition: gpHashLib.c:211
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
Miscellaneous macro definitions.
#define MIN_SIZE
Definition: gpHashLib.c:32
A doubly-linked list library.
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
GPHENTRY *epicsStdCall gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
Definition: gpHashLib.c:97
#define DEFAULT_SIZE
Definition: gpHashLib.c:33
APIs for the epicsMutex mutual exclusion semaphore.
void epicsStdCall gphDump(gphPvt *pgphPvt)
Definition: gpHashLib.c:206
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
#define stdout
Definition: epicsStdio.h:30
List node type.
Definition: ellLib.h:45
unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed)
Definition: epicsString.c:369
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
struct gphPvt gphPvt
void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
Definition: gpHashLib.c:142
void * pvtid
Definition: gpHash.h:24
GPHENTRY *epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t len, void *pvtid)
Definition: gpHashLib.c:61
Routines for code that can&#39;t continue or return after an error.
const char * name
Definition: gpHash.h:23
#define stderr
Definition: epicsStdio.h:32
unsigned int mask
Definition: gpHashLib.c:27
List header type.
Definition: ellLib.h:56
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89