hash.c (5362B)
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 const void *key) 48 { 49 return (PLHashNumber)((char *)key - (char *)NULL); 50 } 51 52 /* 53 * nssCKFWHash_Create 54 * 55 */ 56 NSS_IMPLEMENT nssCKFWHash * 57 nssCKFWHash_Create( 58 NSSCKFWInstance *fwInstance, 59 NSSArena *arena, 60 CK_RV *pError) 61 { 62 nssCKFWHash *rv; 63 64 #ifdef NSSDEBUG 65 if (!pError) { 66 return (nssCKFWHash *)NULL; 67 } 68 69 if (PR_SUCCESS != nssArena_verifyPointer(arena)) { 70 *pError = CKR_ARGUMENTS_BAD; 71 return (nssCKFWHash *)NULL; 72 } 73 #endif /* NSSDEBUG */ 74 75 rv = nss_ZNEW(arena, nssCKFWHash); 76 if (!rv) { 77 *pError = CKR_HOST_MEMORY; 78 return (nssCKFWHash *)NULL; 79 } 80 81 rv->mutex = nssCKFWInstance_CreateMutex(fwInstance, arena, pError); 82 if (!rv->mutex) { 83 if (CKR_OK == *pError) { 84 *pError = CKR_GENERAL_ERROR; 85 } 86 (void)nss_ZFreeIf(rv); 87 return (nssCKFWHash *)NULL; 88 } 89 90 rv->plHashTable = PL_NewHashTable(0, nss_ckfw_identity_hash, 91 PL_CompareValues, PL_CompareValues, &nssArenaHashAllocOps, arena); 92 if (!rv->plHashTable) { 93 (void)nssCKFWMutex_Destroy(rv->mutex); 94 (void)nss_ZFreeIf(rv); 95 *pError = CKR_HOST_MEMORY; 96 return (nssCKFWHash *)NULL; 97 } 98 99 rv->count = 0; 100 101 return rv; 102 } 103 104 /* 105 * nssCKFWHash_Destroy 106 * 107 */ 108 NSS_IMPLEMENT void 109 nssCKFWHash_Destroy( 110 nssCKFWHash *hash) 111 { 112 (void)nssCKFWMutex_Destroy(hash->mutex); 113 PL_HashTableDestroy(hash->plHashTable); 114 (void)nss_ZFreeIf(hash); 115 } 116 117 /* 118 * nssCKFWHash_Add 119 * 120 */ 121 NSS_IMPLEMENT CK_RV 122 nssCKFWHash_Add( 123 nssCKFWHash *hash, 124 const void *key, 125 const void *value) 126 { 127 CK_RV error = CKR_OK; 128 PLHashEntry *he; 129 130 error = nssCKFWMutex_Lock(hash->mutex); 131 if (CKR_OK != error) { 132 return error; 133 } 134 135 he = PL_HashTableAdd(hash->plHashTable, key, (void *)value); 136 if (!he) { 137 error = CKR_HOST_MEMORY; 138 } else { 139 hash->count++; 140 } 141 142 (void)nssCKFWMutex_Unlock(hash->mutex); 143 144 return error; 145 } 146 147 /* 148 * nssCKFWHash_Remove 149 * 150 */ 151 NSS_IMPLEMENT void 152 nssCKFWHash_Remove( 153 nssCKFWHash *hash, 154 const void *it) 155 { 156 PRBool found; 157 158 if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) { 159 return; 160 } 161 162 found = PL_HashTableRemove(hash->plHashTable, it); 163 if (found) { 164 hash->count--; 165 } 166 167 (void)nssCKFWMutex_Unlock(hash->mutex); 168 return; 169 } 170 171 /* 172 * nssCKFWHash_Count 173 * 174 */ 175 NSS_IMPLEMENT CK_ULONG 176 nssCKFWHash_Count( 177 nssCKFWHash *hash) 178 { 179 CK_ULONG count; 180 181 if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) { 182 return (CK_ULONG)0; 183 } 184 185 count = hash->count; 186 187 (void)nssCKFWMutex_Unlock(hash->mutex); 188 189 return count; 190 } 191 192 /* 193 * nssCKFWHash_Exists 194 * 195 */ 196 NSS_IMPLEMENT CK_BBOOL 197 nssCKFWHash_Exists( 198 nssCKFWHash *hash, 199 const void *it) 200 { 201 void *value; 202 203 if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) { 204 return CK_FALSE; 205 } 206 207 value = PL_HashTableLookup(hash->plHashTable, it); 208 209 (void)nssCKFWMutex_Unlock(hash->mutex); 210 211 if (!value) { 212 return CK_FALSE; 213 } else { 214 return CK_TRUE; 215 } 216 } 217 218 /* 219 * nssCKFWHash_Lookup 220 * 221 */ 222 NSS_IMPLEMENT void * 223 nssCKFWHash_Lookup( 224 nssCKFWHash *hash, 225 const void *it) 226 { 227 void *rv; 228 229 if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) { 230 return (void *)NULL; 231 } 232 233 rv = PL_HashTableLookup(hash->plHashTable, it); 234 235 (void)nssCKFWMutex_Unlock(hash->mutex); 236 237 return rv; 238 } 239 240 struct arg_str { 241 nssCKFWHashIterator fcn; 242 void *closure; 243 }; 244 245 static PRIntn 246 nss_ckfwhash_enumerator( 247 PLHashEntry *he, 248 PRIntn index, 249 void *arg) 250 { 251 struct arg_str *as = (struct arg_str *)arg; 252 as->fcn(he->key, he->value, as->closure); 253 return HT_ENUMERATE_NEXT; 254 } 255 256 /* 257 * nssCKFWHash_Iterate 258 * 259 * NOTE that the iteration function will be called with the hashtable locked. 260 */ 261 NSS_IMPLEMENT void 262 nssCKFWHash_Iterate( 263 nssCKFWHash *hash, 264 nssCKFWHashIterator fcn, 265 void *closure) 266 { 267 struct arg_str as; 268 as.fcn = fcn; 269 as.closure = closure; 270 271 if (CKR_OK != nssCKFWMutex_Lock(hash->mutex)) { 272 return; 273 } 274 275 PL_HashTableEnumerateEntries(hash->plHashTable, nss_ckfwhash_enumerator, &as); 276 277 (void)nssCKFWMutex_Unlock(hash->mutex); 278 279 return; 280 }