summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixThrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixThrd.c')
-rw-r--r--unix/tclUnixThrd.c221
1 files changed, 133 insertions, 88 deletions
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 7394545..1841242 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -5,7 +5,6 @@
*
* Copyright (c) 1991-1994 The Regents of the University of California.
* Copyright (c) 1994-1997 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.
@@ -15,7 +14,7 @@
#ifdef TCL_THREADS
-typedef struct {
+typedef struct ThreadSpecificData {
char nabuf[16];
} ThreadSpecificData;
@@ -44,7 +43,15 @@ static pthread_mutex_t initLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t allocLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t *allocLockPtr = &allocLock;
+/*
+ * These are for the critical sections inside this file.
+ */
+
+#define MASTER_LOCK pthread_mutex_lock(&masterLock)
+#define MASTER_UNLOCK pthread_mutex_unlock(&masterLock)
+
#endif /* TCL_THREADS */
+
/*
*----------------------------------------------------------------------
@@ -66,7 +73,7 @@ static pthread_mutex_t *allocLockPtr = &allocLock;
int
TclpThreadCreate(
Tcl_ThreadId *idPtr, /* Return, the ID of the thread */
- Tcl_ThreadCreateProc *proc, /* Main() function of the thread */
+ Tcl_ThreadCreateProc proc, /* Main() function of the thread */
ClientData clientData, /* The one argument to Main() */
int stackSize, /* Size of stack for the new thread */
int flags) /* Flags controlling behaviour of the new
@@ -98,19 +105,18 @@ TclpThreadCreate(
*/
size_t size;
-
result = pthread_attr_getstacksize(&attr, &size);
if (!result && (size < TCL_THREAD_STACK_MIN)) {
pthread_attr_setstacksize(&attr, (size_t) TCL_THREAD_STACK_MIN);
}
-#endif /* TCL_THREAD_STACK_MIN */
+#endif
}
-#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
-
+#endif
if (! (flags & TCL_THREAD_JOINABLE)) {
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
}
+
if (pthread_create(&theThread, &attr,
(void * (*)(void *))proc, (void *)clientData) &&
pthread_create(&theThread, NULL,
@@ -189,6 +195,99 @@ TclpThreadExit(
}
#endif /* TCL_THREADS */
+#ifdef TCL_THREADS
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpThreadGetStackSize --
+ *
+ * This procedure returns the size of the current thread's stack.
+ *
+ * Results:
+ * Stack size (in bytes?) or -1 for error or 0 for undeterminable.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+size_t
+TclpThreadGetStackSize(void)
+{
+ size_t stackSize = 0;
+#if defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && defined(TclpPthreadGetAttrs)
+ pthread_attr_t threadAttr; /* This will hold the thread attributes for
+ * the current thread. */
+#ifdef __GLIBC__
+ /*
+ * Fix for [Bug 1815573]
+ *
+ * DESCRIPTION:
+ * On linux TclpPthreadGetAttrs (which is pthread_attr_get_np) may return
+ * bogus values on the initial thread.
+ *
+ * ASSUMPTIONS:
+ * There seems to be no api to determine if we are on the initial
+ * thread. The simple scheme implemented here assumes:
+ * 1. The first Tcl interp to be created lives in the initial thread. If
+ * this assumption is not true, the fix is to call
+ * TclpThreadGetStackSize from the initial thread previous to
+ * creating any Tcl interpreter. In this case, especially if another
+ * Tcl interpreter may be created in the initial thread, it might be
+ * better to enable the second branch in the #if below
+ * 2. There will be no races in creating the first Tcl interp - ie, the
+ * second Tcl interp will be created only after the first call to
+ * Tcl_CreateInterp returns.
+ *
+ * These assumptions are satisfied by tclsh. Embedders on linux may want
+ * to check their validity, and possibly adapt the code on failing to meet
+ * them.
+ */
+
+ static int initialized = 0;
+
+ if (!initialized) {
+ initialized = 1;
+ return 0;
+ } else {
+#else
+ {
+#endif
+ if (pthread_attr_init(&threadAttr) != 0) {
+ return -1;
+ }
+ if (TclpPthreadGetAttrs(pthread_self(), &threadAttr) != 0) {
+ pthread_attr_destroy(&threadAttr);
+ return (size_t)-1;
+ }
+ }
+
+
+ if (pthread_attr_getstacksize(&threadAttr, &stackSize) != 0) {
+ pthread_attr_destroy(&threadAttr);
+ return (size_t)-1;
+ }
+ pthread_attr_destroy(&threadAttr);
+#elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP)
+#ifdef __APPLE__
+ /*
+ * On Darwin, the API below does not return the correct stack size for the
+ * main thread (which is not a real pthread), so fallback to getrlimit().
+ */
+ if (!pthread_main_np())
+#endif
+ stackSize = pthread_get_stacksize_np(pthread_self());
+#else
+ /*
+ * Cannot determine the real stack size of this thread. The caller might
+ * want to try looking at the process accounting limits instead.
+ */
+#endif
+ return stackSize;
+}
+#endif /* TCL_THREADS */
+
/*
*----------------------------------------------------------------------
*
@@ -245,7 +344,7 @@ TclpInitLock(void)
/*
*----------------------------------------------------------------------
*
- * TclFinalizeLock
+ * TclpFinalizeLock
*
* This procedure is used to destroy all private resources used in this
* file.
@@ -414,18 +513,18 @@ Tcl_MutexLock(
pthread_mutex_t *pmutexPtr;
if (*mutexPtr == NULL) {
- pthread_mutex_lock(&masterLock);
+ MASTER_LOCK;
if (*mutexPtr == NULL) {
/*
* Double inside master lock check to avoid a race condition.
*/
- pmutexPtr = ckalloc(sizeof(pthread_mutex_t));
+ pmutexPtr = (pthread_mutex_t *)ckalloc(sizeof(pthread_mutex_t));
pthread_mutex_init(pmutexPtr, NULL);
*mutexPtr = (Tcl_Mutex)pmutexPtr;
TclRememberMutex(mutexPtr);
}
- pthread_mutex_unlock(&masterLock);
+ MASTER_UNLOCK;
}
pmutexPtr = *((pthread_mutex_t **)mutexPtr);
pthread_mutex_lock(pmutexPtr);
@@ -452,8 +551,7 @@ void
Tcl_MutexUnlock(
Tcl_Mutex *mutexPtr) /* Really (pthread_mutex_t **) */
{
- pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **) mutexPtr;
-
+ pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
pthread_mutex_unlock(pmutexPtr);
}
@@ -480,11 +578,10 @@ void
TclpFinalizeMutex(
Tcl_Mutex *mutexPtr)
{
- pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **) mutexPtr;
-
+ pthread_mutex_t *pmutexPtr = *(pthread_mutex_t **)mutexPtr;
if (pmutexPtr != NULL) {
pthread_mutex_destroy(pmutexPtr);
- ckfree(pmutexPtr);
+ ckfree((char *) pmutexPtr);
*mutexPtr = NULL;
}
}
@@ -515,14 +612,14 @@ void
Tcl_ConditionWait(
Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */
Tcl_Mutex *mutexPtr, /* Really (pthread_mutex_t **) */
- const Tcl_Time *timePtr) /* Timeout on waiting period */
+ Tcl_Time *timePtr) /* Timeout on waiting period */
{
pthread_cond_t *pcondPtr;
pthread_mutex_t *pmutexPtr;
struct timespec ptime;
if (*condPtr == NULL) {
- pthread_mutex_lock(&masterLock);
+ MASTER_LOCK;
/*
* Double check inside mutex to avoid race, then initialize condition
@@ -530,12 +627,12 @@ Tcl_ConditionWait(
*/
if (*condPtr == NULL) {
- pcondPtr = ckalloc(sizeof(pthread_cond_t));
+ pcondPtr = (pthread_cond_t *) ckalloc(sizeof(pthread_cond_t));
pthread_cond_init(pcondPtr, NULL);
- *condPtr = (Tcl_Condition) pcondPtr;
+ *condPtr = (Tcl_Condition)pcondPtr;
TclRememberCondition(condPtr);
}
- pthread_mutex_unlock(&masterLock);
+ MASTER_UNLOCK;
}
pmutexPtr = *((pthread_mutex_t **)mutexPtr);
pcondPtr = *((pthread_cond_t **)condPtr);
@@ -614,10 +711,9 @@ TclpFinalizeCondition(
Tcl_Condition *condPtr)
{
pthread_cond_t *pcondPtr = *(pthread_cond_t **)condPtr;
-
if (pcondPtr != NULL) {
pthread_cond_destroy(pcondPtr);
- ckfree(pcondPtr);
+ ckfree((char *) pcondPtr);
*condPtr = NULL;
}
}
@@ -651,7 +747,6 @@ TclpReaddir(
return TclOSreaddir(dir);
}
-#undef TclpInetNtoa
char *
TclpInetNtoa(
struct in_addr addr)
@@ -673,9 +768,10 @@ TclpInetNtoa(
*/
#ifdef USE_THREAD_ALLOC
+static volatile int initialized = 0;
static pthread_key_t key;
-typedef struct {
+typedef struct allocMutex {
Tcl_Mutex tlock;
pthread_mutex_t plock;
} allocMutex;
@@ -683,10 +779,10 @@ typedef struct {
Tcl_Mutex *
TclpNewAllocMutex(void)
{
- allocMutex *lockPtr;
+ struct allocMutex *lockPtr;
register pthread_mutex_t *plockPtr;
- lockPtr = malloc(sizeof(allocMutex));
+ lockPtr = malloc(sizeof(struct allocMutex));
if (lockPtr == NULL) {
Tcl_Panic("could not allocate lock");
}
@@ -709,14 +805,6 @@ TclpFreeAllocMutex(
}
void
-TclpInitAllocCache(void)
-{
- pthread_mutex_lock(allocLockPtr);
- pthread_key_create(&key, NULL);
- pthread_mutex_unlock(allocLockPtr);
-}
-
-void
TclpFreeAllocCache(
void *ptr)
{
@@ -729,19 +817,28 @@ TclpFreeAllocCache(
TclFreeAllocCache(ptr);
pthread_setspecific(key, NULL);
- } else {
+ } else if (initialized) {
/*
* Called by TclFinalizeThreadAlloc() during the process
* finalization initiated from Tcl_Finalize()
*/
pthread_key_delete(key);
+ initialized = 0;
}
}
void *
TclpGetAllocCache(void)
{
+ if (!initialized) {
+ pthread_mutex_lock(allocLockPtr);
+ if (!initialized) {
+ pthread_key_create(&key, NULL);
+ initialized = 1;
+ }
+ pthread_mutex_unlock(allocLockPtr);
+ }
return pthread_getspecific(key);
}
@@ -752,58 +849,6 @@ TclpSetAllocCache(
pthread_setspecific(key, arg);
}
#endif /* USE_THREAD_ALLOC */
-
-void *
-TclpThreadCreateKey(void)
-{
- pthread_key_t *ptkeyPtr;
-
- ptkeyPtr = TclpSysAlloc(sizeof *ptkeyPtr, 0);
- if (NULL == ptkeyPtr) {
- Tcl_Panic("unable to allocate thread key!");
- }
-
- if (pthread_key_create(ptkeyPtr, NULL)) {
- Tcl_Panic("unable to create pthread key!");
- }
-
- return ptkeyPtr;
-}
-
-void
-TclpThreadDeleteKey(
- void *keyPtr)
-{
- pthread_key_t *ptkeyPtr = keyPtr;
-
- if (pthread_key_delete(*ptkeyPtr)) {
- Tcl_Panic("unable to delete key!");
- }
-
- TclpSysFree(keyPtr);
-}
-
-void
-TclpThreadSetMasterTSD(
- void *tsdKeyPtr,
- void *ptr)
-{
- pthread_key_t *ptkeyPtr = tsdKeyPtr;
-
- if (pthread_setspecific(*ptkeyPtr, ptr)) {
- Tcl_Panic("unable to set master TSD value");
- }
-}
-
-void *
-TclpThreadGetMasterTSD(
- void *tsdKeyPtr)
-{
- pthread_key_t *ptkeyPtr = tsdKeyPtr;
-
- return pthread_getspecific(*ptkeyPtr);
-}
-
#endif /* TCL_THREADS */
/*