void Tcl_InitHashTable( register Tcl_HashTable *tablePtr, /* Pointer to table record, which is supplied * by the caller. */ int keyType) /* Type of keys to use in table: * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, or an * integer >= 2. */ { /* * Use a special value to inform the extended version that it must not * access any of the new fields in the Tcl_HashTable. If an extension is * rebuilt then any calls to this function will be redirected to the * extended version by a macro. */ Tcl_InitCustomHashTable(tablePtr, keyType, (const Tcl_HashKeyType *) -1); }
void TclInitThreadStorage(void) { Tcl_InitCustomHashTable(&threadStorageHashTable, TCL_CUSTOM_TYPE_KEYS, &tclThreadStorageHashKeyType); /* * We also initialize the cache. */ memset((void*) &threadStorageCache, 0, sizeof(ThreadStorage) * STORAGE_CACHE_SLOTS); /* * Now, we set the first value to be used for a thread data key. */ nextThreadStorageKey = STORAGE_FIRST_KEY; }
static Tcl_HashTable * ThreadStorageGetHashTable( Tcl_ThreadId id) /* Id of thread to get hash table for */ { int index = PTR2UINT(id) % STORAGE_CACHE_SLOTS; Tcl_HashEntry *hPtr; int isNew; Tcl_HashTable *hashTablePtr; /* * It's important that we pick up the hash table pointer BEFORE comparing * thread Id in case another thread is in the critical region changing * things out from under you. * * Thread safety: threadStorageCache is accessed w/o locks in order to * avoid serialization of all threads at this hot-spot. It is safe to * do this here because (threadStorageCache[index].id != id) test below * should be atomic on all (currently) supported platforms and there * are no devastatig side effects of the test. * * Note Valgrind users: this place will show up as a race-condition in * helgrind-tool output. To silence this warnings, define VALGRIND * symbol at compilation time. */ #if !defined(VALGRIND) hashTablePtr = threadStorageCache[index].hashTablePtr; if (threadStorageCache[index].id != id) { Tcl_MutexLock(&threadStorageLock); #else Tcl_MutexLock(&threadStorageLock); hashTablePtr = threadStorageCache[index].hashTablePtr; if (threadStorageCache[index].id != id) { #endif /* * It's not in the cache, so we look it up... */ hPtr = Tcl_FindHashEntry(&threadStorageHashTable, (char *) id); if (hPtr != NULL) { /* * We found it, extract the hash table pointer. */ hashTablePtr = Tcl_GetHashValue(hPtr); } else { /* * The thread specific hash table is not found. */ hashTablePtr = NULL; } if (hashTablePtr == NULL) { hashTablePtr = (Tcl_HashTable *) TclpSysAlloc(sizeof(Tcl_HashTable), 0); if (hashTablePtr == NULL) { Tcl_Panic("could not allocate thread specific hash table, " "TclpSysAlloc failed from ThreadStorageGetHashTable!"); } Tcl_InitCustomHashTable(hashTablePtr, TCL_CUSTOM_TYPE_KEYS, &tclThreadStorageHashKeyType); /* * Add new thread storage hash table to the master hash table. */ hPtr = Tcl_CreateHashEntry(&threadStorageHashTable, (char *) id, &isNew); if (hPtr == NULL) { Tcl_Panic("Tcl_CreateHashEntry failed from " "ThreadStorageGetHashTable!"); } Tcl_SetHashValue(hPtr, hashTablePtr); } /* * Now, we put it in the cache since it is highly likely it will be * needed again shortly. */ threadStorageCache[index].id = id; threadStorageCache[index].hashTablePtr = hashTablePtr; #if !defined(VALGRIND) Tcl_MutexUnlock(&threadStorageLock); } #else } Tcl_MutexUnlock(&threadStorageLock); #endif return hashTablePtr; }
static Tcl_HashTable * ThreadStorageGetHashTable( Tcl_ThreadId id) /* Id of thread to get hash table for */ { int index = PTR2UINT(id) % STORAGE_CACHE_SLOTS; Tcl_HashEntry *hPtr; int isNew; /* * It's important that we pick up the hash table pointer BEFORE comparing * thread Id in case another thread is in the critical region changing * things out from under you. */ Tcl_HashTable *hashTablePtr = threadStorageCache[index].hashTablePtr; if (threadStorageCache[index].id != id) { Tcl_MutexLock(&threadStorageLock); /* * It's not in the cache, so we look it up... */ hPtr = Tcl_FindHashEntry(&threadStorageHashTable, (char *) id); if (hPtr != NULL) { /* * We found it, extract the hash table pointer. */ hashTablePtr = Tcl_GetHashValue(hPtr); } else { /* * The thread specific hash table is not found. */ hashTablePtr = NULL; } if (hashTablePtr == NULL) { hashTablePtr = (Tcl_HashTable *) TclpSysAlloc(sizeof(Tcl_HashTable), 0); if (hashTablePtr == NULL) { Tcl_Panic("could not allocate thread specific hash table, " "TclpSysAlloc failed from ThreadStorageGetHashTable!"); } Tcl_InitCustomHashTable(hashTablePtr, TCL_CUSTOM_TYPE_KEYS, &tclThreadStorageHashKeyType); /* * Add new thread storage hash table to the master hash table. */ hPtr = Tcl_CreateHashEntry(&threadStorageHashTable, (char *) id, &isNew); if (hPtr == NULL) { Tcl_Panic("Tcl_CreateHashEntry failed from " "ThreadStorageGetHashTable!"); } Tcl_SetHashValue(hPtr, hashTablePtr); } /* * Now, we put it in the cache since it is highly likely it will be * needed again shortly. */ threadStorageCache[index].id = id; threadStorageCache[index].hashTablePtr = hashTablePtr; Tcl_MutexUnlock(&threadStorageLock); } return hashTablePtr; }