📄 tclunixthrd.c
字号:
* * TclpThreadDataKeyInit -- * * 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. * *---------------------------------------------------------------------- */voidTclpThreadDataKeyInit(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */{ pthread_key_t *pkeyPtr; MASTER_LOCK; if (*keyPtr == NULL) { pkeyPtr = (pthread_key_t *)ckalloc(sizeof(pthread_key_t)); pthread_key_create(pkeyPtr, NULL); *keyPtr = (Tcl_ThreadDataKey)pkeyPtr; TclRememberDataKey(keyPtr); } MASTER_UNLOCK;}/* *---------------------------------------------------------------------- * * TclpThreadDataKeyGet -- * * 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 *TclpThreadDataKeyGet(keyPtr) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */{ pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr; if (pkeyPtr == NULL) { return NULL; } else { return (VOID *)pthread_getspecific(*pkeyPtr); }}/* *---------------------------------------------------------------------- * * TclpThreadDataKeySet -- * * This procedure sets the pointer to a block of thread local storage. * * Results: * None. * * Side effects: * Sets up the thread so future calls to TclpThreadDataKeyGet with * this key will return the data pointer. * *---------------------------------------------------------------------- */voidTclpThreadDataKeySet(keyPtr, data) Tcl_ThreadDataKey *keyPtr; /* Identifier for the data chunk, * really (pthread_key_t **) */ VOID *data; /* Thread local storage */{ pthread_key_t *pkeyPtr = *(pthread_key_t **)keyPtr; pthread_setspecific(*pkeyPtr, data);}/* *---------------------------------------------------------------------- * * TclpFinalizeThreadData -- * * 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. * *---------------------------------------------------------------------- */voidTclpFinalizeThreadData(keyPtr) Tcl_ThreadDataKey *keyPtr;{ VOID *result; pthread_key_t *pkeyPtr; if (*keyPtr != NULL) { pkeyPtr = *(pthread_key_t **)keyPtr; result = (VOID *)pthread_getspecific(*pkeyPtr); if (result != NULL) { ckfree((char *)result); pthread_setspecific(*pkeyPtr, (void *)NULL); } }}/* *---------------------------------------------------------------------- * * TclpFinalizeThreadDataKey -- * * 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. * * Results: * None. * * Side effects: * The key is deallocated. * *---------------------------------------------------------------------- */voidTclpFinalizeThreadDataKey(keyPtr) Tcl_ThreadDataKey *keyPtr;{ pthread_key_t *pkeyPtr; if (*keyPtr != NULL) { pkeyPtr = *(pthread_key_t **)keyPtr; pthread_key_delete(*pkeyPtr); ckfree((char *)pkeyPtr); *keyPtr = NULL; }}/* *---------------------------------------------------------------------- * * Tcl_ConditionWait -- * * This procedure is invoked to wait on a condition variable. * The mutex is automically released as part of the wait, and * automatically grabbed when the condition is signaled. * * The mutex must be held when this procedure is called. * * Results: * None. * * Side effects: * May block the current thread. The mutex is aquired when * this returns. Will allocate memory for a pthread_mutex_t * and initialize this the first time this Tcl_Mutex is used. * *---------------------------------------------------------------------- */voidTcl_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 */{ pthread_cond_t *pcondPtr; pthread_mutex_t *pmutexPtr; struct timespec ptime; if (*condPtr == NULL) { MASTER_LOCK; /* * Double check inside mutex to avoid race, * then initialize condition variable if necessary. */ if (*condPtr == NULL) { pcondPtr = (pthread_cond_t *)ckalloc(sizeof(pthread_cond_t)); pthread_cond_init(pcondPtr, NULL); *condPtr = (Tcl_Condition)pcondPtr; TclRememberCondition(condPtr); } MASTER_UNLOCK; } pmutexPtr = *((pthread_mutex_t **)mutexPtr); pcondPtr = *((pthread_cond_t **)condPtr); if (timePtr == NULL) { pthread_cond_wait(pcondPtr, pmutexPtr); } else { Tcl_Time now; /* * Make sure to take into account the microsecond component of the * current time, including possible overflow situations. [Bug #411603] */ Tcl_GetTime(&now); ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000; ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000); pthread_cond_timedwait(pcondPtr, pmutexPtr, &ptime); }}/* *---------------------------------------------------------------------- * * Tcl_ConditionNotify -- * * This procedure is invoked to signal a condition variable. * * The mutex must be held during this call to avoid races, * but this interface does not enforce that. * * Results: * None. * * Side effects: * May unblock another thread. * *---------------------------------------------------------------------- */voidTcl_ConditionNotify(condPtr) Tcl_Condition *condPtr;{ pthread_cond_t *pcondPtr = *((pthread_cond_t **)condPtr); if (pcondPtr != NULL) { pthread_cond_broadcast(pcondPtr); } else { /* * Noone has used the condition variable, so there are no waiters. */ }}/* *---------------------------------------------------------------------- * * TclpFinalizeCondition -- * * This procedure is invoked to clean up a condition variable. * This is only safe to call at the end of time. * * This assumes the Master Lock is held. * * Results: * None. * * Side effects: * The condition variable is deallocated. * *---------------------------------------------------------------------- */voidTclpFinalizeCondition(condPtr) Tcl_Condition *condPtr;{ pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr; if (pcondPtr != NULL) { pthread_cond_destroy(pcondPtr); ckfree((char *)pcondPtr); *condPtr = NULL; }}#endif /* TCL_THREADS *//* *---------------------------------------------------------------------- * * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa -- * * These procedures replace core C versions to be used in a * threaded environment. * * Results: * See documentation of C functions. * * Side effects: * See documentation of C functions. * *---------------------------------------------------------------------- */#if defined(TCL_THREADS) && !defined(HAVE_READDIR_R)TCL_DECLARE_MUTEX( rdMutex )#undef readdir#endifTcl_DirEntry *TclpReaddir(DIR * dir){ Tcl_DirEntry *ent;#ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);#ifdef HAVE_READDIR_R ent = &tsdPtr->rdbuf.ent; if (TclOSreaddir_r(dir, ent, &ent) != 0) { ent = NULL; }#else /* !HAVE_READDIR_R */ Tcl_MutexLock(&rdMutex);# ifdef HAVE_STRUCT_DIRENT64 ent = readdir64(dir);# else /* !HAVE_STRUCT_DIRENT64 */ ent = readdir(dir);# endif /* HAVE_STRUCT_DIRENT64 */ if (ent != NULL) { memcpy((VOID *) &tsdPtr->rdbuf.ent, (VOID *) ent, sizeof(&tsdPtr->rdbuf)); ent = &tsdPtr->rdbuf.ent; } Tcl_MutexUnlock(&rdMutex);#endif /* HAVE_READDIR_R */#else# ifdef HAVE_STRUCT_DIRENT64 ent = readdir64(dir);# else /* !HAVE_STRUCT_DIRENT64 */ ent = readdir(dir);# endif /* HAVE_STRUCT_DIRENT64 */#endif return ent;}#if defined(TCL_THREADS) && (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R))TCL_DECLARE_MUTEX( tmMutex )#undef localtime#undef gmtime#endifstruct tm *TclpLocaltime(time_t * clock){#ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);#ifdef HAVE_LOCALTIME_R return localtime_r(clock, &tsdPtr->ltbuf);#else Tcl_MutexLock( &tmMutex ); memcpy( (VOID *) &tsdPtr->ltbuf, (VOID *) localtime( clock ), sizeof (struct tm) ); Tcl_MutexUnlock( &tmMutex ); return &tsdPtr->ltbuf;#endif #else return localtime(clock);#endif}struct tm *TclpGmtime(time_t * clock){#ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);#ifdef HAVE_GMTIME_R return gmtime_r(clock, &tsdPtr->gtbuf);#else Tcl_MutexLock( &tmMutex ); memcpy( (VOID *) &tsdPtr->gtbuf, (VOID *) gmtime( clock ), sizeof (struct tm) ); Tcl_MutexUnlock( &tmMutex ); return &tsdPtr->gtbuf;#endif #else return gmtime(clock);#endif}char *TclpInetNtoa(struct in_addr addr){#ifdef TCL_THREADS ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); union { unsigned long l; unsigned char b[4]; } u; u.l = (unsigned long) addr.s_addr; sprintf(tsdPtr->nabuf, "%u.%u.%u.%u", u.b[0], u.b[1], u.b[2], u.b[3]); return tsdPtr->nabuf;#else return inet_ntoa(addr);#endif}#ifdef TCL_THREADS/* * Additions by AOL for specialized thread memory allocator. */#ifdef USE_THREAD_ALLOCstatic int initialized = 0;static pthread_key_t key;static pthread_once_t once = PTHREAD_ONCE_INIT;Tcl_Mutex *TclpNewAllocMutex(void){ struct lock { Tcl_Mutex tlock; pthread_mutex_t plock; } *lockPtr; lockPtr = malloc(sizeof(struct lock)); if (lockPtr == NULL) { panic("could not allocate lock"); } lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock; pthread_mutex_init(&lockPtr->plock, NULL); return &lockPtr->tlock;}static voidInitKey(void){ extern void TclFreeAllocCache(void *); pthread_key_create(&key, TclFreeAllocCache); initialized = 1;}void *TclpGetAllocCache(void){ if (!initialized) { pthread_once(&once, InitKey); } return pthread_getspecific(key);}voidTclpSetAllocCache(void *arg){ pthread_setspecific(key, arg);}#endif /* USE_THREAD_ALLOC */#endif /* TCL_THREADS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -