summaryrefslogtreecommitdiffstats
path: root/generic/tclThreadStorage.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclThreadStorage.c')
-rw-r--r--generic/tclThreadStorage.c286
1 files changed, 149 insertions, 137 deletions
diff --git a/generic/tclThreadStorage.c b/generic/tclThreadStorage.c
index 7eb66be..09aa125 100644
--- a/generic/tclThreadStorage.c
+++ b/generic/tclThreadStorage.c
@@ -5,10 +5,10 @@
*
* Copyright (c) 2003-2004 by Joe Mistachkin
*
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclThreadStorage.c,v 1.4 2004/06/24 09:05:46 dkf Exp $
+ * RCS: @(#) $Id: tclThreadStorage.c,v 1.5 2005/07/19 22:45:35 dkf Exp $
*/
#include "tclInt.h"
@@ -16,29 +16,28 @@
#if defined(TCL_THREADS) && defined(USE_THREAD_STORAGE)
/*
- * This is the thread storage cache array and it's accompanying mutex.
- * The elements are pairs of thread Id and an associated hash table
- * pointer; the hash table being pointed to contains the thread storage
- * for it's associated thread. The purpose of this cache is to minimize
- * the number of hash table lookups in the master thread storage hash
- * table.
+ * This is the thread storage cache array and it's accompanying mutex. The
+ * elements are pairs of thread Id and an associated hash table pointer; the
+ * hash table being pointed to contains the thread storage for it's associated
+ * thread. The purpose of this cache is to minimize the number of hash table
+ * lookups in the master thread storage hash table.
*/
static Tcl_Mutex threadStorageLock;
/*
- * This is the struct used for a thread storage cache slot. It contains
- * the owning thread Id and the associated hash table pointer.
+ * This is the struct used for a thread storage cache slot. It contains the
+ * owning thread Id and the associated hash table pointer.
*/
typedef struct ThreadStorage {
- Tcl_ThreadId id; /* the owning thread id */
- Tcl_HashTable *hashTablePtr; /* the hash table for the thread */
+ Tcl_ThreadId id; /* the owning thread id */
+ Tcl_HashTable *hashTablePtr;/* the hash table for the thread */
} ThreadStorage;
/*
- * These are the prototypes for the custom hash table allocation
- * functions used by the thread storage subsystem.
+ * These are the prototypes for the custom hash table allocation functions
+ * used by the thread storage subsystem.
*/
static Tcl_HashEntry * AllocThreadStorageEntry _ANSI_ARGS_((
@@ -51,6 +50,7 @@ static void FreeThreadStorageEntry _ANSI_ARGS_((
* combination with the new hash key type flag TCL_HASH_KEY_SYSTEM_HASH
* because these hash tables MAY be used by the threaded memory allocator.
*/
+
Tcl_HashKeyType tclThreadStorageHashKeyType = {
TCL_HASH_KEY_TYPE_VERSION, /* version */
TCL_HASH_KEY_SYSTEM_HASH, /* flags */
@@ -73,31 +73,30 @@ Tcl_HashKeyType tclThreadStorageHashKeyType = {
#define STORAGE_INVALID_KEY 0
/*
- * This is the first valid key for use by external callers.
- * All the values below this are RESERVED for future use.
+ * This is the first valid key for use by external callers. All the values
+ * below this are RESERVED for future use.
*/
#define STORAGE_FIRST_KEY 101
/*
- * This is the default number of thread storage cache slots.
- * This define may need to be fine tuned for maximum performance.
+ * This is the default number of thread storage cache slots. This define may
+ * need to be fine tuned for maximum performance.
*/
#define STORAGE_CACHE_SLOTS 97
/*
- * This is the master thread storage hash table. It is keyed on
- * thread Id and contains values that are hash tables for each thread.
- * The thread specific hash tables contain the actual thread storage.
+ * This is the master thread storage hash table. It is keyed on thread Id and
+ * contains values that are hash tables for each thread. The thread specific
+ * hash tables contain the actual thread storage.
*/
static Tcl_HashTable *threadStorageHashTablePtr = NULL;
/*
- * This is the next thread data key value to use. We increment this
- * everytime we "allocate" one. It is initially set to 1 in
- * TclThreadStorageInit.
+ * This is the next thread data key value to use. We increment this everytime
+ * we "allocate" one. It is initially set to 1 in TclThreadStorageInit.
*/
static int nextThreadStorageKey = STORAGE_INVALID_KEY;
@@ -109,9 +108,8 @@ static int nextThreadStorageKey = STORAGE_INVALID_KEY;
static int initThreadStorage = 0;
/*
- * This is the master thread storage cache. Per kennykb's idea, this
- * prevents unnecessary lookups for threads that use a lot of thread
- * storage.
+ * This is the master thread storage cache. Per Kevin Kenny's idea, this
+ * prevents unnecessary lookups for threads that use a lot of thread storage.
*/
static volatile ThreadStorage threadStorageCache[STORAGE_CACHE_SLOTS];
@@ -121,15 +119,15 @@ static volatile ThreadStorage threadStorageCache[STORAGE_CACHE_SLOTS];
*
* TclThreadStorageLockInit
*
- * This procedure is used to initialize the lock that serializes
- * creation of thread storage.
+ * This procedure is used to initialize the lock that serializes creation
+ * of thread storage.
*
* Results:
* None.
*
* Side effects:
- * The master lock is acquired and possibly initialized for the
- * first time.
+ * The master lock is acquired and possibly initialized for the first
+ * time.
*
*----------------------------------------------------------------------
*/
@@ -139,10 +137,11 @@ TclThreadStorageLockInit()
{
if (!initThreadStorage) {
/*
- * Mutexes in Tcl are self initializing, and we are taking
- * advantage of that fact since this file cannot contain
- * platform specific calls.
+ * Mutexes in Tcl are self initializing, and we are taking advantage
+ * of that fact since this file cannot contain platform specific
+ * calls.
*/
+
initThreadStorage = 1;
}
}
@@ -152,11 +151,11 @@ TclThreadStorageLockInit()
*
* TclThreadStorageLock
*
- * This procedure is used to grab a lock that serializes creation
- * of thread storage.
+ * This procedure is used to grab a lock that serializes creation of
+ * thread storage.
*
- * This lock must be different than the initLock because the
- * initLock is held during creation of syncronization objects.
+ * This lock must be different than the initLock because the initLock is
+ * held during creation of syncronization objects.
*
* Results:
* None.
@@ -179,8 +178,8 @@ TclThreadStorageLock()
*
* TclThreadStorageUnlock
*
- * This procedure is used to release a lock that serializes creation
- * of thread storage.
+ * This procedure is used to release a lock that serializes creation of
+ * thread storage.
*
* Results:
* None.
@@ -202,9 +201,9 @@ TclThreadStorageUnlock()
*
* AllocThreadStorageEntry --
*
- * Allocate space for a Tcl_HashEntry using TclpSysAlloc (not
- * ckalloc). We do this because the threaded memory allocator MAY
- * use the thread storage hash tables.
+ * Allocate space for a Tcl_HashEntry using TclpSysAlloc (not ckalloc).
+ * We do this because the threaded memory allocator MAY use the thread
+ * storage hash tables.
*
* Results:
* The return value is a pointer to the created entry.
@@ -233,9 +232,9 @@ AllocThreadStorageEntry(tablePtr, keyPtr)
*
* FreeThreadStorageEntry --
*
- * Frees space for a Tcl_HashEntry using TclpSysFree (not ckfree).
- * We do this because the threaded memory allocator MAY use the
- * thread storage hash tables.
+ * Frees space for a Tcl_HashEntry using TclpSysFree (not ckfree). We do
+ * this because the threaded memory allocator MAY use the thread storage
+ * hash tables.
*
* Results:
* None.
@@ -258,9 +257,9 @@ FreeThreadStorageEntry(hPtr)
*
* TclThreadStoragePrint --
*
- * This procedure prints out the contents of the master thread
- * storage hash table, the thread storage cache, and the next key
- * value to the specified file.
+ * This procedure prints out the contents of the master thread storage
+ * hash table, the thread storage cache, and the next key value to the
+ * specified file.
*
* This assumes that thread storage lock is held.
*
@@ -303,7 +302,7 @@ TclThreadStoragePrint(outFile, flags)
}
header = 0; /* we have not output the header yet. */
- for (index = 0; index < STORAGE_CACHE_SLOTS; index++) {
+ for (index=0 ; index<STORAGE_CACHE_SLOTS ; index++) {
if (threadStorageCache[index].id != STORAGE_INVALID_THREAD) {
if (!header) {
fprintf(outFile, "thread storage cache (%d total slots):\n",
@@ -314,12 +313,14 @@ TclThreadStoragePrint(outFile, flags)
fprintf(outFile, "slot %d, thread %p, thread table ptr %p\n",
index, threadStorageCache[index].id,
threadStorageCache[index].hashTablePtr);
+
#ifdef VERBOSE_THREAD_STORAGE_DEBUGGING
/*
- * Currently not enabled by default due to Tcl_HashStats
- * use of ckalloc and ckfree. Please note that this can
- * produce a LOT of output.
+ * Currently not enabled by default due to Tcl_HashStats use of
+ * ckalloc and ckfree. Please note that this can produce a LOT of
+ * output.
*/
+
if (threadStorageCache[index].hashTablePtr != NULL) {
CONST char *stats =
Tcl_HashStats(threadStorageCache[index].hashTablePtr);
@@ -333,6 +334,7 @@ TclThreadStoragePrint(outFile, flags)
}
}
#endif
+
} else {
/* fprintf(outFile, "cache slot %d not used\n", index); */
}
@@ -362,12 +364,12 @@ TclThreadStoragePrint(outFile, flags)
* This assumes that thread storage lock is held.
*
* Results:
- * A hash table pointer for the specified thread, or NULL
- * if the hash table has not been created yet.
+ * A hash table pointer for the specified thread, or NULL if the hash
+ * table has not been created yet.
*
* Side effects:
- * May change an entry in the master thread storage cache to point
- * to the specified thread and it's associated hash table.
+ * May change an entry in the master thread storage cache to point to the
+ * specified thread and it's associated hash table.
*
*----------------------------------------------------------------------
*/
@@ -381,9 +383,9 @@ TclThreadStorageGetHashTable(id)
int new;
/*
- * 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.
+ * 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;
@@ -408,11 +410,13 @@ TclThreadStorageGetHashTable(id)
/*
* We found it, extract the hash table pointer.
*/
+
hashTablePtr = Tcl_GetHashValue(hPtr);
} else {
/*
* The thread specific hash table is not found.
*/
+
hashTablePtr = NULL;
}
@@ -429,8 +433,7 @@ TclThreadStorageGetHashTable(id)
&tclThreadStorageHashKeyType);
/*
- * Add new thread storage hash table to the master
- * hash table.
+ * Add new thread storage hash table to the master hash table.
*/
hPtr = Tcl_CreateHashEntry(threadStorageHashTablePtr,
@@ -444,17 +447,18 @@ TclThreadStorageGetHashTable(id)
}
/*
- * Now, we put it in the cache since it is highly likely
- * it will be needed again shortly.
+ * 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;
} else {
/*
- * We cannot look it up, the master hash table has not
- * been initialized.
+ * We cannot look it up, the master hash table has not been
+ * initialized.
*/
+
hashTablePtr = NULL;
}
TclThreadStorageUnlock();
@@ -475,8 +479,8 @@ TclThreadStorageGetHashTable(id)
* This assumes that thread storage lock is held.
*
* Results:
- * A hash table pointer for the specified thread, or NULL if we are
- * be called to initialize the master hash table only.
+ * A hash table pointer for the specified thread, or NULL if we are be
+ * called to initialize the master hash table only.
*
* Side effects:
* The thread specific hash table may be initialized and added to the
@@ -496,8 +500,8 @@ TclThreadStorageInit(id, reserved)
if (threadStorageHashTablePtr == NULL) {
/*
- * Looks like we haven't created the outer hash table yet we
- * can just do that now.
+ * Looks like we haven't created the outer hash table yet we can just
+ * do that now.
*/
threadStorageHashTablePtr = (Tcl_HashTable *)
@@ -531,30 +535,29 @@ TclThreadStorageInit(id, reserved)
*
* TclThreadStorageDataKeyInit --
*
- * This procedure initializes a thread specific data block key.
- * Each thread has table of pointers to thread specific data.
- * all threads agree on which table entry is used by each module.
- * this is remembered in a "data key", that is just an index into
- * this table. To allow self initialization, the interface
- * passes a pointer to this key and the first thread to use
- * the key fills in the pointer to the key. The key should be
- * a process-wide static.
+ * This procedure initializes a thread specific data block key. Each
+ * thread has table of pointers to thread specific data. all threads
+ * agree on which table entry is used by each module. this is remembered
+ * in a "data key", that is just an index into this table. To allow self
+ * initialization, the interface passes a pointer to this key and the
+ * first thread to use the key fills in the pointer to the key. The key
+ * should be a process-wide static.
*
* Results:
* None.
*
* Side effects:
- * Will allocate memory the first time this process calls for
- * this key. In this case it modifies its argument
- * to hold the pointer to information about the key.
+ * Will allocate memory the first time this process calls for this key.
+ * In this case it modifies its argument to hold the pointer to
+ * information about the key.
*
*----------------------------------------------------------------------
*/
void
TclThreadStorageDataKeyInit(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (int **) */
+ Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, really
+ * (int**) */
{
int *indexPtr;
int newKey;
@@ -566,8 +569,8 @@ TclThreadStorageDataKeyInit(keyPtr)
}
/*
- * We must call this now to make sure that
- * nextThreadStorageKey has a well defined value.
+ * We must call this now to make sure that nextThreadStorageKey has a
+ * well defined value.
*/
TclThreadStorageLock();
@@ -579,11 +582,11 @@ TclThreadStorageDataKeyInit(keyPtr)
TclThreadStorageInit(STORAGE_INVALID_THREAD, NULL);
/*
- * These data key values are sequentially assigned and we must
- * use the storage lock to prevent serious problems here.
- * Also note that the caller should NOT make any assumptions
- * about the provided values. In particular, we may need to
- * reserve some values in the future.
+ * These data key values are sequentially assigned and we must use the
+ * storage lock to prevent serious problems here. Also note that the
+ * caller should NOT make any assumptions about the provided
+ * values. In particular, we may need to reserve some values in the
+ * future.
*/
newKey = nextThreadStorageKey++;
@@ -603,8 +606,8 @@ TclThreadStorageDataKeyInit(keyPtr)
* This procedure returns a pointer to a block of thread local storage.
*
* Results:
- * A thread-specific pointer to the data structure, or NULL
- * if the memory has not been assigned to this key for this thread.
+ * A thread-specific pointer to the data structure, or NULL if the memory
+ * has not been assigned to this key for this thread.
*
* Side effects:
* None.
@@ -614,8 +617,8 @@ TclThreadStorageDataKeyInit(keyPtr)
void *
TclThreadStorageDataKeyGet(keyPtr)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (int **) */
+ Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, really
+ * (int**) */
{
int *indexPtr = *(int **)keyPtr;
@@ -631,12 +634,12 @@ TclThreadStorageDataKeyGet(keyPtr)
"TclThreadStorageDataKeyGet!");
}
- hPtr = Tcl_FindHashEntry(hashTablePtr, (char *)*indexPtr);
+ hPtr = Tcl_FindHashEntry(hashTablePtr, (char *) *indexPtr);
if (hPtr == NULL) {
return NULL;
}
- return (void *)Tcl_GetHashValue(hPtr);
+ return (void *) Tcl_GetHashValue(hPtr);
}
}
@@ -651,16 +654,16 @@ TclThreadStorageDataKeyGet(keyPtr)
* None.
*
* Side effects:
- * Sets up the thread so future calls to TclThreadStorageDataKeyGet
- * with this key will return the data pointer.
+ * Sets up the thread so future calls to TclThreadStorageDataKeyGet with
+ * this key will return the data pointer.
*
*----------------------------------------------------------------------
*/
void
TclThreadStorageDataKeySet(keyPtr, data)
- Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk,
- * really (pthread_key_t **) */
+ Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, really
+ * (pthread_key_t **) */
void *data; /* Thread local storage */
{
int *indexPtr = *(int **)keyPtr;
@@ -678,8 +681,10 @@ TclThreadStorageDataKeySet(keyPtr, data)
/*
* Does the item need to be created?
*/
+
if (hPtr == NULL) {
int new;
+
hPtr = Tcl_CreateHashEntry(hashTablePtr, (char *)*indexPtr, &new);
if (hPtr == NULL) {
Tcl_Panic("could not create hash entry value from "
@@ -709,12 +714,12 @@ TclThreadStorageDataKeySet(keyPtr, data)
void
TclFinalizeThreadStorageThread(id)
- Tcl_ThreadId id; /* Id of the thread to finalize */
+ Tcl_ThreadId id; /* Id of the thread to finalize. */
{
int index = (unsigned int)id % STORAGE_CACHE_SLOTS;
- Tcl_HashTable *hashTablePtr; /* Hash table for current thread */
+ Tcl_HashTable *hashTablePtr;/* Hash table for current thread. */
Tcl_HashEntry *hPtr; /* Hash entry for current thread in master
- * table */
+ * table. */
TclThreadStorageLock();
@@ -730,8 +735,7 @@ TclFinalizeThreadStorageThread(id)
if (hashTablePtr != NULL) {
/*
- * Delete thread specific hash table and free the
- * struct.
+ * Delete thread specific hash table and free the struct.
*/
Tcl_DeleteHashTable(hashTablePtr);
@@ -752,9 +756,8 @@ TclFinalizeThreadStorageThread(id)
if (threadStorageCache[index].id == id) {
/*
- * We do not step on another thread's cache entry. This is
- * especially important if we are creating and exiting a lot
- * of threads.
+ * We do not step on another thread's cache entry. This is especially
+ * important if we are creating and exiting a lot of threads.
*/
threadStorageCache[index].id = STORAGE_INVALID_THREAD;
@@ -769,8 +772,8 @@ TclFinalizeThreadStorageThread(id)
*
* TclFinalizeThreadStorage --
*
- * This procedure cleans up the master thread storage hash table,
- * all thread specific hash tables, and the thread storage cache.
+ * This procedure cleans up the master thread storage hash table, all
+ * thread specific hash tables, and the thread storage cache.
*
* Results:
* None.
@@ -794,9 +797,9 @@ TclFinalizeThreadStorage()
* master table. */
/*
- * We are going to delete the hash table for every thread now.
- * This hash table should be empty at this point, except for
- * one entry for the current thread.
+ * We are going to delete the hash table for every thread now. This
+ * hash table should be empty at this point, except for one entry for
+ * the current thread.
*/
for (hPtr = Tcl_FirstHashEntry(threadStorageHashTablePtr, &search);
@@ -838,8 +841,8 @@ TclFinalizeThreadStorage()
sizeof(ThreadStorage) * STORAGE_CACHE_SLOTS);
/*
- * Reset this to zero, it will be set to STORAGE_FIRST_KEY if the
- * thread storage subsystem gets reinitialized
+ * Reset this to zero, it will be set to STORAGE_FIRST_KEY if the thread
+ * storage subsystem gets reinitialized
*/
nextThreadStorageKey = STORAGE_INVALID_KEY;
@@ -852,8 +855,8 @@ TclFinalizeThreadStorage()
*
* TclFinalizeThreadStorageData --
*
- * This procedure cleans up the thread-local storage. This is
- * called once for each thread.
+ * This procedure cleans up the thread-local storage. This is called
+ * once for each thread.
*
* Results:
* None.
@@ -870,7 +873,7 @@ TclFinalizeThreadStorageData(keyPtr)
{
if (*keyPtr != NULL) {
Tcl_ThreadId id = Tcl_GetCurrentThread();
- Tcl_HashTable *hashTablePtr; /* Hash table for current thread */
+ Tcl_HashTable *hashTablePtr; /* Hash table for current thread. */
Tcl_HashEntry *hPtr; /* Hash entry for data key in current
* thread. */
int *indexPtr = *(int **)keyPtr;
@@ -887,9 +890,10 @@ TclFinalizeThreadStorageData(keyPtr)
if (result != NULL) {
/*
- * This must be ckfree because tclThread.c allocates
- * these using ckalloc.
+ * This must be ckfree because tclThread.c allocates these
+ * using ckalloc.
*/
+
ckfree((char *)result);
}
@@ -903,9 +907,9 @@ TclFinalizeThreadStorageData(keyPtr)
*
* TclFinalizeThreadStorageDataKey --
*
- * This procedure is invoked to clean up one key. This is a
- * process-wide storage identifier. The thread finalization code
- * cleans up the thread local storage itself.
+ * This procedure is invoked to clean up one key. This is a process-wide
+ * storage identifier. The thread finalization code cleans up the thread
+ * local storage itself.
*
* This assumes the master lock is held.
*
@@ -923,7 +927,7 @@ TclFinalizeThreadStorageDataKey(keyPtr)
Tcl_ThreadDataKey *keyPtr;
{
int *indexPtr;
- Tcl_HashTable *hashTablePtr;/* Hash table for current thread */
+ Tcl_HashTable *hashTablePtr;/* Hash table for current thread. */
Tcl_HashSearch search; /* Need to hit every thread with this search */
Tcl_HashEntry *hPtr; /* Hash entry for current thread in master
* table. */
@@ -936,22 +940,23 @@ TclFinalizeThreadStorageDataKey(keyPtr)
if (threadStorageHashTablePtr != NULL) {
/*
- * We are going to delete the specified data key entry
- * from every thread.
+ * We are going to delete the specified data key entry from every
+ * thread.
*/
for (hPtr = Tcl_FirstHashEntry(threadStorageHashTablePtr, &search);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
-
/*
* Get the hash table corresponding to the thread in question.
*/
+
hashTablePtr = Tcl_GetHashValue(hPtr);
if (hashTablePtr != NULL) {
/*
* Now find the entry for the specified data key.
*/
+
hDataPtr = Tcl_FindHashEntry(hashTablePtr,
(char *)*indexPtr);
@@ -959,6 +964,7 @@ TclFinalizeThreadStorageDataKey(keyPtr)
/*
* Delete the data key for this thread.
*/
+
Tcl_DeleteHashEntry(hDataPtr);
}
}
@@ -981,15 +987,14 @@ static void ThreadStoragePanic _ANSI_ARGS_((CONST char *message));
*
* ThreadStoragePanic --
*
- * Panic if Tcl was compiled without TCL_THREADS or without
- * USE_THREAD_STORAGE and a thread storage function has been
- * called.
+ * Panic if Tcl was compiled without TCL_THREADS or without
+ * USE_THREAD_STORAGE and a thread storage function has been called.
*
* Results:
- * None.
+ * None.
*
* Side effects:
- * None.
+ * None.
*
*----------------------------------------------------------------------
*/
@@ -999,10 +1004,9 @@ static void ThreadStoragePanic(message)
#ifdef TCL_THREADS
# ifdef USE_THREAD_STORAGE
/*
- * Do nothing, everything is OK. However, this should never happen
- * because this function only gets called by the dummy thread
- * storage functions (used when one or both of these DEFINES are
- * not present).
+ * Do nothing, everything is OK. However, this should never happen because
+ * this function only gets called by the dummy thread storage functions
+ * (used when one or both of these DEFINES are not present).
*/
# else
Tcl_Panic("Tcl was not compiled with thread storage enabled.");
@@ -1110,3 +1114,11 @@ TclFinalizeThreadStorageDataKey(keyPtr)
}
#endif /* defined(TCL_THREADS) && defined(USE_THREAD_STORAGE) */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */