Tcl Source Code

Artifact [6549b68737]
Login

Artifact 6549b68737d5444d162f0817506cda3fd3dcd04a:

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);