diff options
author | vasiljevic <zv@archiware.com> | 2006-03-10 14:27:41 (GMT) |
---|---|---|
committer | vasiljevic <zv@archiware.com> | 2006-03-10 14:27:41 (GMT) |
commit | c7c3c9503cff625b0809b5aad0f78f9819ea00ac (patch) | |
tree | 86eba32429c18cbbfffae4fe58b94a6695273b02 /win | |
parent | acf788d099066659a2bb0358eb317e3d5676f4aa (diff) | |
download | tcl-c7c3c9503cff625b0809b5aad0f78f9819ea00ac.zip tcl-c7c3c9503cff625b0809b5aad0f78f9819ea00ac.tar.gz tcl-c7c3c9503cff625b0809b5aad0f78f9819ea00ac.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.c | 134 |
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); |