andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: * hash.c andre@0: * andre@0: * This is merely a couple wrappers around NSPR's PLHashTable, using andre@0: * the identity hash and arena-aware allocators. The reason I did andre@0: * this is that hash tables are used in a few places throughout the andre@0: * NSS Cryptoki Framework in a fairly stereotyped way, and this allows andre@0: * me to pull the commonalities into one place. Should we ever want andre@0: * to change the implementation, it's all right here. andre@0: */ andre@0: andre@0: #ifndef CK_T andre@0: #include "ck.h" andre@0: #endif /* CK_T */ andre@0: andre@0: /* andre@0: * nssCKFWHash andre@0: * andre@0: * nssCKFWHash_Create andre@0: * nssCKFWHash_Destroy andre@0: * nssCKFWHash_Add andre@0: * nssCKFWHash_Remove andre@0: * nssCKFWHash_Count andre@0: * nssCKFWHash_Exists andre@0: * nssCKFWHash_Lookup andre@0: * nssCKFWHash_Iterate andre@0: */ andre@0: andre@0: struct nssCKFWHashStr { andre@0: NSSCKFWMutex *mutex; andre@0: andre@0: /* andre@0: * The invariant that mutex protects is: andre@0: * The count accurately reflects the hashtable state. andre@0: */ andre@0: andre@0: PLHashTable *plHashTable; andre@0: CK_ULONG count; andre@0: }; andre@0: andre@0: static PLHashNumber andre@0: nss_ckfw_identity_hash andre@0: ( andre@0: const void *key andre@0: ) andre@0: { andre@0: PRUint32 i = (PRUint32)key; andre@0: PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32)); andre@0: return (PLHashNumber)i; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Create andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT nssCKFWHash * andre@0: nssCKFWHash_Create andre@0: ( andre@0: NSSCKFWInstance *fwInstance, andre@0: NSSArena *arena, andre@0: CK_RV *pError andre@0: ) andre@0: { andre@0: nssCKFWHash *rv; andre@0: andre@0: #ifdef NSSDEBUG andre@0: if (!pError) { andre@0: return (nssCKFWHash *)NULL; andre@0: } andre@0: andre@0: if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { andre@0: *pError = CKR_ARGUMENTS_BAD; andre@0: return (nssCKFWHash *)NULL; andre@0: } andre@0: #endif /* NSSDEBUG */ andre@0: andre@0: rv = nss_ZNEW(arena, nssCKFWHash); andre@0: if (!rv) { andre@0: *pError = CKR_HOST_MEMORY; andre@0: return (nssCKFWHash *)NULL; andre@0: } andre@0: andre@0: rv->mutex = nssCKFWInstance_CreateMutex(fwInstance, arena, pError); andre@0: if (!rv->mutex) { andre@0: if( CKR_OK == *pError ) { andre@0: (void)nss_ZFreeIf(rv); andre@0: *pError = CKR_GENERAL_ERROR; andre@0: } andre@0: return (nssCKFWHash *)NULL; andre@0: } andre@0: andre@0: rv->plHashTable = PL_NewHashTable(0, nss_ckfw_identity_hash, andre@0: PL_CompareValues, PL_CompareValues, &nssArenaHashAllocOps, arena); andre@0: if (!rv->plHashTable) { andre@0: (void)nssCKFWMutex_Destroy(rv->mutex); andre@0: (void)nss_ZFreeIf(rv); andre@0: *pError = CKR_HOST_MEMORY; andre@0: return (nssCKFWHash *)NULL; andre@0: } andre@0: andre@0: rv->count = 0; andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Destroy andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT void andre@0: nssCKFWHash_Destroy andre@0: ( andre@0: nssCKFWHash *hash andre@0: ) andre@0: { andre@0: (void)nssCKFWMutex_Destroy(hash->mutex); andre@0: PL_HashTableDestroy(hash->plHashTable); andre@0: (void)nss_ZFreeIf(hash); andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Add andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT CK_RV andre@0: nssCKFWHash_Add andre@0: ( andre@0: nssCKFWHash *hash, andre@0: const void *key, andre@0: const void *value andre@0: ) andre@0: { andre@0: CK_RV error = CKR_OK; andre@0: PLHashEntry *he; andre@0: andre@0: error = nssCKFWMutex_Lock(hash->mutex); andre@0: if( CKR_OK != error ) { andre@0: return error; andre@0: } andre@0: andre@0: he = PL_HashTableAdd(hash->plHashTable, key, (void *)value); andre@0: if (!he) { andre@0: error = CKR_HOST_MEMORY; andre@0: } else { andre@0: hash->count++; andre@0: } andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: andre@0: return error; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Remove andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT void andre@0: nssCKFWHash_Remove andre@0: ( andre@0: nssCKFWHash *hash, andre@0: const void *it andre@0: ) andre@0: { andre@0: PRBool found; andre@0: andre@0: if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { andre@0: return; andre@0: } andre@0: andre@0: found = PL_HashTableRemove(hash->plHashTable, it); andre@0: if( found ) { andre@0: hash->count--; andre@0: } andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: return; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Count andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT CK_ULONG andre@0: nssCKFWHash_Count andre@0: ( andre@0: nssCKFWHash *hash andre@0: ) andre@0: { andre@0: CK_ULONG count; andre@0: andre@0: if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { andre@0: return (CK_ULONG)0; andre@0: } andre@0: andre@0: count = hash->count; andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: andre@0: return count; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Exists andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT CK_BBOOL andre@0: nssCKFWHash_Exists andre@0: ( andre@0: nssCKFWHash *hash, andre@0: const void *it andre@0: ) andre@0: { andre@0: void *value; andre@0: andre@0: if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { andre@0: return CK_FALSE; andre@0: } andre@0: andre@0: value = PL_HashTableLookup(hash->plHashTable, it); andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: andre@0: if (!value) { andre@0: return CK_FALSE; andre@0: } else { andre@0: return CK_TRUE; andre@0: } andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Lookup andre@0: * andre@0: */ andre@0: NSS_IMPLEMENT void * andre@0: nssCKFWHash_Lookup andre@0: ( andre@0: nssCKFWHash *hash, andre@0: const void *it andre@0: ) andre@0: { andre@0: void *rv; andre@0: andre@0: if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { andre@0: return (void *)NULL; andre@0: } andre@0: andre@0: rv = PL_HashTableLookup(hash->plHashTable, it); andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: struct arg_str { andre@0: nssCKFWHashIterator fcn; andre@0: void *closure; andre@0: }; andre@0: andre@0: static PRIntn andre@0: nss_ckfwhash_enumerator andre@0: ( andre@0: PLHashEntry *he, andre@0: PRIntn index, andre@0: void *arg andre@0: ) andre@0: { andre@0: struct arg_str *as = (struct arg_str *)arg; andre@0: as->fcn(he->key, he->value, as->closure); andre@0: return HT_ENUMERATE_NEXT; andre@0: } andre@0: andre@0: /* andre@0: * nssCKFWHash_Iterate andre@0: * andre@0: * NOTE that the iteration function will be called with the hashtable locked. andre@0: */ andre@0: NSS_IMPLEMENT void andre@0: nssCKFWHash_Iterate andre@0: ( andre@0: nssCKFWHash *hash, andre@0: nssCKFWHashIterator fcn, andre@0: void *closure andre@0: ) andre@0: { andre@0: struct arg_str as; andre@0: as.fcn = fcn; andre@0: as.closure = closure; andre@0: andre@0: if( CKR_OK != nssCKFWMutex_Lock(hash->mutex) ) { andre@0: return; andre@0: } andre@0: andre@0: PL_HashTableEnumerateEntries(hash->plHashTable, nss_ckfwhash_enumerator, &as); andre@0: andre@0: (void)nssCKFWMutex_Unlock(hash->mutex); andre@0: andre@0: return; andre@0: }