summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-05-03 10:19:16 (GMT)
committersebres <sebres@users.sourceforge.net>2017-05-03 10:19:16 (GMT)
commit3dd348e3693ea3a0e5b01646d0fe726bf21b9c8f (patch)
tree71da655a4dc260f18516b29f195135d50c79bd8a
parent286451604f908628de79417be012ff656652db05 (diff)
downloadtcl-3dd348e3693ea3a0e5b01646d0fe726bf21b9c8f.zip
tcl-3dd348e3693ea3a0e5b01646d0fe726bf21b9c8f.tar.gz
tcl-3dd348e3693ea3a0e5b01646d0fe726bf21b9c8f.tar.bz2
[win] Introduces new threaded declarations TclWinThreadCreate/TclWinThreadExit:
because of usage of CRT and/or TLS (if threaded) - use the _beginthreadex/_endthreadex functions for thread management rather than CreateThread/ExitThread. Prevents sporadic run-time errors, like R6016 (not enough space for thread data). See section "Remarks" in https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
-rw-r--r--win/tclWinConsole.c10
-rw-r--r--win/tclWinInt.h49
-rw-r--r--win/tclWinPipe.c40
-rw-r--r--win/tclWinSerial.c5
-rw-r--r--win/tclWinThrd.c20
5 files changed, 91 insertions, 33 deletions
diff --git a/win/tclWinConsole.c b/win/tclWinConsole.c
index 5d5c8d3..748f93c 100644
--- a/win/tclWinConsole.c
+++ b/win/tclWinConsole.c
@@ -1310,18 +1310,16 @@ TclWinOpenConsoleChannel(
SetConsoleMode(infoPtr->handle, modes);
infoPtr->reader.readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- infoPtr->reader.thread = CreateThread(NULL, 256, ConsoleReaderThread,
- TclPipeThreadCreateTI(&infoPtr->reader.TI, infoPtr,
- infoPtr->reader.readyEvent), 0, NULL);
+ infoPtr->reader.thread = TclPipeThreadCreate(&infoPtr->reader.TI,
+ ConsoleReaderThread, infoPtr, infoPtr->reader.readyEvent);
SetThreadPriority(infoPtr->reader.thread, THREAD_PRIORITY_HIGHEST);
}
if (permissions & TCL_WRITABLE) {
infoPtr->writer.readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
- infoPtr->writer.thread = CreateThread(NULL, 256, ConsoleWriterThread,
- TclPipeThreadCreateTI(&infoPtr->writer.TI, infoPtr,
- infoPtr->writer.readyEvent), 0, NULL);
+ infoPtr->writer.thread = TclPipeThreadCreate(&infoPtr->writer.TI,
+ ConsoleWriterThread, infoPtr, infoPtr->writer.readyEvent);
SetThreadPriority(infoPtr->writer.thread, THREAD_PRIORITY_HIGHEST);
}
diff --git a/win/tclWinInt.h b/win/tclWinInt.h
index 5f0ade9..1feb8ed 100644
--- a/win/tclWinInt.h
+++ b/win/tclWinInt.h
@@ -210,6 +210,51 @@ MODULE_SCOPE void TclpSetAllocCache(void *);
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400
#endif
+
+/*
+ * Windows specified thread declarations.
+ *
+ * Prevent runtime error R6016 (not enough space for thread data). See section
+ * "Remarks" in https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
+ */
+
+static inline HANDLE
+TclWinThreadCreate(
+ Tcl_ThreadId *idPtr, /* Return, the ID of the thread. */
+ LPTHREAD_START_ROUTINE proc,/* Main() function of the thread. */
+ ClientData clientData, /* The one argument to Main(). */
+ int stackSize) /* Size of stack for the new thread. */
+{
+
+ if (idPtr) {
+ *idPtr = 0; /* must initialize as Tcl_Thread is a pointer and
+ * on WIN64 sizeof void* != sizeof unsigned */
+ }
+ /*
+ * Threads that calls CRT, should use the _beginthreadex and _endthreadex
+ * functions for thread management rather than CreateThread and ExitThread.
+ * WARNING: If a thread created using CreateThread calls the CRT, the CRT
+ * may terminate the process in low-memory conditions.
+ */
+#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
+ return (HANDLE) _beginthreadex(NULL, (unsigned) stackSize,
+ proc, clientData, 0, (unsigned *)idPtr);
+#else
+ return CreateThread(NULL, (DWORD) stackSize,
+ proc, clientData, 0, (LPDWORD)idPtr);
+#endif
+}
+
+static void
+TclWinThreadExit(int status)
+{
+#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
+ _endthreadex((unsigned) status);
+#else
+ ExitThread((DWORD) status);
+#endif
+}
+
/*
*----------------------------------------------------------------------
* Declarations of helper-workers threaded facilities for a pipe based channel.
@@ -252,6 +297,10 @@ typedef struct TclPipeThreadInfo {
MODULE_SCOPE
TclPipeThreadInfo * TclPipeThreadCreateTI(TclPipeThreadInfo **pipeTIPtr,
ClientData clientData, HANDLE wakeEvent);
+MODULE_SCOPE HANDLE TclPipeThreadCreate(TclPipeThreadInfo **pipeTIPtr,
+ LPTHREAD_START_ROUTINE proc, ClientData clientData,
+ HANDLE wakeEvent);
+
MODULE_SCOPE int TclPipeThreadWaitForSignal(TclPipeThreadInfo **pipeTIPtr);
static inline void
diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c
index 8d269ba..068a6d6 100644
--- a/win/tclWinPipe.c
+++ b/win/tclWinPipe.c
@@ -1667,9 +1667,8 @@ TclpCreateCommandChannel(
*/
infoPtr->readable = CreateEvent(NULL, TRUE, TRUE, NULL);
- infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
- TclPipeThreadCreateTI(&infoPtr->readTI, infoPtr, infoPtr->readable),
- 0, NULL);
+ infoPtr->readThread = TclPipeThreadCreate(&infoPtr->readTI,
+ PipeReaderThread, infoPtr, infoPtr->readable);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
} else {
@@ -1682,9 +1681,8 @@ TclpCreateCommandChannel(
*/
infoPtr->writable = CreateEvent(NULL, TRUE, TRUE, NULL);
- infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
- TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr, infoPtr->writable),
- 0, NULL);
+ infoPtr->writeThread = TclPipeThreadCreate(&infoPtr->writeTI,
+ PipeWriterThread, infoPtr, infoPtr->writable);
SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
} else {
@@ -3035,6 +3033,31 @@ TclPipeThreadCreateTI(
/*
*----------------------------------------------------------------------
*
+ * TclPipeThreadCreate --
+ *
+ * Creates a pipe-worker thread and its thread info structure.
+ *
+ * Results:
+ * Pointer to created TI structure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+HANDLE
+TclPipeThreadCreate(
+ TclPipeThreadInfo **pipeTIPtr,/* Resulting thread info structure */
+ LPTHREAD_START_ROUTINE proc,/* Main() function of the thread. */
+ ClientData clientData, /* The one argument to Main(). */
+ HANDLE wakeEvent) /* Optional thread wake-up event */
+{
+ return TclWinThreadCreate(NULL, proc,
+ TclPipeThreadCreateTI(pipeTIPtr, clientData, wakeEvent), 256);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
* TclPipeThreadWaitForSignal --
*
* Wait for work/stop signals inside pipe worker.
@@ -3371,7 +3394,7 @@ TclPipeThreadExit(
* own it.
*/
if (!pipeTI) {
- return;
+ goto end;
}
*pipeTIPtr = NULL;
if ((state = InterlockedExchange(&pipeTI->state,
@@ -3388,6 +3411,9 @@ TclPipeThreadExit(
Tcl_FinalizeThread();
#endif
}
+
+ end:
+ TclWinThreadExit(0);
}
/*
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c
index 2f1f88c..707d3d5 100644
--- a/win/tclWinSerial.c
+++ b/win/tclWinSerial.c
@@ -1469,9 +1469,8 @@ TclWinOpenSerialChannel(
infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL);
- infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread,
- TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr,
- infoPtr->evWritable), 0, NULL);
+ infoPtr->writeThread = TclPipeThreadCreate(&infoPtr->writeTI,
+ SerialWriterThread, infoPtr, infoPtr->evWritable);
}
/*
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c
index 7828e65..a8ae484 100644
--- a/win/tclWinThrd.c
+++ b/win/tclWinThrd.c
@@ -223,18 +223,8 @@ TclpThreadCreate(
EnterCriticalSection(&joinLock);
- *idPtr = 0; /* must initialize as Tcl_Thread is a pointer and
- * on WIN64 sizeof void* != sizeof unsigned
- */
-
-#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
- tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize,
- (Tcl_ThreadCreateProc*) TclWinThreadStart, winThreadPtr,
- 0, (unsigned *)idPtr);
-#else
- tHandle = CreateThread(NULL, (DWORD) stackSize,
- TclWinThreadStart, winThreadPtr, 0, (LPDWORD)idPtr);
-#endif
+ tHandle = TclWinThreadCreate(idPtr, TclWinThreadStart, winThreadPtr,
+ stackSize);
if (tHandle == NULL) {
LeaveCriticalSection(&joinLock);
@@ -305,11 +295,7 @@ TclpThreadExit(
TclSignalExitThread(Tcl_GetCurrentThread(), status);
LeaveCriticalSection(&joinLock);
-#if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__)
- _endthreadex((unsigned) status);
-#else
- ExitThread((DWORD) status);
-#endif
+ TclWinThreadExit(status);
}
/*