diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c')
-rw-r--r-- | security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c new file mode 100644 index 0000000000..260365375e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c @@ -0,0 +1,383 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_hashtable.c + * + * Hashtable Object Functions + * + */ + +#include "pkix_pl_hashtable.h" + +/* --Private-Structure-------------------------------------------- */ + +struct PKIX_PL_HashTableStruct { + pkix_pl_PrimHashTable *primHash; + PKIX_PL_Mutex *tableLock; + PKIX_UInt32 maxEntriesPerBucket; +}; + +/* --Private-Functions-------------------------------------------- */ + +#define PKIX_MUTEX_UNLOCK(mutex) \ + do { \ + if (mutex && lockedMutex == (PKIX_PL_Mutex *)(mutex)) { \ + pkixTempResult = \ + PKIX_PL_Mutex_Unlock((mutex), plContext); \ + PORT_Assert(pkixTempResult == NULL); \ + if (pkixTempResult) { \ + PKIX_DoAddError(&stdVars, pkixTempResult, plContext); \ + pkixTempResult = NULL; \ + } \ + lockedMutex = NULL; \ + } else { \ + PORT_Assert(lockedMutex == NULL); \ + }\ + } while (0) + + +#define PKIX_MUTEX_LOCK(mutex) \ + do { \ + if (mutex){ \ + PORT_Assert(lockedMutex == NULL); \ + PKIX_CHECK(PKIX_PL_Mutex_Lock((mutex), plContext), \ + PKIX_MUTEXLOCKFAILED); \ + lockedMutex = (mutex); \ + } \ + } while (0) + +/* + * FUNCTION: pkix_pl_HashTable_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_HashTable_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_HashTable *ht = NULL; + pkix_pl_HT_Elem *item = NULL; + PKIX_UInt32 i; + + PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_HASHTABLE_TYPE, plContext), + PKIX_OBJECTNOTHASHTABLE); + + ht = (PKIX_PL_HashTable*) object; + + /* DecRef every object in the primitive hash table */ + for (i = 0; i < ht->primHash->size; i++) { + for (item = ht->primHash->buckets[i]; + item != NULL; + item = item->next) { + PKIX_DECREF(item->key); + PKIX_DECREF(item->value); + } + } + + PKIX_CHECK(pkix_pl_PrimHashTable_Destroy(ht->primHash, plContext), + PKIX_PRIMHASHTABLEDESTROYFAILED); + + PKIX_DECREF(ht->tableLock); + +cleanup: + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: pkix_pl_HashTable_RegisterSelf + * DESCRIPTION: + * Registers PKIX_HASHTABLE_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + */ +PKIX_Error * +pkix_pl_HashTable_RegisterSelf( + void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_RegisterSelf"); + + entry.description = "HashTable"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_HashTable); + entry.destructor = pkix_pl_HashTable_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_HASHTABLE_TYPE] = entry; + + PKIX_RETURN(HASHTABLE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_HashTable_Create (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Create( + PKIX_UInt32 numBuckets, + PKIX_UInt32 maxEntriesPerBucket, + PKIX_PL_HashTable **pResult, + void *plContext) +{ + PKIX_PL_HashTable *hashTable = NULL; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Create"); + PKIX_NULLCHECK_ONE(pResult); + + if (numBuckets == 0) { + PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO); + } + + /* Allocate a new hashtable */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_HASHTABLE_TYPE, + sizeof (PKIX_PL_HashTable), + (PKIX_PL_Object **)&hashTable, + plContext), + PKIX_COULDNOTCREATEHASHTABLEOBJECT); + + /* Create the underlying primitive hash table type */ + PKIX_CHECK(pkix_pl_PrimHashTable_Create + (numBuckets, &hashTable->primHash, plContext), + PKIX_PRIMHASHTABLECREATEFAILED); + + /* Create a lock for this table */ + PKIX_CHECK(PKIX_PL_Mutex_Create(&hashTable->tableLock, plContext), + PKIX_ERRORCREATINGTABLELOCK); + + hashTable->maxEntriesPerBucket = maxEntriesPerBucket; + + *pResult = hashTable; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(hashTable); + } + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Add (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Add( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + PKIX_PL_Object *value, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_PL_Object *deletedKey = NULL; + PKIX_PL_Object *deletedValue = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + PKIX_UInt32 bucketSize = 0; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Add"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_THREE(ht, key, value); +#else + PKIX_NULLCHECK_TWO(key, value); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + /* Insert into primitive hashtable */ + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + PKIX_CHECK(pkix_pl_PrimHashTable_GetBucketSize + (ht->primHash, + hashCode, + &bucketSize, + plContext), + PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED); + + if (ht->maxEntriesPerBucket != 0 && + bucketSize >= ht->maxEntriesPerBucket) { + /* drop the last one in the bucket */ + PKIX_CHECK(pkix_pl_PrimHashTable_RemoveFIFO + (ht->primHash, + hashCode, + (void **) &deletedKey, + (void **) &deletedValue, + plContext), + PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED); + PKIX_DECREF(deletedKey); + PKIX_DECREF(deletedValue); + } + + PKIX_CHECK(pkix_pl_PrimHashTable_Add + (ht->primHash, + (void *)key, + (void *)value, + hashCode, + keyComp, + plContext), + PKIX_PRIMHASHTABLEADDFAILED); + + PKIX_INCREF(key); + PKIX_INCREF(value); + PKIX_MUTEX_UNLOCK(ht->tableLock); + + /* + * we don't call PKIX_PL_InvalidateCache here b/c we have + * not implemented toString or hashcode for this Object + */ + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Remove (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Remove( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_PL_Object *origKey = NULL; + PKIX_PL_Object *value = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Remove"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_TWO(ht, key); +#else + PKIX_NULLCHECK_ONE(key); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + /* Remove from primitive hashtable */ + PKIX_CHECK(pkix_pl_PrimHashTable_Remove + (ht->primHash, + (void *)key, + hashCode, + keyComp, + (void **)&origKey, + (void **)&value, + plContext), + PKIX_PRIMHASHTABLEREMOVEFAILED); + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_DECREF(origKey); + PKIX_DECREF(value); + + /* + * we don't call PKIX_PL_InvalidateCache here b/c we have + * not implemented toString or hashcode for this Object + */ + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} + +/* + * FUNCTION: PKIX_PL_HashTable_Lookup (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_HashTable_Lookup( + PKIX_PL_HashTable *ht, + PKIX_PL_Object *key, + PKIX_PL_Object **pResult, + void *plContext) +{ + PKIX_PL_Mutex *lockedMutex = NULL; + PKIX_UInt32 hashCode; + PKIX_PL_EqualsCallback keyComp; + PKIX_PL_Object *result = NULL; + + PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Lookup"); + +#if !defined(PKIX_OBJECT_LEAK_TEST) + PKIX_NULLCHECK_THREE(ht, key, pResult); +#else + PKIX_NULLCHECK_TWO(key, pResult); + + if (ht == NULL) { + PKIX_RETURN(HASHTABLE); + } +#endif + + PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext), + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback + (key, &keyComp, plContext), + PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED); + + PKIX_MUTEX_LOCK(ht->tableLock); + + /* Lookup in primitive hashtable */ + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (ht->primHash, + (void *)key, + hashCode, + keyComp, + (void **)&result, + plContext), + PKIX_PRIMHASHTABLELOOKUPFAILED); + + PKIX_INCREF(result); + PKIX_MUTEX_UNLOCK(ht->tableLock); + + *pResult = result; + +cleanup: + + PKIX_MUTEX_UNLOCK(ht->tableLock); + + PKIX_RETURN(HASHTABLE); +} |