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