tclthread.c

来自「tcl是工具命令语言」· C语言 代码 · 共 578 行

C
578
字号
/*  * tclThread.c -- * *	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. * * 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 $ */#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. * * These statics are guarded by the mutex in the caller of * TclRememberThreadData, e.g., TclpThreadDataKeyInit */typedef struct {    int num;		/* Number of objects remembered */    int max;		/* Max size of the array */    char **list;	/* List of pointers */} SyncObjRecord;static SyncObjRecord keyRecord;static SyncObjRecord mutexRecord;static SyncObjRecord condRecord;/* * 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));/*  * 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. */#ifndef TCL_THREADS#undef Tcl_MutexLock#undef Tcl_MutexUnlock#undef Tcl_MutexFinalize#undef Tcl_ConditionNotify#undef Tcl_ConditionWait#undef Tcl_ConditionFinalize#endif/* *---------------------------------------------------------------------- * * Tcl_GetThreadData -- * *	This procedure 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. * *---------------------------------------------------------------------- */VOID *Tcl_GetThreadData(keyPtr, size)    Tcl_ThreadDataKey *keyPtr;	/* Identifier for the data chunk */    int size;			/* Size of storage block */{    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);    if (result == NULL) {	result  = (VOID *)ckalloc((size_t)size);	memset(result, 0, (size_t)size);	TclpThreadDataKeySet(keyPtr, result);    }#else    if (*keyPtr == NULL) {	result = (VOID *)ckalloc((size_t)size);	memset((char *)result, 0, (size_t)size);	*keyPtr = (Tcl_ThreadDataKey)result;	TclRememberDataKey(keyPtr);    }    result = *(VOID **)keyPtr;#endif    return result;}/* *---------------------------------------------------------------------- * * TclThreadDataKeyGet -- * *	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. * * Side effects: *	None. * *---------------------------------------------------------------------- */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. * *---------------------------------------------------------------------- */voidTclThreadDataKeySet(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;#endif /* TCL_THREADS */}/* *---------------------------------------------------------------------- * * RememberSyncObject * *      Keep a list of (mutexes/condition variable/data key) *	used during finalization. * * Results: *	None. * * Side effects: *	Add to the appropriate list. * *---------------------------------------------------------------------- */static voidRememberSyncObject(objPtr, recPtr)    char *objPtr;		/* Pointer to sync object */    SyncObjRecord *recPtr;	/* Record of sync objects */{    char **newList;    int i, j;    /*     * 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 *));	for (i=0,j=0 ; i<recPtr->num ; i++) {            if (recPtr->list[i] != NULL) {		newList[j++] = recPtr->list[i];            }	}	if (recPtr->list != NULL) {	    ckfree((char *)recPtr->list);	}	recPtr->list = newList;	recPtr->num = j;    }    recPtr->list[recPtr->num] = objPtr;    recPtr->num++;}/* *---------------------------------------------------------------------- * * ForgetSyncObject * *      Remove a single object from the list. * * Results: *	None. * * Side effects: *	Remove from the appropriate list. * *---------------------------------------------------------------------- */static voidForgetSyncObject(objPtr, recPtr)    char *objPtr;		/* Pointer to sync object */    SyncObjRecord *recPtr;	/* Record of sync objects */{    int i;    for (i=0 ; i<recPtr->num ; i++) {	if (objPtr == recPtr->list[i]) {	    recPtr->list[i] = NULL;	    return;	}    }}/* *---------------------------------------------------------------------- * * TclRememberMutex * *      Keep a list of mutexes used during finalization. * * Results: *	None. * * Side effects: *	Add to the mutex list. * *---------------------------------------------------------------------- */voidTclRememberMutex(mutexPtr)    Tcl_Mutex *mutexPtr;{    RememberSyncObject((char *)mutexPtr, &mutexRecord);}/* *---------------------------------------------------------------------- * * Tcl_MutexFinalize * *      Finalize a single mutex and remove it from the *	list of remembered objects. * * Results: *	None. * * Side effects: *	Remove the mutex from the list. * *---------------------------------------------------------------------- */voidTcl_MutexFinalize(mutexPtr)    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. * *---------------------------------------------------------------------- */voidTclRememberDataKey(keyPtr)    Tcl_ThreadDataKey *keyPtr;{    RememberSyncObject((char *)keyPtr, &keyRecord);}/* *---------------------------------------------------------------------- * * TclRememberCondition * *      Keep a list of condition variables used during finalization. * * Results: *	None. * * Side effects: *	Add to the condition variable list. * *---------------------------------------------------------------------- */voidTclRememberCondition(condPtr)    Tcl_Condition *condPtr;{    RememberSyncObject((char *)condPtr, &condRecord);}/* *---------------------------------------------------------------------- * * Tcl_ConditionFinalize * *      Finalize a single condition variable and remove it from the *	list of remembered objects. * * Results: *	None. * * Side effects: *	Remove the condition variable from the list. * *---------------------------------------------------------------------- */voidTcl_ConditionFinalize(condPtr)    Tcl_Condition *condPtr;{#ifdef TCL_THREADS    TclpFinalizeCondition(condPtr);#endif    ForgetSyncObject((char *)condPtr, &condRecord);}/* *---------------------------------------------------------------------- * * TclFinalizeThreadData -- * *	This procedure cleans up the thread-local storage.  This is *	called once for each thread. * * Results: *	None. * * Side effects: *	Frees up all thread local storage. * *---------------------------------------------------------------------- */voidTclFinalizeThreadData(){    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;	}#endif    }    TclpMasterUnlock();}/* *---------------------------------------------------------------------- * * TclFinalizeSynchronization -- * *      This procedure cleans up all synchronization objects: *      mutexes, condition variables, and thread-local storage. * * Results: *	None. * * Side effects: *	Frees up the memory. * *---------------------------------------------------------------------- */voidTclFinalizeSynchronization(){#ifdef TCL_THREADS    Tcl_ThreadDataKey *keyPtr;    Tcl_Mutex *mutexPtr;    Tcl_Condition *condPtr;    int i;    TclpMasterLock();    for (i=0 ; i<keyRecord.num ; i++) {	keyPtr = (Tcl_ThreadDataKey *)keyRecord.list[i];	TclpFinalizeThreadDataKey(keyPtr);    }    if (keyRecord.list != NULL) {	ckfree((char *)keyRecord.list);	keyRecord.list = NULL;    }    keyRecord.max = 0;    keyRecord.num = 0;    for (i=0 ; i<mutexRecord.num ; i++) {	mutexPtr = (Tcl_Mutex *)mutexRecord.list[i];	if (mutexPtr != NULL) {	    TclpFinalizeMutex(mutexPtr);	}    }    if (mutexRecord.list != NULL) {	ckfree((char *)mutexRecord.list);	mutexRecord.list = NULL;    }    mutexRecord.max = 0;    mutexRecord.num = 0;    for (i=0 ; i<condRecord.num ; i++) {	condPtr = (Tcl_Condition *)condRecord.list[i];	if (condPtr != NULL) {	    TclpFinalizeCondition(condPtr);	}    }    if (condRecord.list != NULL) {	ckfree((char *)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}/* *---------------------------------------------------------------------- * * 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. * * Results: *	None. * * Side effects: *	All thread exit handlers are invoked, then the thread dies. * *---------------------------------------------------------------------- */voidTcl_ExitThread(status)    int status;{    Tcl_FinalizeThread();#ifdef TCL_THREADS    TclpThreadExit(status);#endif}#ifndef TCL_THREADS/* *---------------------------------------------------------------------- * * 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. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */#undef Tcl_ConditionWaitvoidTcl_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 */{}#undef Tcl_ConditionNotifyvoidTcl_ConditionNotify(condPtr)    Tcl_Condition *condPtr;{}#undef Tcl_MutexLockvoidTcl_MutexLock(mutexPtr)    Tcl_Mutex *mutexPtr;{}#undef Tcl_MutexUnlockvoidTcl_MutexUnlock(mutexPtr)    Tcl_Mutex *mutexPtr;{}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?