Esempio n. 1
0
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);
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}