diff options
Diffstat (limited to 'generic/tclThread.c')
| -rw-r--r-- | generic/tclThread.c | 390 | 
1 files changed, 173 insertions, 217 deletions
| diff --git a/generic/tclThread.c b/generic/tclThread.c index 5ddbb91..8c972a8 100644 --- a/generic/tclThread.c +++ b/generic/tclThread.c @@ -1,24 +1,22 @@ -/*  +/*   * tclThread.c --   * - *	This file implements   Platform independent thread operations. - *	Most of the real work is done in the platform dependent files. + *	This file implements Platform independent thread operations. Most of + *	the real work is done in the platform dependent files.   *   * Copyright (c) 1998 by Sun Microsystems, Inc. + * Copyright (c) 2008 by George Peter Staplin   * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tclThread.c,v 1.6 2002/12/10 00:34:15 hobbs Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclInt.h"  /* - * There are three classes of synchronization objects: - * mutexes, thread data keys, and condition variables. - * The following are used to record the memory used for these - * objects so they can be finalized. + * There are three classes of synchronization objects: mutexes, thread data + * keys, and condition variables. The following are used to record the memory + * used for these objects so they can be finalized.   *   * These statics are guarded by the mutex in the caller of   * TclRememberThreadData, e.g., TclpThreadDataKeyInit @@ -27,27 +25,27 @@  typedef struct {      int num;		/* Number of objects remembered */      int max;		/* Max size of the array */ -    char **list;	/* List of pointers */ +    void **list;	/* List of pointers */  } SyncObjRecord; -static SyncObjRecord keyRecord; -static SyncObjRecord mutexRecord; -static SyncObjRecord condRecord; +static SyncObjRecord keyRecord = {0, 0, NULL}; +static SyncObjRecord mutexRecord = {0, 0, NULL}; +static SyncObjRecord condRecord = {0, 0, NULL};  /* - * Prototypes of functions used only in this file + * Prototypes of functions used only in this file.   */ -  -static void		RememberSyncObject _ANSI_ARGS_((char *objPtr, -			    SyncObjRecord *recPtr)); -static void		ForgetSyncObject _ANSI_ARGS_((char *objPtr, -			    SyncObjRecord *recPtr)); -/*  +static void		ForgetSyncObject(void *objPtr, SyncObjRecord *recPtr); +static void		RememberSyncObject(void *objPtr, +			    SyncObjRecord *recPtr); + +/*   * Several functions are #defined to nothing in tcl.h if TCL_THREADS is not - * specified.  Here we undo that so the procedures are defined in the - * stubs table. + * specified. Here we undo that so the functions are defined in the stubs + * table.   */ +  #ifndef TCL_THREADS  #undef Tcl_MutexLock  #undef Tcl_MutexUnlock @@ -56,61 +54,53 @@ static void		ForgetSyncObject _ANSI_ARGS_((char *objPtr,  #undef Tcl_ConditionWait  #undef Tcl_ConditionFinalize  #endif -  /*   *----------------------------------------------------------------------   *   * Tcl_GetThreadData --   * - *	This procedure allocates and initializes a chunk of thread - *	local storage. + *	This function allocates and initializes a chunk of thread local + *	storage.   *   * Results:   *	A thread-specific pointer to the data structure.   *   * Side effects: - *	Will allocate memory the first time this thread calls for - *	this chunk of storage. + *	Will allocate memory the first time this thread calls for this chunk + *	of storage.   *   *----------------------------------------------------------------------   */ -VOID * -Tcl_GetThreadData(keyPtr, size) -    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk */ -    int size;			/* Size of storage block */ +void * +Tcl_GetThreadData( +    Tcl_ThreadDataKey *keyPtr,	/* Identifier for the data chunk */ +    int size)			/* Size of storage block */  { -    VOID *result; +    void *result;  #ifdef TCL_THREADS - -    /* -     * See if this is the first thread to init this key. -     */ - -    if (*keyPtr == NULL) { -	TclpThreadDataKeyInit(keyPtr); -    } -      /*       * Initialize the key for this thread.       */ -    result = TclpThreadDataKeyGet(keyPtr); +    result = TclThreadStorageKeyGet(keyPtr); +      if (result == NULL) { -	result  = (VOID *)ckalloc((size_t)size); -	memset(result, 0, (size_t)size); -	TclpThreadDataKeySet(keyPtr, result); +	result = ckalloc(size); +	memset(result, 0, (size_t) size); +	TclThreadStorageKeySet(keyPtr, result);      } -#else +#else /* TCL_THREADS */      if (*keyPtr == NULL) { -	result = (VOID *)ckalloc((size_t)size); -	memset((char *)result, 0, (size_t)size); -	*keyPtr = (Tcl_ThreadDataKey)result; -	TclRememberDataKey(keyPtr); +	result = ckalloc(size); +	memset(result, 0, (size_t)size); +	*keyPtr = result; +	RememberSyncObject(keyPtr, &keyRecord); +    } else { +	result = *keyPtr;      } -    result = *(VOID **)keyPtr; -#endif +#endif /* TCL_THREADS */      return result;  } @@ -119,11 +109,11 @@ Tcl_GetThreadData(keyPtr, size)   *   * TclThreadDataKeyGet --   * - *	This procedure returns a pointer to a block of thread local storage. + *	This function 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. @@ -131,61 +121,27 @@ Tcl_GetThreadData(keyPtr, size)   *----------------------------------------------------------------------   */ -VOID * -TclThreadDataKeyGet(keyPtr) -    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk, -				 * really (pthread_key_t **) */ -{ -#ifdef TCL_THREADS -    return (VOID *)TclpThreadDataKeyGet(keyPtr); -#else -    char *result = *(char **)keyPtr; -    return (VOID *)result; -#endif /* TCL_THREADS */ -} - - -/* - *---------------------------------------------------------------------- - * - * TclThreadDataKeySet -- - * - *	This procedure sets a thread local storage pointer. - * - * Results: - *	None. - * - * Side effects: - *	The assigned value will be returned by TclpThreadDataKeyGet. - * - *---------------------------------------------------------------------- - */ +void * +TclThreadDataKeyGet( +    Tcl_ThreadDataKey *keyPtr)	/* Identifier for the data chunk. */ -void -TclThreadDataKeySet(keyPtr, data) -    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk, -				 * really (pthread_key_t **) */ -    VOID *data;			/* Thread local storage */  {  #ifdef TCL_THREADS -    if (*keyPtr == NULL) { -	TclpThreadDataKeyInit(keyPtr); -    } -    TclpThreadDataKeySet(keyPtr, data); -#else -    *keyPtr = (Tcl_ThreadDataKey)data; +    return TclThreadStorageKeyGet(keyPtr); +#else /* TCL_THREADS */ +    return *keyPtr;  #endif /* TCL_THREADS */  } - -  /*   *----------------------------------------------------------------------   *   * RememberSyncObject   * - *      Keep a list of (mutexes/condition variable/data key) - *	used during finalization. + *	Keep a list of (mutexes/condition variable/data key) used during + *	finalization. + * + *	Assume master lock is held.   *   * Results:   *	None. @@ -197,33 +153,45 @@ TclThreadDataKeySet(keyPtr, data)   */  static void -RememberSyncObject(objPtr, recPtr) -    char *objPtr;		/* Pointer to sync object */ -    SyncObjRecord *recPtr;	/* Record of sync objects */ +RememberSyncObject( +    void *objPtr,		/* Pointer to sync object */ +    SyncObjRecord *recPtr)	/* Record of sync objects */  { -    char **newList; +    void **newList;      int i, j; + +    /* +     * Reuse any free slot in the list. +     */ + +    for (i=0 ; i < recPtr->num ; ++i) { +	if (recPtr->list[i] == NULL) { +	    recPtr->list[i] = objPtr; +	    return; +	} +    } +      /* -     * Save the pointer to the allocated object so it can be finalized.       * Grow the list of pointers if necessary, copying only non-NULL       * pointers to the new list.       */      if (recPtr->num >= recPtr->max) {  	recPtr->max += 8; -	newList = (char **)ckalloc(recPtr->max * sizeof(char *)); +	newList = ckalloc(recPtr->max * sizeof(void *));  	for (i=0,j=0 ; i<recPtr->num ; i++) { -            if (recPtr->list[i] != NULL) { +	    if (recPtr->list[i] != NULL) {  		newList[j++] = recPtr->list[i]; -            } +	    }  	}  	if (recPtr->list != NULL) { -	    ckfree((char *)recPtr->list); +	    ckfree(recPtr->list);  	}  	recPtr->list = newList;  	recPtr->num = j;      } +      recPtr->list[recPtr->num] = objPtr;      recPtr->num++;  } @@ -233,7 +201,8 @@ RememberSyncObject(objPtr, recPtr)   *   * ForgetSyncObject   * - *      Remove a single object from the list. + *	Remove a single object from the list. + *	Assume master lock is held.   *   * Results:   *	None. @@ -245,9 +214,9 @@ RememberSyncObject(objPtr, recPtr)   */  static void -ForgetSyncObject(objPtr, recPtr) -    char *objPtr;		/* Pointer to sync object */ -    SyncObjRecord *recPtr;	/* Record of sync objects */ +ForgetSyncObject( +    void *objPtr,		/* Pointer to sync object */ +    SyncObjRecord *recPtr)	/* Record of sync objects */  {      int i; @@ -264,7 +233,8 @@ ForgetSyncObject(objPtr, recPtr)   *   * TclRememberMutex   * - *      Keep a list of mutexes used during finalization. + *	Keep a list of mutexes used during finalization. + *	Assume master lock is held.   *   * Results:   *	None. @@ -276,19 +246,19 @@ ForgetSyncObject(objPtr, recPtr)   */  void -TclRememberMutex(mutexPtr) -    Tcl_Mutex *mutexPtr; +TclRememberMutex( +    Tcl_Mutex *mutexPtr)  { -    RememberSyncObject((char *)mutexPtr, &mutexRecord); +    RememberSyncObject(mutexPtr, &mutexRecord);  }  /*   *----------------------------------------------------------------------   * - * Tcl_MutexFinalize + * Tcl_MutexFinalize --   * - *      Finalize a single mutex and remove it from the - *	list of remembered objects. + *	Finalize a single mutex and remove it from the list of remembered + *	objects.   *   * Results:   *	None. @@ -300,36 +270,15 @@ TclRememberMutex(mutexPtr)   */  void -Tcl_MutexFinalize(mutexPtr) -    Tcl_Mutex *mutexPtr; +Tcl_MutexFinalize( +    Tcl_Mutex *mutexPtr)  {  #ifdef TCL_THREADS      TclpFinalizeMutex(mutexPtr);  #endif -    ForgetSyncObject((char *)mutexPtr, &mutexRecord); -} - -/* - *---------------------------------------------------------------------- - * - * TclRememberDataKey - * - *      Keep a list of thread data keys used during finalization. - * - * Results: - *	None. - * - * Side effects: - *	Add to the key list. - * - *---------------------------------------------------------------------- - */ - -void -TclRememberDataKey(keyPtr) -    Tcl_ThreadDataKey *keyPtr; -{ -    RememberSyncObject((char *)keyPtr, &keyRecord); +    TclpMasterLock(); +    ForgetSyncObject(mutexPtr, &mutexRecord); +    TclpMasterUnlock();  }  /* @@ -337,7 +286,8 @@ TclRememberDataKey(keyPtr)   *   * TclRememberCondition   * - *      Keep a list of condition variables used during finalization. + *	Keep a list of condition variables used during finalization. + *	Assume master lock is held.   *   * Results:   *	None. @@ -349,19 +299,19 @@ TclRememberDataKey(keyPtr)   */  void -TclRememberCondition(condPtr) -    Tcl_Condition *condPtr; +TclRememberCondition( +    Tcl_Condition *condPtr)  { -    RememberSyncObject((char *)condPtr, &condRecord); +    RememberSyncObject(condPtr, &condRecord);  }  /*   *----------------------------------------------------------------------   * - * Tcl_ConditionFinalize + * Tcl_ConditionFinalize --   * - *      Finalize a single condition variable and remove it from the - *	list of remembered objects. + *	Finalize a single condition variable and remove it from the list of + *	remembered objects.   *   * Results:   *	None. @@ -373,13 +323,15 @@ TclRememberCondition(condPtr)   */  void -Tcl_ConditionFinalize(condPtr) -    Tcl_Condition *condPtr; +Tcl_ConditionFinalize( +    Tcl_Condition *condPtr)  {  #ifdef TCL_THREADS      TclpFinalizeCondition(condPtr);  #endif -    ForgetSyncObject((char *)condPtr, &condRecord); +    TclpMasterLock(); +    ForgetSyncObject(condPtr, &condRecord); +    TclpMasterUnlock();  }  /* @@ -387,8 +339,9 @@ Tcl_ConditionFinalize(condPtr)   *   * TclFinalizeThreadData --   * - *	This procedure cleans up the thread-local storage.  This is - *	called once for each thread. + *	This function cleans up the thread-local storage. Secondary, it cleans + *	thread alloc cache. + *	This is called once for each thread before thread exits.   *   * Results:   *	None. @@ -400,24 +353,12 @@ Tcl_ConditionFinalize(condPtr)   */  void -TclFinalizeThreadData() +TclFinalizeThreadData(void)  { -    int i; -    Tcl_ThreadDataKey *keyPtr; - -    TclpMasterLock(); -    for (i=0 ; i<keyRecord.num ; i++) { -	keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i]; -#ifdef TCL_THREADS -	TclpFinalizeThreadData(keyPtr); -#else -	if (*keyPtr != NULL) { -	    ckfree((char *)*keyPtr); -	    *keyPtr = NULL; -	} +    TclFinalizeThreadDataThread(); +#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) +    TclFinalizeThreadAllocThread();  #endif -    } -    TclpMasterUnlock();  }  /* @@ -425,8 +366,8 @@ TclFinalizeThreadData()   *   * TclFinalizeSynchronization --   * - *      This procedure cleans up all synchronization objects: - *      mutexes, condition variables, and thread-local storage. + *	This function cleans up all synchronization objects: mutexes, + *	condition variables, and thread-local storage.   *   * Results:   *	None. @@ -438,26 +379,42 @@ TclFinalizeThreadData()   */  void -TclFinalizeSynchronization() +TclFinalizeSynchronization(void)  { -#ifdef TCL_THREADS +    int i; +    void *blockPtr;      Tcl_ThreadDataKey *keyPtr; +#ifdef TCL_THREADS      Tcl_Mutex *mutexPtr;      Tcl_Condition *condPtr; -    int i;      TclpMasterLock(); -    for (i=0 ; i<keyRecord.num ; i++) { -	keyPtr = (Tcl_ThreadDataKey *)keyRecord.list[i]; -	TclpFinalizeThreadDataKey(keyPtr); -    } +#endif + +    /* +     * If we're running unthreaded, the TSD blocks are simply stored inside +     * their thread data keys. Free them here. +     */ +      if (keyRecord.list != NULL) { -	ckfree((char *)keyRecord.list); +	for (i=0 ; i<keyRecord.num ; i++) { +	    keyPtr = (Tcl_ThreadDataKey *) keyRecord.list[i]; +	    blockPtr = *keyPtr; +	    ckfree(blockPtr); +	} +	ckfree(keyRecord.list);  	keyRecord.list = NULL;      }      keyRecord.max = 0;      keyRecord.num = 0; +#ifdef TCL_THREADS +    /* +     * Call thread storage master cleanup. +     */ + +    TclFinalizeThreadStorage(); +      for (i=0 ; i<mutexRecord.num ; i++) {  	mutexPtr = (Tcl_Mutex *)mutexRecord.list[i];  	if (mutexPtr != NULL) { @@ -465,45 +422,37 @@ TclFinalizeSynchronization()  	}      }      if (mutexRecord.list != NULL) { -	ckfree((char *)mutexRecord.list); +	ckfree(mutexRecord.list);  	mutexRecord.list = NULL;      }      mutexRecord.max = 0;      mutexRecord.num = 0;      for (i=0 ; i<condRecord.num ; i++) { -	condPtr = (Tcl_Condition *)condRecord.list[i]; +	condPtr = (Tcl_Condition *) condRecord.list[i];  	if (condPtr != NULL) {  	    TclpFinalizeCondition(condPtr);  	}      }      if (condRecord.list != NULL) { -	ckfree((char *)condRecord.list); +	ckfree(condRecord.list);  	condRecord.list = NULL;      }      condRecord.max = 0;      condRecord.num = 0;      TclpMasterUnlock(); -#else -    if (keyRecord.list != NULL) { -	ckfree((char *)keyRecord.list); -	keyRecord.list = NULL; -    } -    keyRecord.max = 0; -    keyRecord.num = 0; -#endif +#endif /* TCL_THREADS */  } -  /*   *----------------------------------------------------------------------   *   * Tcl_ExitThread --   * - *	This procedure is called to terminate the current thread. - *	This should be used by extensions that create threads with - *	additional interpreters in them. + *	This function is called to terminate the current thread. This should + *	be used by extensions that create threads with additional interpreters + *	in them.   *   * Results:   *	None. @@ -515,8 +464,8 @@ TclFinalizeSynchronization()   */  void -Tcl_ExitThread(status) -    int status; +Tcl_ExitThread( +    int status)  {      Tcl_FinalizeThread();  #ifdef TCL_THREADS @@ -531,10 +480,9 @@ Tcl_ExitThread(status)   *   * Tcl_ConditionWait, et al. --   * - *	These noop procedures are provided so the stub table does - *	not have to be conditionalized for threads.  The real - *	implementations of these functions live in the platform - *	specific files. + *	These noop functions are provided so the stub table does not have to + *	be conditionalized for threads. The real implementations of these + *	functions live in the platform specific files.   *   * Results:   *	None. @@ -547,31 +495,39 @@ Tcl_ExitThread(status)  #undef Tcl_ConditionWait  void -Tcl_ConditionWait(condPtr, mutexPtr, timePtr) -    Tcl_Condition *condPtr;	/* Really (pthread_cond_t **) */ -    Tcl_Mutex *mutexPtr;	/* Really (pthread_mutex_t **) */ -    Tcl_Time *timePtr;		/* Timeout on waiting period */ +Tcl_ConditionWait( +    Tcl_Condition *condPtr,	/* Really (pthread_cond_t **) */ +    Tcl_Mutex *mutexPtr,	/* Really (pthread_mutex_t **) */ +    const Tcl_Time *timePtr) /* Timeout on waiting period */  {  }  #undef Tcl_ConditionNotify  void -Tcl_ConditionNotify(condPtr) -    Tcl_Condition *condPtr; +Tcl_ConditionNotify( +    Tcl_Condition *condPtr)  {  }  #undef Tcl_MutexLock  void -Tcl_MutexLock(mutexPtr) -    Tcl_Mutex *mutexPtr; +Tcl_MutexLock( +    Tcl_Mutex *mutexPtr)  {  }  #undef Tcl_MutexUnlock  void -Tcl_MutexUnlock(mutexPtr) -    Tcl_Mutex *mutexPtr; +Tcl_MutexUnlock( +    Tcl_Mutex *mutexPtr)  {  } -#endif +#endif /* !TCL_THREADS */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ | 
