Attachment "1437595.patch" to
ticket [1437595fff]
added by
dgp
2006-03-01 01:34:22.
Index: generic/tclEvent.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclEvent.c,v
retrieving revision 1.28.2.13
diff -u -r1.28.2.13 tclEvent.c
--- generic/tclEvent.c 16 Aug 2005 15:23:56 -0000 1.28.2.13
+++ generic/tclEvent.c 28 Feb 2006 18:27:56 -0000
@@ -961,9 +961,9 @@
Tcl_FinalizeThread()
{
ExitHandler *exitPtr;
- ThreadSpecificData *tsdPtr =
- (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ ThreadSpecificData *tsdPtr;
+ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr != NULL) {
tsdPtr->inExit = 1;
@@ -994,17 +994,17 @@
TclFinalizeAsync();
}
- /*
- * Blow away all thread local storage blocks.
+ /*
+ * Blow away all thread local storage blocks.
*
* Note that Tcl API allows creation of threads which do not use any
* Tcl interp or other Tcl subsytems. Those threads might, however,
* use thread local storage, so we must unconditionally finalize it.
*
* Fix [Bug #571002]
- */
+ */
- TclFinalizeThreadData();
+ TclFinalizeThreadData();
}
/*
Index: generic/tclIO.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIO.c,v
retrieving revision 1.61.2.18
diff -u -r1.61.2.18 tclIO.c
--- generic/tclIO.c 15 Feb 2006 16:04:27 -0000 1.61.2.18
+++ generic/tclIO.c 28 Feb 2006 18:27:56 -0000
@@ -185,7 +185,7 @@
*
* TclFinalizeIOSubsystem --
*
- * Releases all resources used by this subsystem on a per-process
+ * Releases all resources used by this subsystem on a per-thread
* basis. Closes all extant channels that have not already been
* closed because they were not owned by any interp.
*
@@ -207,6 +207,11 @@
ChannelState *nextCSPtr; /* Iterates over open channels. */
ChannelState *statePtr; /* state of channel stack */
+ /*
+ * Walk all channel state structures known to this thread and
+ * close corresponding channels.
+ */
+
for (statePtr = tsdPtr->firstCSPtr; statePtr != (ChannelState *) NULL;
statePtr = nextCSPtr) {
chanPtr = statePtr->topChanPtr;
@@ -234,7 +239,9 @@
* Preserve statePtr from disappearing until we can get the
* nextCSPtr below.
*/
+
Tcl_Preserve(statePtr);
+
if (statePtr->refCount <= 0) {
/*
@@ -244,7 +251,9 @@
*/
(void) Tcl_Close((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr);
+
} else {
+
/*
* The refcount is greater than zero, so flush the channel.
*/
@@ -274,13 +283,17 @@
chanPtr->instanceData = (ClientData) NULL;
statePtr->flags |= CHANNEL_DEAD;
}
+
/*
* We look for the next pointer now in case we had one closed on up
* during the current channel's closeproc (eg: rechan extension)
*/
+
nextCSPtr = statePtr->nextCSPtr;
Tcl_Release(statePtr);
- }
+ }
+
+ TclpFinalizeSockets();
TclpFinalizePipes();
}
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.118.2.21
diff -u -r1.118.2.21 tclInt.h
--- generic/tclInt.h 27 Nov 2005 02:34:41 -0000 1.118.2.21
+++ generic/tclInt.h 28 Feb 2006 18:27:57 -0000
@@ -1742,6 +1742,7 @@
Tcl_Condition *condPtr));
EXTERN void TclpFinalizeMutex _ANSI_ARGS_((Tcl_Mutex *mutexPtr));
EXTERN void TclpFinalizePipes _ANSI_ARGS_((void));
+EXTERN void TclpFinalizeSockets _ANSI_ARGS_((void));
EXTERN void TclpFinalizeThreadData _ANSI_ARGS_((
Tcl_ThreadDataKey *keyPtr));
EXTERN void TclpFinalizeThreadDataKey _ANSI_ARGS_((
Index: mac/tclMacSock.c
===================================================================
RCS file: /cvsroot/tcl/tcl/mac/Attic/tclMacSock.c,v
retrieving revision 1.14
diff -u -r1.14 tclMacSock.c
--- mac/tclMacSock.c 8 Apr 2002 09:03:17 -0000 1.14
+++ mac/tclMacSock.c 28 Feb 2006 18:27:57 -0000
@@ -159,7 +159,6 @@
int flags));
static int SocketEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
int flags));
-static void SocketExitHandler _ANSI_ARGS_((ClientData clientData));
static void SocketFreeProc _ANSI_ARGS_((ClientData clientData));
static int SocketReady _ANSI_ARGS_((TcpState *statePtr));
static void SocketSetupProc _ANSI_ARGS_((ClientData clientData,
@@ -367,37 +366,36 @@
tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr == NULL) {
+ tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->socketList = NULL;
Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
- Tcl_CreateThreadExitHandler(SocketExitHandler, (ClientData) NULL);
}
}
/*
*----------------------------------------------------------------------
*
- * SocketExitHandler --
+ * TclpFinalizeSockets --
*
- * Callback invoked during exit clean up to deinitialize the
- * socket module.
+ * Invoked during exit clean up to deinitialize the socket module.
*
* Results:
* None.
*
* Side effects:
- * None.
+ * Removed event source.
*
*----------------------------------------------------------------------
*/
-static void
-SocketExitHandler(
- ClientData clientData) /* Not used. */
+void
+TclpFinalizeSockets()
{
- if (hasSockets) {
+ ThreadSpecificData *tsdPtr;
+
+ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ if (tsdPtr != NULL) {
Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
- /* CleanUpExitProc();
- TclMacDeleteExitToShellPatch(CleanUpExitProc); */
}
}
Index: unix/tclUnixPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPipe.c,v
retrieving revision 1.23.2.5
diff -u -r1.23.2.5 tclUnixPipe.c
--- unix/tclUnixPipe.c 28 Jul 2005 15:27:59 -0000 1.23.2.5
+++ unix/tclUnixPipe.c 28 Feb 2006 18:27:57 -0000
@@ -1258,7 +1258,8 @@
* Results:
* None.
*
- * This procedure carries out no operation on Unix.
+ * Side effects:
+ * None.
*
*----------------------------------------------------------------------
*/
@@ -1266,5 +1267,6 @@
void
TclpFinalizePipes()
{
+ return;
}
Index: unix/tclUnixSock.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixSock.c,v
retrieving revision 1.6
diff -u -r1.6 tclUnixSock.c
--- unix/tclUnixSock.c 27 Feb 2002 01:16:43 -0000 1.6
+++ unix/tclUnixSock.c 28 Feb 2006 18:27:57 -0000
@@ -148,3 +148,25 @@
{
return TCL_OK;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpFinalizeSockets --
+ *
+ * Performs per-thread socket subsystem finalization.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclpFinalizeSockets()
+{
+ return;
+}
Index: win/tclWinPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinPipe.c,v
retrieving revision 1.33.2.15
diff -u -r1.33.2.15 tclWinPipe.c
--- win/tclWinPipe.c 4 Nov 2005 18:33:35 -0000 1.33.2.15
+++ win/tclWinPipe.c 28 Feb 2006 18:27:58 -0000
@@ -189,7 +189,6 @@
static int PipeClose2Proc(ClientData instanceData,
Tcl_Interp *interp, int flags);
static int PipeEventProc(Tcl_Event *evPtr, int flags);
-static void PipeExitHandler(ClientData clientData);
static int PipeGetHandleProc(ClientData instanceData,
int direction, ClientData *handlePtr);
static void PipeInit(void);
@@ -271,57 +270,35 @@
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->firstPipePtr = NULL;
Tcl_CreateEventSource(PipeSetupProc, PipeCheckProc, NULL);
- Tcl_CreateThreadExitHandler(PipeExitHandler, NULL);
}
}
/*
*----------------------------------------------------------------------
*
- * PipeExitHandler --
- *
- * This function is called to cleanup the pipe module before
- * Tcl is unloaded.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Removes the pipe event source.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-PipeExitHandler(
- ClientData clientData) /* Old window proc */
-{
- Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL);
-}
-
-/*
- *----------------------------------------------------------------------
- *
* TclpFinalizePipes --
*
- * This function is called to cleanup the process list before
- * Tcl is unloaded.
+ * This function is called from Tcl_FinalizeThread to finalize the
+ * platform specific pipe subsystem.
*
* Results:
* None.
*
* Side effects:
- * Resets the process list.
+ * Removes the pipe event source.
*
*----------------------------------------------------------------------
*/
void
TclpFinalizePipes()
-{
- Tcl_MutexLock(&pipeMutex);
- initialized = 0;
- Tcl_MutexUnlock(&pipeMutex);
+{
+ ThreadSpecificData *tsdPtr;
+
+ tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
+ if (tsdPtr != NULL) {
+ Tcl_DeleteEventSource(PipeSetupProc, PipeCheckProc, NULL);
+ }
}
/*
Index: win/tclWinSock.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinSock.c,v
retrieving revision 1.36.2.4
diff -u -r1.36.2.4 tclWinSock.c
--- win/tclWinSock.c 28 Nov 2005 09:49:57 -0000 1.36.2.4
+++ win/tclWinSock.c 28 Feb 2006 18:27:58 -0000
@@ -249,7 +249,6 @@
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 @@
* 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 @@
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 @@
*
* 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 @@
* 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 @@
/*
*----------------------------------------------------------------------
*
- * 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 @@
SOCKET socket;
{
SocketInfo *infoPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
infoPtr->socket = socket;
@@ -2324,28 +2319,43 @@
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;
+ return 1;
}
/*
* Process all messages on the socket window until WM_QUIT.
+ * This threads exits only when istructed 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 @@
notifyCmd = SELECT;
} else {
- SocketInfo **nextPtrPtr;
+ SocketInfo **nextPtrPtr;
int removed = 0;
tsdPtr = TCL_TSD_INIT(&dataKey);