summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorvasiljevic <zv@archiware.com>2006-03-10 14:27:41 (GMT)
committervasiljevic <zv@archiware.com>2006-03-10 14:27:41 (GMT)
commit5e0d82e5a916c0a59ba7a2827b695d74886edcf3 (patch)
tree86eba32429c18cbbfffae4fe58b94a6695273b02 /win
parent23596eee23da84c3e56fadc163dc8a2734b8f453 (diff)
downloadtcl-5e0d82e5a916c0a59ba7a2827b695d74886edcf3.zip
tcl-5e0d82e5a916c0a59ba7a2827b695d74886edcf3.tar.gz
tcl-5e0d82e5a916c0a59ba7a2827b695d74886edcf3.tar.bz2
Finalization of the sockets is now solely done in
TclpFinalizeSockets() and not over the thread-exit handler, because the order of actions the Tcl generic core will impose may result in cores/hangs if the thread exit handler tears down socket subsystem too early (See Tcl Bug #1437595).
Diffstat (limited to 'win')
-rw-r--r--win/tclWinSock.c134
1 files changed, 72 insertions, 62 deletions
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index 6643345..99913ea 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.4 2005/11/28 09:49:57 dkf Exp $
+ * RCS: @(#) $Id: tclWinSock.c,v 1.36.2.5 2006/03/10 14:27:41 vasiljevic Exp $
*/
#include "tclWinInt.h"
@@ -249,7 +249,6 @@ static LRESULT CALLBACK SocketProc _ANSI_ARGS_((HWND hwnd,
UINT message, WPARAM wParam,
LPARAM lParam));
static Tcl_EventSetupProc SocketSetupProc;
-static Tcl_ExitProc SocketThreadExitHandler;
static int SocketsEnabled _ANSI_ARGS_((void));
static void TcpAccept _ANSI_ARGS_((SocketInfo *infoPtr));
static Tcl_DriverBlockModeProc TcpBlockProc;
@@ -303,7 +302,7 @@ static Tcl_ChannelType tcpChannelType = {
* library and set up the winSock function table. If successful,
* registers the event window for the socket notifier code.
*
- * Assumes Mutex is held.
+ * Assumes socketMutex is held.
*
* Results:
* None.
@@ -491,45 +490,41 @@ InitSockets()
if (tsdPtr == NULL) {
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->socketList = NULL;
- tsdPtr->hwnd = NULL;
-
- tsdPtr->threadId = Tcl_GetCurrentThread();
-
+ tsdPtr->hwnd = NULL;
+ tsdPtr->threadId = Tcl_GetCurrentThread();
tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (tsdPtr->readyEvent == NULL) {
+ goto unloadLibrary;
+ }
tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
+ if (tsdPtr->socketListLock == NULL) {
+ goto unloadLibrary;
+ }
tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread,
tsdPtr, 0, &id);
- SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
-
if (tsdPtr->socketThread == NULL) {
goto unloadLibrary;
}
-
+
+ SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
/*
- * Wait for the thread to signal that the window has
- * been created and is ready to go. Timeout after twenty
- * seconds.
+ * Wait for the thread to signal when the window has
+ * been created and if it is ready to go.
*/
-
- if (WaitForSingleObject(tsdPtr->readyEvent, 20000)
- == WAIT_TIMEOUT) {
- goto unloadLibrary;
- }
+
+ WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
if (tsdPtr->hwnd == NULL) {
- goto unloadLibrary;
+ goto unloadLibrary; /* Trouble creating the window */
}
-
+
Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
- Tcl_CreateThreadExitHandler(SocketThreadExitHandler, NULL);
}
return;
unloadLibrary:
- if (tsdPtr != NULL && tsdPtr->hwnd != NULL) {
- SocketThreadExitHandler(0);
- }
+ TclpFinalizeSockets();
FreeLibrary(winSock.hModule);
winSock.hModule = NULL;
return;
@@ -568,7 +563,7 @@ SocketsEnabled()
*
* SocketExitHandler --
*
- * Callback invoked during exit clean up to delete the socket
+ * Callback invoked during app exit clean up to delete the socket
* communication window and to release the WinSock DLL.
*
* Results:
@@ -591,7 +586,7 @@ SocketExitHandler(clientData)
* Make sure the socket event handling window is cleaned-up
* for, at most, this thread.
*/
- SocketThreadExitHandler(clientData);
+ TclpFinalizeSockets();
UnregisterClass("TclSocket", TclWinGetTclInstance());
winSock.WSACleanup();
FreeLibrary(winSock.hModule);
@@ -605,49 +600,50 @@ SocketExitHandler(clientData)
/*
*----------------------------------------------------------------------
*
- * SocketThreadExitHandler --
+ * TclpFinalizeSockets --
*
- * Callback invoked during thread clean up to delete the socket
- * event source.
+ * This function is called from Tcl_FinalizeThread to finalize
+ * the platform specific socket subsystem.
+ * Also, it may be called from within this module to cleanup
+ * the state if unable to initialize the sockets subsystem.
*
* Results:
* None.
*
* Side effects:
- * Delete the event source.
+ * Deletes the event source and destroys the socket thread.
*
*----------------------------------------------------------------------
*/
- /* ARGSUSED */
-static void
-SocketThreadExitHandler(clientData)
- ClientData clientData; /* Not used. */
+void
+TclpFinalizeSockets()
{
- ThreadSpecificData *tsdPtr =
- (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
-
- if (tsdPtr != NULL && tsdPtr->socketThread != NULL) {
- DWORD exitCode;
-
- GetExitCodeThread(tsdPtr->socketThread, &exitCode);
- if (exitCode == STILL_ACTIVE) {
- PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
- /*
- * Wait for the thread to close. This ensures that we are
- * completely cleaned up before we leave this function.
- * If Tcl_Finalize was called from DllMain, the thread
- * is in a paused state so we need to timeout and continue.
- */
+ ThreadSpecificData *tsdPtr;
- WaitForSingleObject(tsdPtr->socketThread, 100);
+ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ if (tsdPtr != NULL) {
+ if (tsdPtr->socketThread != NULL) {
+ if (tsdPtr->hwnd != NULL) {
+ PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
+ /*
+ * Wait for the thread to exit. This ensures that we are
+ * completely cleaned up before we leave this function.
+ */
+ WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
+ tsdPtr->hwnd = NULL;
+ }
+ CloseHandle(tsdPtr->socketThread);
+ tsdPtr->socketThread = NULL;
+ }
+ if (tsdPtr->readyEvent != NULL) {
+ CloseHandle(tsdPtr->readyEvent);
+ tsdPtr->readyEvent = NULL;
+ }
+ if (tsdPtr->socketListLock != NULL) {
+ CloseHandle(tsdPtr->socketListLock);
+ tsdPtr->socketListLock = NULL;
}
- CloseHandle(tsdPtr->socketThread);
- tsdPtr->socketThread = NULL;
- CloseHandle(tsdPtr->readyEvent);
- CloseHandle(tsdPtr->socketListLock);
-
- Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL);
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
}
}
@@ -1033,7 +1029,6 @@ NewSocketInfo(socket)
SOCKET socket;
{
SocketInfo *infoPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
infoPtr->socket = socket;
@@ -2324,28 +2319,43 @@ SocketThread(LPVOID arg)
MSG msg;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)(arg);
+ /*
+ * Create a dummy window receiving socket events.
+ */
+
tsdPtr->hwnd = CreateWindow("TclSocket", "TclSocket",
WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
/*
- * Signal the main thread that the window has been created
- * and that the socket thread is ready to go.
+ * Signalize thread creator that we are done creating the window.
*/
-
+
SetEvent(tsdPtr->readyEvent);
-
+
+ /*
+ * If unable to create the window, exit this thread immediately.
+ */
+
if (tsdPtr->hwnd == NULL) {
return 1;
}
/*
* Process all messages on the socket window until WM_QUIT.
+ * This threads exits only when instructed to do so by the
+ * call to PostMessage(SOCKET_TERMINATE) in TclpFinalizeSockets().
*/
while (GetMessage(&msg, NULL, 0, 0) > 0) {
DispatchMessage(&msg);
}
+ /*
+ * This releases waiters on thread exit in TclpFinalizeSockets()
+ */
+
+ SetEvent(tsdPtr->readyEvent);
+
return msg.wParam;
}
@@ -2703,7 +2713,7 @@ TcpThreadActionProc (instanceData, action)
notifyCmd = SELECT;
} else {
- SocketInfo **nextPtrPtr;
+ SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);