|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* |
|
6 * hash.c |
|
7 * |
|
8 * This is merely a couple wrappers around NSPR's PLHashTable, using |
|
9 * the identity hash and arena-aware allocators. The reason I did |
|
10 * this is that hash tables are used in a few places throughout the |
|
11 * NSS Cryptoki Framework in a fairly stereotyped way, and this allows |
|
12 * me to pull the commonalities into one place. Should we ever want |
|
13 * to change the implementation, it's all right here. |
|
14 */ |
|
15 |
|
16 #ifndef CK_T |
|
17 #include "ck.h" |
|
18 #endif /* CK_T */ |
|
19 |
|
20 /* |
|
21 * nssCKFWHash |
|
22 * |
|
23 * nssCKFWHash_Create |
|
24 * nssCKFWHash_Destroy |
|
25 * nssCKFWHash_Add |
|
26 * nssCKFWHash_Remove |
|
27 * nssCKFWHash_Count |
|
28 * nssCKFWHash_Exists |
|
29 * nssCKFWHash_Lookup |
|
30 * nssCKFWHash_Iterate |
|
31 */ |
|
32 |
|
33 struct nssCKFWHashStr { |
|
34 NSSCKFWMutex *mutex; |
|
35 |
|
36 /* |
|
37 * The invariant that mutex protects is: |
|
38 * The count accurately reflects the hashtable state. |
|
39 */ |
|
40 |
|
41 PLHashTable *plHashTable; |
|
42 CK_ULONG count; |
|
43 }; |
|
44 |
|
45 static PLHashNumber |
|
46 nss_ckfw_identity_hash |
|
47 ( |
|
48 const void *key |
|
49 ) |
|
50 { |
|
51 PRUint32 i = (PRUint32)key; |
|
52 PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32)); |
|
53 return (PLHashNumber)i; |
|
54 } |
|
55 |
|
56 /* |
|
57 * nssCKFWHash_Create |
|
58 * |
|
59 */ |
|
60 NSS_IMPLEMENT nssCKFWHash * |
|
61 nssCKFWHash_Create |
|
62 ( |
|
63 NSSCKFWInstance *fwInstance, |
|
64 NSSArena *arena, |
|
65 CK_RV *pError |
|
66 ) |
|
67 { |
|
68 nssCKFWHash *rv; |
|
69 |
|
70 #ifdef NSSDEBUG |
|
71 if (!pError) { |
|
72 return (nssCKFWHash *)NULL; |
|
73 } |
|
74 |
|
75 if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { |
|
76 *pError = CKR_ARGUMENTS_BAD; |
|
77 return (nssCKFWHash *)NULL; |
|
78 } |
|
79 #endif /* NSSDEBUG */ |
|
80 |
|
81 rv = nss_ZNEW(arena, nssCKFWHash); |
|
82 if (!rv) { |
|
83 *pError = CKR_HOST_MEMORY; |
|
84 return (nssCKFWHash *)NULL; |
|
85 } |
|
86 |
|
87 rv->mutex = nssCKFWInstance_CreateMutex(fwInstance, arena, pError); |
|
88 if (!rv->mutex) { |
|
89 if( CKR_OK == *pError ) { |
|
90 (void)nss_ZFreeIf(rv); |
|
91 *pError = CKR_GENERAL_ERROR; |
|
92 } |
|
93 return (nssCKFWHash *)NULL; |
|
94 } |
|
95 |
|
96 rv->plHashTable = PL_NewHashTable(0, nss_ckfw_identity_hash, |
|
97 PL_CompareValues, PL_CompareValues, &nssArenaHashAllocOps, arena); |
|
98 if (!rv->plHashTable) { |
|
99 (void)nssCKFWMutex_Destroy(rv->mutex); |
|
100 (void)nss_ZFreeIf(rv); |
|
101 *pError = CKR_HOST_MEMORY; |
|
102 return (nssCKFWHash *)NULL; |
|
103 } |
|
104 |
|
105 rv->count = 0; |
|
106 |
|
107 return rv; |
|
108 } |
|
109 |
|
110 /* |
|
111 * nssCKFWHash_Destroy |
|
112 * |
|
113 */ |
|
114 NSS_IMPLEMENT void |
|
115 nssCKFWHash_Destroy |
|
116 ( |
|
117 nssCKFWHash *hash |
|
118 ) |
|
119 { |
|
120 (void)nssCKFWMutex_Destroy(hash->mutex); |
|
121 PL_HashTableDestroy(hash->plHashTable); |
|
122 (void)nss_ZFreeIf(hash); |
|
123 } |
|
124 |
|
125 /* |
|
126 * nssCKFWHash_Add |
|
127 * |
|
128 */ |
|
129 NSS_IMPLEMENT CK_RV |
|
130 nssCKFWHash_Add |
|
131 ( |
|
132 nssCKFWHash *hash, |
|
133 const void *key, |
|
134 const void *value |
|
135 ) |
|
136 { |
|
137 CK_RV error = CKR_OK; |
|
138 PLHashEntry *he; |
|
139 |
|
140 error = nssCKFWMutex_Lock(hash->mutex); |
|
141 if( CKR_OK != error ) { |
|
142 return error; |
|
143 } |
|
144 |
|
145 he = PL_HashTableAdd(hash->plHashTable, key, (void *)value); |
|
146 if (!he) { |
|
147 error = CKR_HOST_MEMORY; |
|
148 } else { |
|
149 hash->count++; |
|
150 } |
|
151 |
|
152 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
153 |
|
154 return error; |
|
155 } |
|
156 |
|
157 /* |
|
158 * nssCKFWHash_Remove |
|
159 * |
|
160 */ |
|
161 NSS_IMPLEMENT void |
|
162 nssCKFWHash_Remove |
|
163 ( |
|
164 nssCKFWHash *hash, |
|
165 const void *it |
|
166 ) |
|
167 { |
|
168 PRBool found; |
|
169 |
|
170 if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { |
|
171 return; |
|
172 } |
|
173 |
|
174 found = PL_HashTableRemove(hash->plHashTable, it); |
|
175 if( found ) { |
|
176 hash->count--; |
|
177 } |
|
178 |
|
179 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
180 return; |
|
181 } |
|
182 |
|
183 /* |
|
184 * nssCKFWHash_Count |
|
185 * |
|
186 */ |
|
187 NSS_IMPLEMENT CK_ULONG |
|
188 nssCKFWHash_Count |
|
189 ( |
|
190 nssCKFWHash *hash |
|
191 ) |
|
192 { |
|
193 CK_ULONG count; |
|
194 |
|
195 if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { |
|
196 return (CK_ULONG)0; |
|
197 } |
|
198 |
|
199 count = hash->count; |
|
200 |
|
201 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
202 |
|
203 return count; |
|
204 } |
|
205 |
|
206 /* |
|
207 * nssCKFWHash_Exists |
|
208 * |
|
209 */ |
|
210 NSS_IMPLEMENT CK_BBOOL |
|
211 nssCKFWHash_Exists |
|
212 ( |
|
213 nssCKFWHash *hash, |
|
214 const void *it |
|
215 ) |
|
216 { |
|
217 void *value; |
|
218 |
|
219 if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { |
|
220 return CK_FALSE; |
|
221 } |
|
222 |
|
223 value = PL_HashTableLookup(hash->plHashTable, it); |
|
224 |
|
225 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
226 |
|
227 if (!value) { |
|
228 return CK_FALSE; |
|
229 } else { |
|
230 return CK_TRUE; |
|
231 } |
|
232 } |
|
233 |
|
234 /* |
|
235 * nssCKFWHash_Lookup |
|
236 * |
|
237 */ |
|
238 NSS_IMPLEMENT void * |
|
239 nssCKFWHash_Lookup |
|
240 ( |
|
241 nssCKFWHash *hash, |
|
242 const void *it |
|
243 ) |
|
244 { |
|
245 void *rv; |
|
246 |
|
247 if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { |
|
248 return (void *)NULL; |
|
249 } |
|
250 |
|
251 rv = PL_HashTableLookup(hash->plHashTable, it); |
|
252 |
|
253 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
254 |
|
255 return rv; |
|
256 } |
|
257 |
|
258 struct arg_str { |
|
259 nssCKFWHashIterator fcn; |
|
260 void *closure; |
|
261 }; |
|
262 |
|
263 static PRIntn |
|
264 nss_ckfwhash_enumerator |
|
265 ( |
|
266 PLHashEntry *he, |
|
267 PRIntn index, |
|
268 void *arg |
|
269 ) |
|
270 { |
|
271 struct arg_str *as = (struct arg_str *)arg; |
|
272 as->fcn(he->key, he->value, as->closure); |
|
273 return HT_ENUMERATE_NEXT; |
|
274 } |
|
275 |
|
276 /* |
|
277 * nssCKFWHash_Iterate |
|
278 * |
|
279 * NOTE that the iteration function will be called with the hashtable locked. |
|
280 */ |
|
281 NSS_IMPLEMENT void |
|
282 nssCKFWHash_Iterate |
|
283 ( |
|
284 nssCKFWHash *hash, |
|
285 nssCKFWHashIterator fcn, |
|
286 void *closure |
|
287 ) |
|
288 { |
|
289 struct arg_str as; |
|
290 as.fcn = fcn; |
|
291 as.closure = closure; |
|
292 |
|
293 if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { |
|
294 return; |
|
295 } |
|
296 |
|
297 PL_HashTableEnumerateEntries(hash->plHashTable, nss_ckfwhash_enumerator, &as); |
|
298 |
|
299 (void)nssCKFWMutex_Unlock(hash->mutex); |
|
300 |
|
301 return; |
|
302 } |