diff options
author | sebres <sebres@users.sourceforge.net> | 2017-05-03 10:19:16 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-05-03 10:19:16 (GMT) |
commit | 3dd348e3693ea3a0e5b01646d0fe726bf21b9c8f (patch) | |
tree | 71da655a4dc260f18516b29f195135d50c79bd8a | |
parent | 286451604f908628de79417be012ff656652db05 (diff) | |
download | tcl-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.c | 10 | ||||
-rw-r--r-- | win/tclWinInt.h | 49 | ||||
-rw-r--r-- | win/tclWinPipe.c | 40 | ||||
-rw-r--r-- | win/tclWinSerial.c | 5 | ||||
-rw-r--r-- | win/tclWinThrd.c | 20 |
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); } /* |