Tcl Source Code

Artifact [b272a0f070]
Login

Artifact b272a0f0707f8ad0987fae5e561408ad6cc5483a:

Attachment "tcl-setnotifier.diff" to ticket [1938497fff] added by das 2008-04-16 21:22:55.
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.363
diff -u -p -r1.363 tclInt.h
--- generic/tclInt.h	30 Mar 2008 04:26:16 -0000	1.363
+++ generic/tclInt.h	16 Apr 2008 13:53:20 -0000
@@ -2357,7 +2357,7 @@ MODULE_SCOPE char *	tclNativeExecutableN
 MODULE_SCOPE int	tclFindExecutableSearchDone;
 MODULE_SCOPE char *	tclMemDumpFileName;
 MODULE_SCOPE TclPlatformType tclPlatform;
-MODULE_SCOPE Tcl_NotifierProcs tclOriginalNotifier;
+MODULE_SCOPE Tcl_NotifierProcs tclNotifierHooks;
 
 /*
  * TIP #233 (Virtualized Time)
Index: generic/tclNotify.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNotify.c,v
retrieving revision 1.25
diff -u -p -r1.25 tclNotify.c
--- generic/tclNotify.c	25 Sep 2006 15:02:54 -0000	1.25
+++ generic/tclNotify.c	16 Apr 2008 13:53:22 -0000
@@ -19,7 +19,14 @@
 
 #include "tclInt.h"
 
-extern TclStubs tclStubs;
+/*
+ * Module-scope struct of notifier hooks that are checked in the default
+ * notifier functions (for overriding via Tcl_SetNotifier).
+ */
+
+Tcl_NotifierProcs tclNotifierHooks = {
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
 
 /*
  * For each event source (created with Tcl_CreateEventSource) there is a
@@ -128,7 +135,7 @@ TclInitNotifier(void)
 
 	tsdPtr = TCL_TSD_INIT(&dataKey);
 	tsdPtr->threadId = threadId;
-	tsdPtr->clientData = tclStubs.tcl_InitNotifier();
+	tsdPtr->clientData = Tcl_InitNotifier();
 	tsdPtr->initialized = 1;
 	tsdPtr->nextPtr = firstNotifierPtr;
 	firstNotifierPtr = tsdPtr;
@@ -184,9 +191,7 @@ TclFinalizeNotifier(void)
 
     Tcl_MutexLock(&listLock);
 
-    if (tclStubs.tcl_FinalizeNotifier) {
-	tclStubs.tcl_FinalizeNotifier(tsdPtr->clientData);
-    }
+    Tcl_FinalizeNotifier(tsdPtr->clientData);
     Tcl_MutexFinalize(&(tsdPtr->queueMutex));
     for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
 	    prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {
@@ -213,9 +218,8 @@ TclFinalizeNotifier(void)
  *	None.
  *
  * Side effects:
- *	Overstomps part of the stub vector. This relies on hooks added to the
- *	default functions in case those are called directly (i.e., not through
- *	the stub table.)
+ *	Set the tclNotifierHooks global, which is checked in the default
+ *	notifier functions.
  *
  *----------------------------------------------------------------------
  */
@@ -224,16 +228,7 @@ void
 Tcl_SetNotifier(
     Tcl_NotifierProcs *notifierProcPtr)
 {
-#if !defined(__WIN32__) /* UNIX */
-    tclStubs.tcl_CreateFileHandler = notifierProcPtr->createFileHandlerProc;
-    tclStubs.tcl_DeleteFileHandler = notifierProcPtr->deleteFileHandlerProc;
-#endif
-    tclStubs.tcl_SetTimer = notifierProcPtr->setTimerProc;
-    tclStubs.tcl_WaitForEvent = notifierProcPtr->waitForEventProc;
-    tclStubs.tcl_InitNotifier = notifierProcPtr->initNotifierProc;
-    tclStubs.tcl_FinalizeNotifier = notifierProcPtr->finalizeNotifierProc;
-    tclStubs.tcl_AlertNotifier = notifierProcPtr->alertNotifierProc;
-    tclStubs.tcl_ServiceModeHook = notifierProcPtr->serviceModeHookProc;
+    tclNotifierHooks = *notifierProcPtr;
 }
 
 /*
@@ -774,9 +769,7 @@ Tcl_SetServiceMode(
 
     oldMode = tsdPtr->serviceMode;
     tsdPtr->serviceMode = mode;
-    if (tclStubs.tcl_ServiceModeHook) {
-	tclStubs.tcl_ServiceModeHook(mode);
-    }
+    Tcl_ServiceModeHook(mode);
     return oldMode;
 }
 
@@ -1136,9 +1129,7 @@ Tcl_ThreadAlert(
     Tcl_MutexLock(&listLock);
     for (tsdPtr = firstNotifierPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
 	if (tsdPtr->threadId == threadId) {
-	    if (tclStubs.tcl_AlertNotifier) {
-		tclStubs.tcl_AlertNotifier(tsdPtr->clientData);
-	    }
+	    Tcl_AlertNotifier(tsdPtr->clientData);
 	    break;
 	}
     }
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.151
diff -u -p -r1.151 tclStubInit.c
--- generic/tclStubInit.c	2 Apr 2008 21:30:04 -0000	1.151
+++ generic/tclStubInit.c	16 Apr 2008 13:53:42 -0000
@@ -34,29 +34,6 @@
 #undef Tcl_FindHashEntry
 #undef Tcl_CreateHashEntry
 
-/*
- * Keep a record of the original Notifier procedures, created in the
- * same compilation unit as the stub tables so we can later do reliable,
- * portable comparisons to see whether a Tcl_SetNotifier() call swapped
- * new routines into the stub table.
- */
-
-Tcl_NotifierProcs tclOriginalNotifier = {
-    Tcl_SetTimer,
-    Tcl_WaitForEvent,
-#if !defined(__WIN32__) /* UNIX */
-    Tcl_CreateFileHandler,
-    Tcl_DeleteFileHandler,
-#else
-    NULL,
-    NULL,
-#endif
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
 MODULE_SCOPE TclIntStubs tclIntStubs;
 MODULE_SCOPE TclIntPlatStubs tclIntPlatStubs;
 MODULE_SCOPE TclPlatStubs tclPlatStubs;
Index: macosx/tclMacOSXNotify.c
===================================================================
RCS file: /cvsroot/tcl/tcl/macosx/tclMacOSXNotify.c,v
retrieving revision 1.18
diff -u -p -r1.18 tclMacOSXNotify.c
--- macosx/tclMacOSXNotify.c	11 Mar 2008 22:24:17 -0000	1.18
+++ macosx/tclMacOSXNotify.c	16 Apr 2008 13:53:48 -0000
@@ -21,9 +21,6 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include <pthread.h>
 
-extern TclStubs tclStubs;
-extern Tcl_NotifierProcs tclOriginalNotifier;
-
 /*
  * This structure is used to keep track of the notifier info for a registered
  * file.
@@ -351,105 +348,113 @@ MODULE_SCOPE long tclMacOSXDarwinRelease
 ClientData
 Tcl_InitNotifier(void)
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+    if (tclNotifierHooks.initNotifierProc) {
+	return tclNotifierHooks.initNotifierProc();
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    tsdPtr->eventReady = 0;
+	tsdPtr->eventReady = 0;
 
 #ifdef WEAK_IMPORT_SPINLOCKLOCK
-    /*
-     * Initialize support for weakly imported spinlock API.
-     */
-    if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) {
-	Tcl_Panic("Tcl_InitNotifier: pthread_once failed");
-    }
+	/*
+	 * Initialize support for weakly imported spinlock API.
+	 */
+	if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) {
+	    Tcl_Panic("Tcl_InitNotifier: pthread_once failed");
+	}
 #endif
 
 #ifndef __CONSTANT_CFSTRINGS__
-    if (!tclEventsOnlyRunLoopMode) {
-	tclEventsOnlyRunLoopMode = CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE);
-    }
+	if (!tclEventsOnlyRunLoopMode) {
+	    tclEventsOnlyRunLoopMode = CFSTR(TCL_EVENTS_ONLY_RUN_LOOP_MODE);
+	}
 #endif
 
-    /*
-     * Initialize CFRunLoopSource and add it to CFRunLoop of this thread.
-     */
+	/*
+	 * Initialize CFRunLoopSource and add it to CFRunLoop of this thread.
+	 */
 
-    if (!tsdPtr->runLoop) {
-	CFRunLoopRef runLoop = CFRunLoopGetCurrent();
-	CFRunLoopSourceRef runLoopSource;
-	CFRunLoopSourceContext runLoopSourceContext;
-
-	bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext));
-	runLoopSourceContext.info = tsdPtr;
-	runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext);
-	if (!runLoopSource) {
-	    Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource");
-	}
-	CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes);
-	CFRunLoopAddSource(runLoop, runLoopSource, tclEventsOnlyRunLoopMode);
-	tsdPtr->runLoopSource = runLoopSource;
-	tsdPtr->runLoop = runLoop;
-    }
+	if (!tsdPtr->runLoop) {
+	    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
+	    CFRunLoopSourceRef runLoopSource;
+	    CFRunLoopSourceContext runLoopSourceContext;
+
+	    bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext));
+	    runLoopSourceContext.info = tsdPtr;
+	    runLoopSource = CFRunLoopSourceCreate(NULL, 0,
+		    &runLoopSourceContext);
+	    if (!runLoopSource) {
+		Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource");
+	    }
+	    CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes);
+	    CFRunLoopAddSource(runLoop, runLoopSource,
+		    tclEventsOnlyRunLoopMode);
+	    tsdPtr->runLoopSource = runLoopSource;
+	    tsdPtr->runLoop = runLoop;
+	}
 
-    LOCK_NOTIFIER_INIT;
+	LOCK_NOTIFIER_INIT;
 #ifdef HAVE_PTHREAD_ATFORK
-    /*
-     * Install pthread_atfork handlers to reinitialize the notifier in the
-     * child of a fork.
-     */
+	/*
+	 * Install pthread_atfork handlers to reinitialize the notifier in the
+	 * child of a fork.
+	 */
 
-    if (
+	if (
 #ifdef WEAK_IMPORT_PTHREAD_ATFORK
-	    pthread_atfork != NULL &&
+		pthread_atfork != NULL &&
 #endif
-	    !atForkInit) {
-	int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
-	if (result) {
-	    Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
+		!atForkInit) {
+	    int result = pthread_atfork(AtForkPrepare, AtForkParent,
+		    AtForkChild);
+
+	    if (result) {
+		Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
+	    }
+	    atForkInit = 1;
 	}
-	atForkInit = 1;
-    }
 #endif
-    if (notifierCount == 0) {
-	int fds[2], status;
+	if (notifierCount == 0) {
+	    int fds[2], status;
 
-	/*
-	 * Initialize trigger pipe.
-	 */
+	    /*
+	     * Initialize trigger pipe.
+	     */
 
-	if (pipe(fds) != 0) {
-	    Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe");
-	}
+	    if (pipe(fds) != 0) {
+		Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe");
+	    }
 
-	status = fcntl(fds[0], F_GETFL);
-	status |= O_NONBLOCK;
-	if (fcntl(fds[0], F_SETFL, status) < 0) {
-	    Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non blocking");
-	}
-	status = fcntl(fds[1], F_GETFL);
-	status |= O_NONBLOCK;
-	if (fcntl(fds[1], F_SETFL, status) < 0) {
-	    Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non blocking");
-	}
+	    status = fcntl(fds[0], F_GETFL);
+	    status |= O_NONBLOCK;
+	    if (fcntl(fds[0], F_SETFL, status) < 0) {
+		Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non blocking");
+	    }
+	    status = fcntl(fds[1], F_GETFL);
+	    status |= O_NONBLOCK;
+	    if (fcntl(fds[1], F_SETFL, status) < 0) {
+		Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non blocking");
+	    }
 
-	receivePipe = fds[0];
-	triggerPipe = fds[1];
+	    receivePipe = fds[0];
+	    triggerPipe = fds[1];
 
-	/*
-	 * Create notifier thread lazily in Tcl_WaitForEvent() to avoid
-	 * interfering with fork() followed immediately by execve()
-	 * (cannot execve() when more than one thread is present).
-	 */
+	    /*
+	     * Create notifier thread lazily in Tcl_WaitForEvent() to avoid
+	     * interfering with fork() followed immediately by execve()
+	     * (cannot execve() when more than one thread is present).
+	     */
 
-	notifierThread = 0;
+	    notifierThread = 0;
 #ifdef TCL_MAC_DEBUG_NOTIFIER
-	OPEN_NOTIFIER_LOG;
+	    OPEN_NOTIFIER_LOG;
 #endif
-    }
-    notifierCount++;
-    UNLOCK_NOTIFIER_INIT;
+	}
+	notifierCount++;
+	UNLOCK_NOTIFIER_INIT;
 
-    return (ClientData) tsdPtr;
+	return (ClientData) tsdPtr;
+    }
 }
 
 /*
@@ -474,66 +479,71 @@ void
 Tcl_FinalizeNotifier(
     ClientData clientData)		/* Not used. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+    if (tclNotifierHooks.finalizeNotifierProc) {
+	tclNotifierHooks.finalizeNotifierProc(clientData);
+	return;
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    LOCK_NOTIFIER_INIT;
-    notifierCount--;
+	LOCK_NOTIFIER_INIT;
+	notifierCount--;
 
-    /*
-     * If this is the last thread to use the notifier, close the notifier pipe
-     * and wait for the background thread to terminate.
-     */
+	/*
+	 * If this is the last thread to use the notifier, close the notifier
+	 * pipe and wait for the background thread to terminate.
+	 */
 
-    if (notifierCount == 0) {
-	int result;
+	if (notifierCount == 0) {
+	    int result;
 
-	if (triggerPipe < 0) {
-	    Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
-	}
+	    if (triggerPipe < 0) {
+		Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
+	    }
 
-	/*
-	 * Send "q" message to the notifier thread so that it will terminate.
-	 * The notifier will return from its call to select() and notice that
-	 * a "q" message has arrived, it will then close its side of the pipe
-	 * and terminate its thread. Note the we can not just close the pipe
-	 * and check for EOF in the notifier thread because if a background
-	 * child process was created with exec, select() would not register
-	 * the EOF on the pipe until the child processes had terminated. [Bug:
-	 * 4139] [Bug: 1222872]
-	 */
+	    /*
+	     * Send "q" message to the notifier thread so that it will
+	     * terminate. The notifier will return from its call to select()
+	     * and notice that a "q" message has arrived, it will then close
+	     * its side of the pipe and terminate its thread. Note the we can
+	     * not just close the pipe and check for EOF in the notifier thread
+	     * because if a background child process was created with exec,
+	     * select() would not register the EOF on the pipe until the child
+	     * processes had terminated. [Bug: 4139] [Bug: 1222872]
+	     */
 
-	write(triggerPipe, "q", 1);
-	close(triggerPipe);
+	    write(triggerPipe, "q", 1);
+	    close(triggerPipe);
 
-	if (notifierThread) {
-	    result = pthread_join(notifierThread, NULL);
-	    if (result) {
-		Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread");
+	    if (notifierThread) {
+		result = pthread_join(notifierThread, NULL);
+		if (result) {
+		    Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread");
+		}
+		notifierThread = 0;
 	    }
-	    notifierThread = 0;
-	}
 
-	close(receivePipe);
-	triggerPipe = -1;
+	    close(receivePipe);
+	    triggerPipe = -1;
 #ifdef TCL_MAC_DEBUG_NOTIFIER
-	CLOSE_NOTIFIER_LOG;
+	    CLOSE_NOTIFIER_LOG;
 #endif
-    }
-    UNLOCK_NOTIFIER_INIT;
+	}
+	UNLOCK_NOTIFIER_INIT;
 
-    LOCK_NOTIFIER;		/* for concurrency with Tcl_AlertNotifier */
-    if (tsdPtr->runLoop) {
-	tsdPtr->runLoop = NULL;
+	LOCK_NOTIFIER;		/* for concurrency with Tcl_AlertNotifier */
+	if (tsdPtr->runLoop) {
+	    tsdPtr->runLoop = NULL;
 
-	/*
-	 * Remove runLoopSource from all CFRunLoops and release it.
-	 */
+	    /*
+	     * Remove runLoopSource from all CFRunLoops and release it.
+	     */
 
-	CFRunLoopSourceInvalidate(tsdPtr->runLoopSource);
-	CFRelease(tsdPtr->runLoopSource);
-	tsdPtr->runLoopSource = NULL;
+	    CFRunLoopSourceInvalidate(tsdPtr->runLoopSource);
+	    CFRelease(tsdPtr->runLoopSource);
+	    tsdPtr->runLoopSource = NULL;
+	}
+	UNLOCK_NOTIFIER;
     }
-    UNLOCK_NOTIFIER;
 }
 
 /*
@@ -559,15 +569,20 @@ void
 Tcl_AlertNotifier(
     ClientData clientData)
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+    if (tclNotifierHooks.alertNotifierProc) {
+	tclNotifierHooks.alertNotifierProc(clientData);
+	return;
+    } else {
+	ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
 
-    LOCK_NOTIFIER;
-    if (tsdPtr->runLoop) {
-	tsdPtr->eventReady = 1;
-	CFRunLoopSourceSignal(tsdPtr->runLoopSource);
-	CFRunLoopWakeUp(tsdPtr->runLoop);
+	LOCK_NOTIFIER;
+	if (tsdPtr->runLoop) {
+	    tsdPtr->eventReady = 1;
+	    CFRunLoopSourceSignal(tsdPtr->runLoopSource);
+	    CFRunLoopWakeUp(tsdPtr->runLoop);
+	}
+	UNLOCK_NOTIFIER;
     }
-    UNLOCK_NOTIFIER;
 }
 
 /*
@@ -592,14 +607,15 @@ void
 Tcl_SetTimer(
     Tcl_Time *timePtr)		/* Timeout value, may be NULL. */
 {
-    /*
-     * The interval timer doesn't do anything in this implementation, because
-     * the only event loop is via Tcl_DoOneEvent, which passes timeout values
-     * to Tcl_WaitForEvent.
-     */
-
-    if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
-	tclStubs.tcl_SetTimer(timePtr);
+    if (tclNotifierHooks.setTimerProc) {
+	tclNotifierHooks.setTimerProc(timePtr);
+	return;
+    } else {
+	/*
+	 * The interval timer doesn't do anything in this implementation,
+	 * because the only event loop is via Tcl_DoOneEvent, which passes
+	 * timeout values to Tcl_WaitForEvent.
+	 */
     }
 }
 
@@ -624,6 +640,12 @@ Tcl_ServiceModeHook(
     int mode)			/* Either TCL_SERVICE_ALL, or
 				 * TCL_SERVICE_NONE. */
 {
+    if (tclNotifierHooks.serviceModeHookProc) {
+	tclNotifierHooks.serviceModeHookProc(mode);
+	return;
+    } else {
+	/* Does nothing in this implementation. */
+    }
 }
 
 /*
@@ -653,53 +675,52 @@ Tcl_CreateFileHandler(
 				 * event. */
     ClientData clientData)	/* Arbitrary data to pass to proc. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    FileHandler *filePtr;
-
-    if (tclStubs.tcl_CreateFileHandler !=
-	    tclOriginalNotifier.createFileHandlerProc) {
-	tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);
+    if (tclNotifierHooks.createFileHandlerProc) {
+	tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
 	return;
-    }
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	FileHandler *filePtr;
 
-    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
-	    filePtr = filePtr->nextPtr) {
-	if (filePtr->fd == fd) {
-	    break;
+	for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
+		filePtr = filePtr->nextPtr) {
+	    if (filePtr->fd == fd) {
+		break;
+	    }
 	}
-    }
-    if (filePtr == NULL) {
-	filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
-	filePtr->fd = fd;
-	filePtr->readyMask = 0;
-	filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
-	tsdPtr->firstFileHandlerPtr = filePtr;
-    }
-    filePtr->proc = proc;
-    filePtr->clientData = clientData;
-    filePtr->mask = mask;
+	if (filePtr == NULL) {
+	    filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
+	    filePtr->fd = fd;
+	    filePtr->readyMask = 0;
+	    filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
+	    tsdPtr->firstFileHandlerPtr = filePtr;
+	}
+	filePtr->proc = proc;
+	filePtr->clientData = clientData;
+	filePtr->mask = mask;
 
-    /*
-     * Update the check masks for this file.
-     */
+	/*
+	 * Update the check masks for this file.
+	 */
 
-    if (mask & TCL_READABLE) {
-	FD_SET(fd, &(tsdPtr->checkMasks.readable));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.readable));
-    }
-    if (mask & TCL_WRITABLE) {
-	FD_SET(fd, &(tsdPtr->checkMasks.writable));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.writable));
-    }
-    if (mask & TCL_EXCEPTION) {
-	FD_SET(fd, &(tsdPtr->checkMasks.exceptional));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
-    }
-    if (tsdPtr->numFdBits <= fd) {
-	tsdPtr->numFdBits = fd+1;
+	if (mask & TCL_READABLE) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.readable));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+	}
+	if (mask & TCL_WRITABLE) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.writable));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+	}
+	if (mask & TCL_EXCEPTION) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.exceptional));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+	}
+	if (tsdPtr->numFdBits <= fd) {
+	    tsdPtr->numFdBits = fd+1;
+	}
     }
 }
 
@@ -724,70 +745,69 @@ Tcl_DeleteFileHandler(
     int fd)			/* Stream id for which to remove callback
 				 * function. */
 {
-    FileHandler *filePtr, *prevPtr;
-    int i;
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-    if (tclStubs.tcl_DeleteFileHandler !=
-	    tclOriginalNotifier.deleteFileHandlerProc) {
-	tclStubs.tcl_DeleteFileHandler(fd);
+    if (tclNotifierHooks.deleteFileHandlerProc) {
+	tclNotifierHooks.deleteFileHandlerProc(fd);
 	return;
-    }
+    } else {
+	FileHandler *filePtr, *prevPtr;
+	int i;
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    /*
-     * Find the entry for the given file (and return if there isn't one).
-     */
+	/*
+	 * Find the entry for the given file (and return if there isn't one).
+	 */
 
-    for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
-	 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
-	if (filePtr == NULL) {
-	    return;
-	}
-	if (filePtr->fd == fd) {
-	    break;
+	for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
+	     prevPtr = filePtr, filePtr = filePtr->nextPtr) {
+	    if (filePtr == NULL) {
+		return;
+	    }
+	    if (filePtr->fd == fd) {
+		break;
+	    }
 	}
-    }
 
-    /*
-     * Update the check masks for this file.
-     */
+	/*
+	 * Update the check masks for this file.
+	 */
 
-    if (filePtr->mask & TCL_READABLE) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.readable));
-    }
-    if (filePtr->mask & TCL_WRITABLE) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.writable));
-    }
-    if (filePtr->mask & TCL_EXCEPTION) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
-    }
+	if (filePtr->mask & TCL_READABLE) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+	}
+	if (filePtr->mask & TCL_WRITABLE) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+	}
+	if (filePtr->mask & TCL_EXCEPTION) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+	}
 
-    /*
-     * Find current max fd.
-     */
+	/*
+	 * Find current max fd.
+	 */
 
-    if (fd+1 == tsdPtr->numFdBits) {
-	tsdPtr->numFdBits = 0;
-	for (i = fd-1; i >= 0; i--) {
-	    if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
-		    || FD_ISSET(i, &(tsdPtr->checkMasks.writable))
-		    || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
-		tsdPtr->numFdBits = i+1;
-		break;
+	if (fd+1 == tsdPtr->numFdBits) {
+	    tsdPtr->numFdBits = 0;
+	    for (i = fd-1; i >= 0; i--) {
+		if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
+			|| FD_ISSET(i, &(tsdPtr->checkMasks.writable))
+			|| FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
+		    tsdPtr->numFdBits = i+1;
+		    break;
+		}
 	    }
 	}
-    }
 
-    /*
-     * Clean up information in the callback record.
-     */
+	/*
+	 * Clean up information in the callback record.
+	 */
 
-    if (prevPtr == NULL) {
-	tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
-    } else {
-	prevPtr->nextPtr = filePtr->nextPtr;
+	if (prevPtr == NULL) {
+	    tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+	} else {
+	    prevPtr->nextPtr = filePtr->nextPtr;
+	}
+	ckfree((char *) filePtr);
     }
-    ckfree((char *) filePtr);
 }
 
 /*
@@ -885,195 +905,203 @@ int
 Tcl_WaitForEvent(
     Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
 {
-    FileHandler *filePtr;
-    FileHandlerEvent *fileEvPtr;
-    int mask;
-    Tcl_Time myTime;
-    int waitForFiles;
-    Tcl_Time *myTimePtr;
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-    if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
-	return tclStubs.tcl_WaitForEvent(timePtr);
-    }
+    if (tclNotifierHooks.waitForEventProc) {
+	return tclNotifierHooks.waitForEventProc(timePtr);
+    } else {
+	FileHandler *filePtr;
+	FileHandlerEvent *fileEvPtr;
+	int mask;
+	Tcl_Time myTime;
+	int waitForFiles;
+	Tcl_Time *myTimePtr;
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    if (timePtr != NULL) {
 	/*
-	 * TIP #233 (Virtualized Time). Is virtual time in effect? And do we
-	 * actually have something to scale? If yes to both then we call the
-	 * handler to do this scaling.
+	 * Set up the timeout structure. Note that if there are no events to
+	 * check for, we return with a negative result rather than blocking
+	 * forever.
 	 */
 
-	myTime.sec  = timePtr->sec;
-	myTime.usec = timePtr->usec;
-
-	if (myTime.sec != 0 || myTime.usec != 0) {
-	    (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
-	}
+	if (timePtr != NULL) {
+	    /*
+	     * TIP #233 (Virtualized Time). Is virtual time in effect? And do
+	     * we actually have something to scale? If yes to both then we call
+	     * the handler to do this scaling.
+	     */
 
-	myTimePtr = &myTime;
-    } else {
-	myTimePtr = NULL;
-    }
+	    myTime.sec  = timePtr->sec;
+	    myTime.usec = timePtr->usec;
 
-    /*
-     * Start notifier thread if necessary.
-     */
+	    if (myTime.sec != 0 || myTime.usec != 0) {
+		(*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
+	    }
 
-    LOCK_NOTIFIER_INIT;
-    if (!notifierCount) {
-        Tcl_Panic("Tcl_WaitForEvent: notifier not initialized");
-    }
-    if (!notifierThread) {
-	int result;
-	pthread_attr_t attr;
-
-	pthread_attr_init(&attr);
-	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
-	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-	pthread_attr_setstacksize(&attr, 60 * 1024);
-	result = pthread_create(&notifierThread, &attr,
-		(void * (*)(void *))NotifierThreadProc, NULL);
-	pthread_attr_destroy(&attr);
-	if (result || !notifierThread) {
-	    Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread");
+	    myTimePtr = &myTime;
+	} else {
+	    myTimePtr = NULL;
 	}
-    }
-    UNLOCK_NOTIFIER_INIT;
 
-    /*
-     * Place this thread on the list of interested threads, signal the
-     * notifier thread, and wait for a response or a timeout.
-     */
-
-    LOCK_NOTIFIER;
-    if (!tsdPtr->runLoop) {
-        Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized");
-    }
-    waitForFiles = (tsdPtr->numFdBits > 0);
-    if (myTimePtr != NULL && myTimePtr->sec == 0 && myTimePtr->usec == 0) {
 	/*
-	 * Cannot emulate a polling select with a polling condition variable.
-	 * Instead, pretend to wait for files and tell the notifier thread
-	 * what we are doing. The notifier thread makes sure it goes through
-	 * select with its select mask in the same state as ours currently is.
-	 * We block until that happens.
+	 * Start notifier thread if necessary.
 	 */
 
-	waitForFiles = 1;
-	tsdPtr->pollState = POLL_WANT;
-	myTimePtr = NULL;
-    } else {
-	tsdPtr->pollState = 0;
-    }
+	LOCK_NOTIFIER_INIT;
+	if (!notifierCount) {
+	    Tcl_Panic("Tcl_WaitForEvent: notifier not initialized");
+	}
+	if (!notifierThread) {
+	    int result;
+	    pthread_attr_t attr;
+
+	    pthread_attr_init(&attr);
+	    pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+	    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+	    pthread_attr_setstacksize(&attr, 60 * 1024);
+	    result = pthread_create(&notifierThread, &attr,
+		    (void * (*)(void *))NotifierThreadProc, NULL);
+	    pthread_attr_destroy(&attr);
+	    if (result || !notifierThread) {
+		Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread");
+	    }
+	}
+	UNLOCK_NOTIFIER_INIT;
 
-    if (waitForFiles) {
 	/*
-	 * Add the ThreadSpecificData structure of this thread to the list of
-	 * ThreadSpecificData structures of all threads that are waiting on
-	 * file events.
+	 * Place this thread on the list of interested threads, signal the
+	 * notifier thread, and wait for a response or a timeout.
 	 */
 
-	tsdPtr->nextPtr = waitingListPtr;
-	if (waitingListPtr) {
-	    waitingListPtr->prevPtr = tsdPtr;
-	}
-	tsdPtr->prevPtr = 0;
-	waitingListPtr = tsdPtr;
-	tsdPtr->onList = 1;
-
-	write(triggerPipe, "", 1);
-    }
-
-    FD_ZERO(&(tsdPtr->readyMasks.readable));
-    FD_ZERO(&(tsdPtr->readyMasks.writable));
-    FD_ZERO(&(tsdPtr->readyMasks.exceptional));
-
-    if (!tsdPtr->eventReady) {
-	CFTimeInterval waitTime;
-	CFStringRef runLoopMode;
-
-	if (myTimePtr == NULL) {
-	    waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */
-	} else {
-	    waitTime = myTimePtr->sec + 1.0e-6 * myTimePtr->usec;
+	LOCK_NOTIFIER;
+	if (!tsdPtr->runLoop) {
+	    Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized");
 	}
-	/*
-	 * If the run loop is already running (e.g. if Tcl_WaitForEvent was
-	 * called recursively), re-run it in a custom run loop mode containing
-	 * only the source for the notifier thread, otherwise wakeups from other
-	 * sources added to the common run loop modes might get lost.
-	 */
-	if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) {
-	    CFRelease(runLoopMode);
-	    runLoopMode = tclEventsOnlyRunLoopMode;
+	waitForFiles = (tsdPtr->numFdBits > 0);
+	if (myTimePtr != NULL && myTimePtr->sec == 0 && myTimePtr->usec == 0) {
+	    /*
+	     * Cannot emulate a polling select with a polling condition
+	     * variable. Instead, pretend to wait for files and tell the
+	     * notifier thread what we are doing. The notifier thread makes
+	     * sure it goes through select with its select mask in the same
+	     * state as ours currently is. We block until that happens.
+	     */
+
+	    waitForFiles = 1;
+	    tsdPtr->pollState = POLL_WANT;
+	    myTimePtr = NULL;
 	} else {
-	    runLoopMode = kCFRunLoopDefaultMode;
+	    tsdPtr->pollState = 0;
 	}
-	UNLOCK_NOTIFIER;
-	CFRunLoopRunInMode(runLoopMode, waitTime, TRUE);
-	LOCK_NOTIFIER;
-    }
-    tsdPtr->eventReady = 0;
 
-    if (waitForFiles && tsdPtr->onList) {
-	/*
-	 * Remove the ThreadSpecificData structure of this thread from the
-	 * waiting list. Alert the notifier thread to recompute its select
-	 * masks - skipping this caused a hang when trying to close a pipe
-	 * which the notifier thread was still doing a select on.
-	 */
+	if (waitForFiles) {
+	    /*
+	     * Add the ThreadSpecificData structure of this thread to the list
+	     * of ThreadSpecificData structures of all threads that are waiting
+	     * on file events.
+	     */
 
-	if (tsdPtr->prevPtr) {
-	    tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
-	} else {
-	    waitingListPtr = tsdPtr->nextPtr;
-	}
-	if (tsdPtr->nextPtr) {
-	    tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+	    tsdPtr->nextPtr = waitingListPtr;
+	    if (waitingListPtr) {
+		waitingListPtr->prevPtr = tsdPtr;
+	    }
+	    tsdPtr->prevPtr = 0;
+	    waitingListPtr = tsdPtr;
+	    tsdPtr->onList = 1;
+
+	    write(triggerPipe, "", 1);
 	}
-	tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
-	tsdPtr->onList = 0;
-	write(triggerPipe, "", 1);
-    }
 
-    /*
-     * Queue all detected file events before returning.
-     */
+	FD_ZERO(&(tsdPtr->readyMasks.readable));
+	FD_ZERO(&(tsdPtr->readyMasks.writable));
+	FD_ZERO(&(tsdPtr->readyMasks.exceptional));
 
-    for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
-	    filePtr = filePtr->nextPtr) {
+	if (!tsdPtr->eventReady) {
+	    CFTimeInterval waitTime;
+	    CFStringRef runLoopMode;
 
-	mask = 0;
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
-	    mask |= TCL_READABLE;
-	}
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
-	    mask |= TCL_WRITABLE;
-	}
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
-	    mask |= TCL_EXCEPTION;
+	    if (myTimePtr == NULL) {
+		waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */
+	    } else {
+		waitTime = myTimePtr->sec + 1.0e-6 * myTimePtr->usec;
+	    }
+	    /*
+	     * If the run loop is already running (e.g. if Tcl_WaitForEvent was
+	     * called recursively), re-run it in a custom run loop mode
+	     * containing only the source for the notifier thread, otherwise
+	     * wakeups from other sources added to the common run loop modes
+	     * might get lost.
+	     */
+	    if ((runLoopMode = CFRunLoopCopyCurrentMode(tsdPtr->runLoop))) {
+		CFRelease(runLoopMode);
+		runLoopMode = tclEventsOnlyRunLoopMode;
+	    } else {
+		runLoopMode = kCFRunLoopDefaultMode;
+	    }
+	    UNLOCK_NOTIFIER;
+	    CFRunLoopRunInMode(runLoopMode, waitTime, TRUE);
+	    LOCK_NOTIFIER;
 	}
+	tsdPtr->eventReady = 0;
 
-	if (!mask) {
-	    continue;
+	if (waitForFiles && tsdPtr->onList) {
+	    /*
+	     * Remove the ThreadSpecificData structure of this thread from the
+	     * waiting list. Alert the notifier thread to recompute its select
+	     * masks - skipping this caused a hang when trying to close a pipe
+	     * which the notifier thread was still doing a select on.
+	     */
+
+	    if (tsdPtr->prevPtr) {
+		tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
+	    } else {
+		waitingListPtr = tsdPtr->nextPtr;
+	    }
+	    if (tsdPtr->nextPtr) {
+		tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+	    }
+	    tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
+	    tsdPtr->onList = 0;
+	    write(triggerPipe, "", 1);
 	}
 
 	/*
-	 * Don't bother to queue an event if the mask was previously non-zero
-	 * since an event must still be on the queue.
+	 * Queue all detected file events before returning.
 	 */
 
-	if (filePtr->readyMask == 0) {
-	    fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
-	    fileEvPtr->header.proc = FileHandlerEventProc;
-	    fileEvPtr->fd = filePtr->fd;
-	    Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+	for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
+		filePtr = filePtr->nextPtr) {
+
+	    mask = 0;
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
+		mask |= TCL_READABLE;
+	    }
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
+		mask |= TCL_WRITABLE;
+	    }
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
+		mask |= TCL_EXCEPTION;
+	    }
+
+	    if (!mask) {
+		continue;
+	    }
+
+	    /*
+	     * Don't bother to queue an event if the mask was previously
+	     * non-zero since an event must still be on the queue.
+	     */
+
+	    if (filePtr->readyMask == 0) {
+		fileEvPtr = (FileHandlerEvent *)
+			ckalloc(sizeof(FileHandlerEvent));
+		fileEvPtr->header.proc = FileHandlerEventProc;
+		fileEvPtr->fd = filePtr->fd;
+		Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+	    }
+	    filePtr->readyMask = mask;
 	}
-	filePtr->readyMask = mask;
+	UNLOCK_NOTIFIER;
+	return 0;
     }
-    UNLOCK_NOTIFIER;
-    return 0;
 }
 
 /*
Index: unix/tclUnixNotfy.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixNotfy.c,v
retrieving revision 1.34
diff -u -p -r1.34 tclUnixNotfy.c
--- unix/tclUnixNotfy.c	11 Mar 2008 22:23:50 -0000	1.34
+++ unix/tclUnixNotfy.c	16 Apr 2008 13:54:35 -0000
@@ -19,14 +19,6 @@
 #include <signal.h>
 
 /*
- * This code does deep stub magic to allow replacement of the notifier at
- * runtime.
- */
-
-extern TclStubs tclStubs;
-extern Tcl_NotifierProcs tclOriginalNotifier;
-
-/*
  * This structure is used to keep track of the notifier info for a registered
  * file.
  */
@@ -199,7 +191,7 @@ static int	FileHandlerEventProc(Tcl_Even
  *	Initializes the platform specific notifier state.
  *
  * Results:
- *	Returns a handle to the notifier state for this thread..
+ *	Returns a handle to the notifier state for this thread.
  *
  * Side effects:
  *	None.
@@ -210,35 +202,38 @@ static int	FileHandlerEventProc(Tcl_Even
 ClientData
 Tcl_InitNotifier(void)
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
+    if (tclNotifierHooks.initNotifierProc) {
+	return tclNotifierHooks.initNotifierProc();
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 #ifdef TCL_THREADS
-    tsdPtr->eventReady = 0;
+	tsdPtr->eventReady = 0;
 
-    /*
-     * Start the Notifier thread if necessary.
-     */
+	/*
+	 * Start the Notifier thread if necessary.
+	 */
 
-    Tcl_MutexLock(&notifierMutex);
-    if (notifierCount == 0) {
-	if (TclpThreadCreate(&notifierThread, NotifierThreadProc, NULL,
-		TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
-	    Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");
+	Tcl_MutexLock(&notifierMutex);
+	if (notifierCount == 0) {
+	    if (TclpThreadCreate(&notifierThread, NotifierThreadProc, NULL,
+		    TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
+		Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");
+	    }
 	}
-    }
-    notifierCount++;
+	notifierCount++;
 
-    /*
-     * Wait for the notifier pipe to be created.
-     */
+	/*
+	 * Wait for the notifier pipe to be created.
+	 */
 
-    while (triggerPipe < 0) {
-	Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);
-    }
+	while (triggerPipe < 0) {
+	    Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);
+	}
 
-    Tcl_MutexUnlock(&notifierMutex);
+	Tcl_MutexUnlock(&notifierMutex);
 #endif
-    return (ClientData) tsdPtr;
+	return (ClientData) tsdPtr;
+    }
 }
 
 /*
@@ -263,55 +258,60 @@ void
 Tcl_FinalizeNotifier(
     ClientData clientData)		/* Not used. */
 {
+    if (tclNotifierHooks.finalizeNotifierProc) {
+	tclNotifierHooks.finalizeNotifierProc(clientData);
+	return;
+    } else {
 #ifdef TCL_THREADS
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    Tcl_MutexLock(&notifierMutex);
-    notifierCount--;
+	Tcl_MutexLock(&notifierMutex);
+	notifierCount--;
 
-    /*
-     * If this is the last thread to use the notifier, close the notifier pipe
-     * and wait for the background thread to terminate.
-     */
+	/*
+	 * If this is the last thread to use the notifier, close the notifier
+	 * pipe and wait for the background thread to terminate.
+	 */
 
-    if (notifierCount == 0) {
-	int result;
+	if (notifierCount == 0) {
+	    int result;
 
-	if (triggerPipe < 0) {
-	    Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
-	}
+	    if (triggerPipe < 0) {
+		Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
+	    }
 
-	/*
-	 * Send "q" message to the notifier thread so that it will terminate.
-	 * The notifier will return from its call to select() and notice that
-	 * a "q" message has arrived, it will then close its side of the pipe
-	 * and terminate its thread. Note the we can not just close the pipe
-	 * and check for EOF in the notifier thread because if a background
-	 * child process was created with exec, select() would not register
-	 * the EOF on the pipe until the child processes had terminated. [Bug:
-	 * 4139] [Bug: 1222872]
-	 */
+	    /*
+	     * Send "q" message to the notifier thread so that it will
+	     * terminate. The notifier will return from its call to select()
+	     * and notice that a "q" message has arrived, it will then close
+	     * its side of the pipe and terminate its thread. Note the we can
+	     * not just close the pipe and check for EOF in the notifier thread
+	     * because if a background child process was created with exec,
+	     * select() would not register the EOF on the pipe until the child
+	     * processes had terminated. [Bug: 4139] [Bug: 1222872]
+	     */
 
-	write(triggerPipe, "q", 1);
-	close(triggerPipe);
-	while(triggerPipe >= 0) {
-	    Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);
-	}
+	    write(triggerPipe, "q", 1);
+	    close(triggerPipe);
+	    while(triggerPipe >= 0) {
+		Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);
+	    }
 
-	result = Tcl_JoinThread(notifierThread, NULL);
-	if (result) {
-	    Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread");
+	    result = Tcl_JoinThread(notifierThread, NULL);
+	    if (result) {
+		Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread");
+	    }
 	}
-    }
 
-    /*
-     * Clean up any synchronization objects in the thread local storage.
-     */
+	/*
+	 * Clean up any synchronization objects in the thread local storage.
+	 */
 
-    Tcl_ConditionFinalize(&(tsdPtr->waitCV));
+	Tcl_ConditionFinalize(&(tsdPtr->waitCV));
 
-    Tcl_MutexUnlock(&notifierMutex);
+	Tcl_MutexUnlock(&notifierMutex);
 #endif
+    }
 }
 
 /*
@@ -337,13 +337,18 @@ void
 Tcl_AlertNotifier(
     ClientData clientData)
 {
+    if (tclNotifierHooks.alertNotifierProc) {
+	tclNotifierHooks.alertNotifierProc(clientData);
+	return;
+    } else {
 #ifdef TCL_THREADS
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
-    Tcl_MutexLock(&notifierMutex);
-    tsdPtr->eventReady = 1;
-    Tcl_ConditionNotify(&tsdPtr->waitCV);
-    Tcl_MutexUnlock(&notifierMutex);
+	ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+	Tcl_MutexLock(&notifierMutex);
+	tsdPtr->eventReady = 1;
+	Tcl_ConditionNotify(&tsdPtr->waitCV);
+	Tcl_MutexUnlock(&notifierMutex);
 #endif
+    }
 }
 
 /*
@@ -368,14 +373,15 @@ void
 Tcl_SetTimer(
     Tcl_Time *timePtr)		/* Timeout value, may be NULL. */
 {
-    /*
-     * The interval timer doesn't do anything in this implementation, because
-     * the only event loop is via Tcl_DoOneEvent, which passes timeout values
-     * to Tcl_WaitForEvent.
-     */
-
-    if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
-	tclStubs.tcl_SetTimer(timePtr);
+    if (tclNotifierHooks.setTimerProc) {
+	tclNotifierHooks.setTimerProc(timePtr);
+	return;
+    } else {
+	/*
+	 * The interval timer doesn't do anything in this implementation,
+	 * because the only event loop is via Tcl_DoOneEvent, which passes
+	 * timeout values to Tcl_WaitForEvent.
+	 */
     }
 }
 
@@ -400,6 +406,12 @@ Tcl_ServiceModeHook(
     int mode)			/* Either TCL_SERVICE_ALL, or
 				 * TCL_SERVICE_NONE. */
 {
+    if (tclNotifierHooks.serviceModeHookProc) {
+	tclNotifierHooks.serviceModeHookProc(mode);
+	return;
+    } else {
+	/* Does nothing in this implementation. */
+    }
 }
 
 /*
@@ -429,53 +441,52 @@ Tcl_CreateFileHandler(
 				 * event. */
     ClientData clientData)	/* Arbitrary data to pass to proc. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    FileHandler *filePtr;
-
-    if (tclStubs.tcl_CreateFileHandler !=
-	    tclOriginalNotifier.createFileHandlerProc) {
-	tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);
+    if (tclNotifierHooks.createFileHandlerProc) {
+	tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
 	return;
-    }
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	FileHandler *filePtr;
 
-    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
-	    filePtr = filePtr->nextPtr) {
-	if (filePtr->fd == fd) {
-	    break;
+	for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
+		filePtr = filePtr->nextPtr) {
+	    if (filePtr->fd == fd) {
+		break;
+	    }
 	}
-    }
-    if (filePtr == NULL) {
-	filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
-	filePtr->fd = fd;
-	filePtr->readyMask = 0;
-	filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
-	tsdPtr->firstFileHandlerPtr = filePtr;
-    }
-    filePtr->proc = proc;
-    filePtr->clientData = clientData;
-    filePtr->mask = mask;
+	if (filePtr == NULL) {
+	    filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
+	    filePtr->fd = fd;
+	    filePtr->readyMask = 0;
+	    filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
+	    tsdPtr->firstFileHandlerPtr = filePtr;
+	}
+	filePtr->proc = proc;
+	filePtr->clientData = clientData;
+	filePtr->mask = mask;
 
-    /*
-     * Update the check masks for this file.
-     */
+	/*
+	 * Update the check masks for this file.
+	 */
 
-    if (mask & TCL_READABLE) {
-	FD_SET(fd, &(tsdPtr->checkMasks.readable));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.readable));
-    }
-    if (mask & TCL_WRITABLE) {
-	FD_SET(fd, &(tsdPtr->checkMasks.writable));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.writable));
-    }
-    if (mask & TCL_EXCEPTION) {
-	FD_SET(fd, &(tsdPtr->checkMasks.exceptional));
-    } else {
-	FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
-    }
-    if (tsdPtr->numFdBits <= fd) {
-	tsdPtr->numFdBits = fd+1;
+	if (mask & TCL_READABLE) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.readable));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+	}
+	if (mask & TCL_WRITABLE) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.writable));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+	}
+	if (mask & TCL_EXCEPTION) {
+	    FD_SET(fd, &(tsdPtr->checkMasks.exceptional));
+	} else {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+	}
+	if (tsdPtr->numFdBits <= fd) {
+	    tsdPtr->numFdBits = fd+1;
+	}
     }
 }
 
@@ -500,70 +511,69 @@ Tcl_DeleteFileHandler(
     int fd)			/* Stream id for which to remove callback
 				 * function. */
 {
-    FileHandler *filePtr, *prevPtr;
-    int i;
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-    if (tclStubs.tcl_DeleteFileHandler !=
-	    tclOriginalNotifier.deleteFileHandlerProc) {
-	tclStubs.tcl_DeleteFileHandler(fd);
+    if (tclNotifierHooks.deleteFileHandlerProc) {
+	tclNotifierHooks.deleteFileHandlerProc(fd);
 	return;
-    }
+    } else {
+	FileHandler *filePtr, *prevPtr;
+	int i;
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    /*
-     * Find the entry for the given file (and return if there isn't one).
-     */
+	/*
+	 * Find the entry for the given file (and return if there isn't one).
+	 */
 
-    for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
-	 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
-	if (filePtr == NULL) {
-	    return;
-	}
-	if (filePtr->fd == fd) {
-	    break;
+	for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
+	     prevPtr = filePtr, filePtr = filePtr->nextPtr) {
+	    if (filePtr == NULL) {
+		return;
+	    }
+	    if (filePtr->fd == fd) {
+		break;
+	    }
 	}
-    }
 
-    /*
-     * Update the check masks for this file.
-     */
+	/*
+	 * Update the check masks for this file.
+	 */
 
-    if (filePtr->mask & TCL_READABLE) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.readable));
-    }
-    if (filePtr->mask & TCL_WRITABLE) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.writable));
-    }
-    if (filePtr->mask & TCL_EXCEPTION) {
-	FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
-    }
+	if (filePtr->mask & TCL_READABLE) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+	}
+	if (filePtr->mask & TCL_WRITABLE) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+	}
+	if (filePtr->mask & TCL_EXCEPTION) {
+	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+	}
 
-    /*
-     * Find current max fd.
-     */
+	/*
+	 * Find current max fd.
+	 */
 
-    if (fd+1 == tsdPtr->numFdBits) {
-	tsdPtr->numFdBits = 0;
-	for (i = fd-1; i >= 0; i--) {
-	    if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
-		    || FD_ISSET(i, &(tsdPtr->checkMasks.writable))
-		    || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
-		tsdPtr->numFdBits = i+1;
-		break;
+	if (fd+1 == tsdPtr->numFdBits) {
+	    tsdPtr->numFdBits = 0;
+	    for (i = fd-1; i >= 0; i--) {
+		if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
+			|| FD_ISSET(i, &(tsdPtr->checkMasks.writable))
+			|| FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
+		    tsdPtr->numFdBits = i+1;
+		    break;
+		}
 	    }
 	}
-    }
 
-    /*
-     * Clean up information in the callback record.
-     */
+	/*
+	 * Clean up information in the callback record.
+	 */
 
-    if (prevPtr == NULL) {
-	tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
-    } else {
-	prevPtr->nextPtr = filePtr->nextPtr;
+	if (prevPtr == NULL) {
+	    tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+	} else {
+	    prevPtr->nextPtr = filePtr->nextPtr;
+	}
+	ckfree((char *) filePtr);
     }
-    ckfree((char *) filePtr);
 }
 
 /*
@@ -661,216 +671,219 @@ int
 Tcl_WaitForEvent(
     Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
 {
-    FileHandler *filePtr;
-    FileHandlerEvent *fileEvPtr;
-    int mask;
-    Tcl_Time myTime;
+    if (tclNotifierHooks.waitForEventProc) {
+	return tclNotifierHooks.waitForEventProc(timePtr);
+    } else {
+	FileHandler *filePtr;
+	FileHandlerEvent *fileEvPtr;
+	int mask;
+	Tcl_Time myTime;
 #ifdef TCL_THREADS
-    int waitForFiles;
-    Tcl_Time *myTimePtr;
+	int waitForFiles;
+	Tcl_Time *myTimePtr;
 #else
-    /*
-     * Impl. notes: timeout & timeoutPtr are used if, and only if threads are
-     * not enabled. They are the arguments for the regular select() used when
-     * the core is not thread-enabled.
-     */
+	/*
+	 * Impl. notes: timeout & timeoutPtr are used if, and only if threads
+	 * are not enabled. They are the arguments for the regular select()
+	 * used when the core is not thread-enabled.
+	 */
 
-    struct timeval timeout, *timeoutPtr;
-    int numFound;
+	struct timeval timeout, *timeoutPtr;
+	int numFound;
 #endif /* TCL_THREADS */
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
-    if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
-	return tclStubs.tcl_WaitForEvent(timePtr);
-    }
-
-    /*
-     * Set up the timeout structure. Note that if there are no events to check
-     * for, we return with a negative result rather than blocking forever.
-     */
-
-    if (timePtr != NULL) {
 	/*
-	 * TIP #233 (Virtualized Time). Is virtual time in effect? And do we
-	 * actually have something to scale? If yes to both then we call the
-	 * handler to do this scaling.
+	 * Set up the timeout structure. Note that if there are no events to
+	 * check for, we return with a negative result rather than blocking
+	 * forever.
 	 */
 
-	myTime.sec  = timePtr->sec;
-	myTime.usec = timePtr->usec;
+	if (timePtr != NULL) {
+	    /*
+	     * TIP #233 (Virtualized Time). Is virtual time in effect? And do
+	     * we actually have something to scale? If yes to both then we call
+	     * the handler to do this scaling.
+	     */
 
-	if (myTime.sec != 0 || myTime.usec != 0) {
-	    (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
-	}
+	    myTime.sec  = timePtr->sec;
+	    myTime.usec = timePtr->usec;
+
+	    if (myTime.sec != 0 || myTime.usec != 0) {
+		(*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
+	    }
 
 #ifdef TCL_THREADS
-	myTimePtr = &myTime;
+	    myTimePtr = &myTime;
 #else
-	timeout.tv_sec = myTime.sec;
-	timeout.tv_usec = myTime.usec;
-	timeoutPtr = &timeout;
+	    timeout.tv_sec = myTime.sec;
+	    timeout.tv_usec = myTime.usec;
+	    timeoutPtr = &timeout;
 #endif /* TCL_THREADS */
 
 #ifndef TCL_THREADS
-    } else if (tsdPtr->numFdBits == 0) {
-	/*
-	 * If there are no threads, no timeout, and no fds registered, then
-	 * there are no events possible and we must avoid deadlock. Note that
-	 * this is not entirely correct because there might be a signal that
-	 * could interrupt the select call, but we don't handle that case if
-	 * we aren't using threads.
-	 */
+	} else if (tsdPtr->numFdBits == 0) {
+	    /*
+	     * If there are no threads, no timeout, and no fds registered, then
+	     * there are no events possible and we must avoid deadlock. Note
+	     * that this is not entirely correct because there might be a
+	     * signal that could interrupt the select call, but we don't handle
+	     * that case if we aren't using threads.
+	     */
 
-	return -1;
+	    return -1;
 #endif /* !TCL_THREADS */
-    } else {
+	} else {
 #ifdef TCL_THREADS
-	myTimePtr = NULL;
+	    myTimePtr = NULL;
 #else
-	timeoutPtr = NULL;
+	    timeoutPtr = NULL;
 #endif /* TCL_THREADS */
-    }
+	}
 
 #ifdef TCL_THREADS
-    /*
-     * Place this thread on the list of interested threads, signal the
-     * notifier thread, and wait for a response or a timeout.
-     */
+	/*
+	 * Place this thread on the list of interested threads, signal the
+	 * notifier thread, and wait for a response or a timeout.
+	 */
 
-    Tcl_MutexLock(&notifierMutex);
+	Tcl_MutexLock(&notifierMutex);
 
-    waitForFiles = (tsdPtr->numFdBits > 0);
-    if (myTimePtr != NULL && myTimePtr->sec == 0 && (myTimePtr->usec == 0
+	waitForFiles = (tsdPtr->numFdBits > 0);
+	if (myTimePtr != NULL && myTimePtr->sec == 0 && (myTimePtr->usec == 0
 #if defined(__APPLE__) && defined(__LP64__)
+		/*
+		 * On 64-bit Darwin, pthread_cond_timedwait() appears to have a
+		 * bug that causes it to wait forever when passed an absolute
+		 * time which has already been exceeded by the system time; as
+		 * a workaround, when given a very brief timeout, just do a
+		 * poll. [Bug 1457797]
+		 */
+		|| myTimePtr->usec < 10
+#endif
+		)) {
 	    /*
-	     * On 64-bit Darwin, pthread_cond_timedwait() appears to have a bug
-	     * that causes it to wait forever when passed an absolute time which
-	     * has already been exceeded by the system time; as a workaround,
-	     * when given a very brief timeout, just do a poll. [Bug 1457797]
+	     * Cannot emulate a polling select with a polling condition
+	     * variable. Instead, pretend to wait for files and tell the
+	     * notifier thread what we are doing. The notifier thread makes
+	     * sure it goes through select with its select mask in the same
+	     * state as ours currently is. We block until that happens.
 	     */
-	    || myTimePtr->usec < 10
-#endif
-	    )) {
-	/*
-	 * Cannot emulate a polling select with a polling condition variable.
-	 * Instead, pretend to wait for files and tell the notifier thread
-	 * what we are doing. The notifier thread makes sure it goes through
-	 * select with its select mask in the same state as ours currently is.
-	 * We block until that happens.
-	 */
 
-	waitForFiles = 1;
-	tsdPtr->pollState = POLL_WANT;
-	myTimePtr = NULL;
-    } else {
-	tsdPtr->pollState = 0;
-    }
+	    waitForFiles = 1;
+	    tsdPtr->pollState = POLL_WANT;
+	    myTimePtr = NULL;
+	} else {
+	    tsdPtr->pollState = 0;
+	}
 
-    if (waitForFiles) {
-	/*
-	 * Add the ThreadSpecificData structure of this thread to the list of
-	 * ThreadSpecificData structures of all threads that are waiting on
-	 * file events.
-	 */
+	if (waitForFiles) {
+	    /*
+	     * Add the ThreadSpecificData structure of this thread to the list
+	     * of ThreadSpecificData structures of all threads that are waiting
+	     * on file events.
+	     */
 
-	tsdPtr->nextPtr = waitingListPtr;
-	if (waitingListPtr) {
-	    waitingListPtr->prevPtr = tsdPtr;
-	}
-	tsdPtr->prevPtr = 0;
-	waitingListPtr = tsdPtr;
-	tsdPtr->onList = 1;
+	    tsdPtr->nextPtr = waitingListPtr;
+	    if (waitingListPtr) {
+		waitingListPtr->prevPtr = tsdPtr;
+	    }
+	    tsdPtr->prevPtr = 0;
+	    waitingListPtr = tsdPtr;
+	    tsdPtr->onList = 1;
 
-	write(triggerPipe, "", 1);
-    }
+	    write(triggerPipe, "", 1);
+	}
 
-    FD_ZERO(&(tsdPtr->readyMasks.readable));
-    FD_ZERO(&(tsdPtr->readyMasks.writable));
-    FD_ZERO(&(tsdPtr->readyMasks.exceptional));
+	FD_ZERO(&(tsdPtr->readyMasks.readable));
+	FD_ZERO(&(tsdPtr->readyMasks.writable));
+	FD_ZERO(&(tsdPtr->readyMasks.exceptional));
 
-    if (!tsdPtr->eventReady) {
-	Tcl_ConditionWait(&tsdPtr->waitCV, &notifierMutex, myTimePtr);
-    }
-    tsdPtr->eventReady = 0;
+	if (!tsdPtr->eventReady) {
+	    Tcl_ConditionWait(&tsdPtr->waitCV, &notifierMutex, myTimePtr);
+	}
+	tsdPtr->eventReady = 0;
 
-    if (waitForFiles && tsdPtr->onList) {
-	/*
-	 * Remove the ThreadSpecificData structure of this thread from the
-	 * waiting list. Alert the notifier thread to recompute its select
-	 * masks - skipping this caused a hang when trying to close a pipe
-	 * which the notifier thread was still doing a select on.
-	 */
+	if (waitForFiles && tsdPtr->onList) {
+	    /*
+	     * Remove the ThreadSpecificData structure of this thread from the
+	     * waiting list. Alert the notifier thread to recompute its select
+	     * masks - skipping this caused a hang when trying to close a pipe
+	     * which the notifier thread was still doing a select on.
+	     */
 
-	if (tsdPtr->prevPtr) {
-	    tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
-	} else {
-	    waitingListPtr = tsdPtr->nextPtr;
-	}
-	if (tsdPtr->nextPtr) {
-	    tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+	    if (tsdPtr->prevPtr) {
+		tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
+	    } else {
+		waitingListPtr = tsdPtr->nextPtr;
+	    }
+	    if (tsdPtr->nextPtr) {
+		tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+	    }
+	    tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
+	    tsdPtr->onList = 0;
+	    write(triggerPipe, "", 1);
 	}
-	tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
-	tsdPtr->onList = 0;
-	write(triggerPipe, "", 1);
-    }
 
 #else
-    tsdPtr->readyMasks = tsdPtr->checkMasks;
-    numFound = select(tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable),
-	    &(tsdPtr->readyMasks.writable), &(tsdPtr->readyMasks.exceptional),
-	    timeoutPtr);
+	tsdPtr->readyMasks = tsdPtr->checkMasks;
+	numFound = select(tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable),
+		&(tsdPtr->readyMasks.writable),
+		&(tsdPtr->readyMasks.exceptional), timeoutPtr);
 
-    /*
-     * Some systems don't clear the masks after an error, so we have to do it
-     * here.
-     */
+	/*
+	 * Some systems don't clear the masks after an error, so we have to do
+	 * it here.
+	 */
 
-    if (numFound == -1) {
-	FD_ZERO(&(tsdPtr->readyMasks.readable));
-	FD_ZERO(&(tsdPtr->readyMasks.writable));
-	FD_ZERO(&(tsdPtr->readyMasks.exceptional));
-    }
+	if (numFound == -1) {
+	    FD_ZERO(&(tsdPtr->readyMasks.readable));
+	    FD_ZERO(&(tsdPtr->readyMasks.writable));
+	    FD_ZERO(&(tsdPtr->readyMasks.exceptional));
+	}
 #endif /* TCL_THREADS */
 
-    /*
-     * Queue all detected file events before returning.
-     */
+	/*
+	 * Queue all detected file events before returning.
+	 */
 
-    for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
-	    filePtr = filePtr->nextPtr) {
+	for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
+		filePtr = filePtr->nextPtr) {
 
-	mask = 0;
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
-	    mask |= TCL_READABLE;
-	}
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
-	    mask |= TCL_WRITABLE;
-	}
-	if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
-	    mask |= TCL_EXCEPTION;
-	}
+	    mask = 0;
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
+		mask |= TCL_READABLE;
+	    }
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
+		mask |= TCL_WRITABLE;
+	    }
+	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
+		mask |= TCL_EXCEPTION;
+	    }
 
-	if (!mask) {
-	    continue;
-	}
+	    if (!mask) {
+		continue;
+	    }
 
-	/*
-	 * Don't bother to queue an event if the mask was previously non-zero
-	 * since an event must still be on the queue.
-	 */
+	    /*
+	     * Don't bother to queue an event if the mask was previously
+	     * non-zero since an event must still be on the queue.
+	     */
 
-	if (filePtr->readyMask == 0) {
-	    fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
-	    fileEvPtr->header.proc = FileHandlerEventProc;
-	    fileEvPtr->fd = filePtr->fd;
-	    Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+	    if (filePtr->readyMask == 0) {
+		fileEvPtr = (FileHandlerEvent *)
+			ckalloc(sizeof(FileHandlerEvent));
+		fileEvPtr->header.proc = FileHandlerEventProc;
+		fileEvPtr->fd = filePtr->fd;
+		Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+	    }
+	    filePtr->readyMask = mask;
 	}
-	filePtr->readyMask = mask;
-    }
 #ifdef TCL_THREADS
-    Tcl_MutexUnlock(&notifierMutex);
+	Tcl_MutexUnlock(&notifierMutex);
 #endif /* TCL_THREADS */
-    return 0;
+	return 0;
+    }
 }
 
 #ifdef TCL_THREADS
Index: win/tclWinNotify.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinNotify.c,v
retrieving revision 1.21
diff -u -p -r1.21 tclWinNotify.c
--- win/tclWinNotify.c	4 Nov 2005 00:06:50 -0000	1.21
+++ win/tclWinNotify.c	16 Apr 2008 13:54:35 -0000
@@ -44,9 +44,6 @@ typedef struct ThreadSpecificData {
 
 static Tcl_ThreadDataKey dataKey;
 
-extern TclStubs tclStubs;
-extern Tcl_NotifierProcs tclOriginalNotifier;
-
 /*
  * The following static indicates the number of threads that have initialized
  * notifiers. It controls the lifetime of the TclNotifier window class.
@@ -83,45 +80,49 @@ static LRESULT CALLBACK		NotifierProc(HW
 ClientData
 Tcl_InitNotifier(void)
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    WNDCLASS class;
-
-    /*
-     * Register Notifier window class if this is the first thread to use this
-     * module.
-     */
+    if (tclNotifierHooks.initNotifierProc) {
+	return tclNotifierHooks.initNotifierProc();
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	WNDCLASS class;
 
-    Tcl_MutexLock(&notifierMutex);
-    if (notifierCount == 0) {
-	class.style = 0;
-	class.cbClsExtra = 0;
-	class.cbWndExtra = 0;
-	class.hInstance = TclWinGetTclInstance();
-	class.hbrBackground = NULL;
-	class.lpszMenuName = NULL;
-	class.lpszClassName = "TclNotifier";
-	class.lpfnWndProc = NotifierProc;
-	class.hIcon = NULL;
-	class.hCursor = NULL;
+	/*
+	 * Register Notifier window class if this is the first thread to use
+	 * this module.
+	 */
 
-	if (!RegisterClassA(&class)) {
-	    Tcl_Panic("Unable to register TclNotifier window class");
+	Tcl_MutexLock(&notifierMutex);
+	if (notifierCount == 0) {
+	    class.style = 0;
+	    class.cbClsExtra = 0;
+	    class.cbWndExtra = 0;
+	    class.hInstance = TclWinGetTclInstance();
+	    class.hbrBackground = NULL;
+	    class.lpszMenuName = NULL;
+	    class.lpszClassName = "TclNotifier";
+	    class.lpfnWndProc = NotifierProc;
+	    class.hIcon = NULL;
+	    class.hCursor = NULL;
+
+	    if (!RegisterClassA(&class)) {
+		Tcl_Panic("Unable to register TclNotifier window class");
+	    }
 	}
-    }
-    notifierCount++;
-    Tcl_MutexUnlock(&notifierMutex);
+	notifierCount++;
+	Tcl_MutexUnlock(&notifierMutex);
 
-    tsdPtr->pending = 0;
-    tsdPtr->timerActive = 0;
+	tsdPtr->pending = 0;
+	tsdPtr->timerActive = 0;
 
-    InitializeCriticalSection(&tsdPtr->crit);
+	InitializeCriticalSection(&tsdPtr->crit);
 
-    tsdPtr->hwnd = NULL;
-    tsdPtr->thread = GetCurrentThreadId();
-    tsdPtr->event = CreateEvent(NULL, TRUE /* manual */,
-	    FALSE /* !signaled */, NULL);
+	tsdPtr->hwnd = NULL;
+	tsdPtr->thread = GetCurrentThreadId();
+	tsdPtr->event = CreateEvent(NULL, TRUE /* manual */,
+		FALSE /* !signaled */, NULL);
 
-    return (ClientData) tsdPtr;
+	return (ClientData) tsdPtr;
+    }
 }
 
 /*
@@ -145,46 +146,51 @@ void
 Tcl_FinalizeNotifier(
     ClientData clientData)	/* Pointer to notifier data. */
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+    if (tclNotifierHooks.finalizeNotifierProc) {
+	tclNotifierHooks.finalizeNotifierProc(clientData);
+	return;
+    } else {
+	ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
 
-    /*
-     * Only finalize the notifier if a notifier was installed in the current
-     * thread; there is a route in which this is not guaranteed to be true
-     * (when tclWin32Dll.c:DllMain() is called with the flag
-     * DLL_PROCESS_DETACH by the OS, which could be doing so from a thread
-     * that's never previously been involved with Tcl, e.g. the task manager)
-     * so this check is important.
-     *
-     * Fixes Bug #217982 reported by Hugh Vu and Gene Leache.
-     */
+	/*
+	 * Only finalize the notifier if a notifier was installed in the
+	 * current thread; there is a route in which this is not guaranteed to
+	 * be true (when tclWin32Dll.c:DllMain() is called with the flag
+	 * DLL_PROCESS_DETACH by the OS, which could be doing so from a thread
+	 * that's never previously been involved with Tcl, e.g. the task
+	 * manager) so this check is important.
+	 *
+	 * Fixes Bug #217982 reported by Hugh Vu and Gene Leache.
+	 */
 
-    if (tsdPtr == NULL) {
-	return;
-    }
+	if (tsdPtr == NULL) {
+	    return;
+	}
 
-    DeleteCriticalSection(&tsdPtr->crit);
-    CloseHandle(tsdPtr->event);
+	DeleteCriticalSection(&tsdPtr->crit);
+	CloseHandle(tsdPtr->event);
 
-    /*
-     * Clean up the timer and messaging window for this thread.
-     */
+	/*
+	 * Clean up the timer and messaging window for this thread.
+	 */
 
-    if (tsdPtr->hwnd) {
-	KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
-	DestroyWindow(tsdPtr->hwnd);
-    }
+	if (tsdPtr->hwnd) {
+	    KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
+	    DestroyWindow(tsdPtr->hwnd);
+	}
 
-    /*
-     * If this is the last thread to use the notifier, unregister the notifier
-     * window class.
-     */
+	/*
+	 * If this is the last thread to use the notifier, unregister the
+	 * notifier window class.
+	 */
 
-    Tcl_MutexLock(&notifierMutex);
-    notifierCount--;
-    if (notifierCount == 0) {
-	UnregisterClassA("TclNotifier", TclWinGetTclInstance());
+	Tcl_MutexLock(&notifierMutex);
+	notifierCount--;
+	if (notifierCount == 0) {
+	    UnregisterClassA("TclNotifier", TclWinGetTclInstance());
+	}
+	Tcl_MutexUnlock(&notifierMutex);
     }
-    Tcl_MutexUnlock(&notifierMutex);
 }
 
 /*
@@ -213,27 +219,32 @@ void
 Tcl_AlertNotifier(
     ClientData clientData)	/* Pointer to thread data. */
 {
-    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
-
-    /*
-     * Note that we do not need to lock around access to the hwnd because the
-     * race condition has no effect since any race condition implies that the
-     * notifier thread is already awake.
-     */
+    if (tclNotifierHooks.alertNotifierProc) {
+	tclNotifierHooks.alertNotifierProc(clientData);
+	return;
+    } else {
+	ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
 
-    if (tsdPtr->hwnd) {
 	/*
-	 * We do need to lock around access to the pending flag.
+	 * Note that we do not need to lock around access to the hwnd because
+	 * the race condition has no effect since any race condition implies
+	 * that the notifier thread is already awake.
 	 */
 
-	EnterCriticalSection(&tsdPtr->crit);
-	if (!tsdPtr->pending) {
-	    PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+	if (tsdPtr->hwnd) {
+	    /*
+	     * We do need to lock around access to the pending flag.
+	     */
+
+	    EnterCriticalSection(&tsdPtr->crit);
+	    if (!tsdPtr->pending) {
+		PostMessage(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
+	    }
+	    tsdPtr->pending = 1;
+	    LeaveCriticalSection(&tsdPtr->crit);
+	} else {
+	    SetEvent(tsdPtr->event);
 	}
-	tsdPtr->pending = 1;
-	LeaveCriticalSection(&tsdPtr->crit);
-    } else {
-	SetEvent(tsdPtr->event);
     }
 }
 
@@ -259,50 +270,45 @@ void
 Tcl_SetTimer(
     Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    UINT timeout;
-
-    /*
-     * Allow the notifier to be hooked. This may not make sense on Windows,
-     * but mirrors the UNIX hook.
-     */
-
-    if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
-	tclStubs.tcl_SetTimer(timePtr);
-	return;
-    }
-
-    /*
-     * We only need to set up an interval timer if we're being called from an
-     * external event loop. If we don't have a window handle then we just
-     * return immediately and let Tcl_WaitForEvent handle timeouts.
-     */
-
-    if (!tsdPtr->hwnd) {
+    if (tclNotifierHooks.setTimerProc) {
+	tclNotifierHooks.setTimerProc(timePtr);
 	return;
-    }
-
-    if (!timePtr) {
-	timeout = 0;
     } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	UINT timeout;
+
 	/*
-	 * Make sure we pass a non-zero value into the timeout argument.
-	 * Windows seems to get confused by zero length timers.
+	 * We only need to set up an interval timer if we're being called from
+	 * an external event loop. If we don't have a window handle then we
+	 * just return immediately and let Tcl_WaitForEvent handle timeouts.
 	 */
 
-	timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
-	if (timeout == 0) {
-	    timeout = 1;
+	if (!tsdPtr->hwnd) {
+	    return;
+	}
+
+	if (!timePtr) {
+	    timeout = 0;
+	} else {
+	    /*
+	     * Make sure we pass a non-zero value into the timeout argument.
+	     * Windows seems to get confused by zero length timers.
+	     */
+
+	    timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
+	    if (timeout == 0) {
+		timeout = 1;
+	    }
+	}
+	tsdPtr->timeout = timeout;
+	if (timeout != 0) {
+	    tsdPtr->timerActive = 1;
+	    SetTimer(tsdPtr->hwnd, INTERVAL_TIMER,
+		    (unsigned long) tsdPtr->timeout, NULL);
+	} else {
+	    tsdPtr->timerActive = 0;
+	    KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
 	}
-    }
-    tsdPtr->timeout = timeout;
-    if (timeout != 0) {
-	tsdPtr->timerActive = 1;
-	SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, (unsigned long) tsdPtr->timeout,
-		NULL);
-    } else {
-	tsdPtr->timerActive = 0;
-	KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
     }
 }
 
@@ -328,29 +334,36 @@ Tcl_ServiceModeHook(
     int mode)			/* Either TCL_SERVICE_ALL, or
 				 * TCL_SERVICE_NONE. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
-    /*
-     * If this is the first time that the notifier has been used from a modal
-     * loop, then create a communication window. Note that after this point,
-     * the application needs to service events in a timely fashion or Windows
-     * will hang waiting for the window to respond to synchronous system
-     * messages. At some point, we may want to consider destroying the window
-     * if we leave the modal loop, but for now we'll leave it around.
-     */
-
-    if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
-	tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier", WS_TILED,
-		0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL);
+    if (tclNotifierHooks.serviceModeHookProc) {
+	tclNotifierHooks.serviceModeHookProc(mode);
+	return;
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
 
 	/*
-	 * Send an initial message to the window to ensure that we wake up the
-	 * notifier once we get into the modal loop. This will force the
-	 * notifier to recompute the timeout value and schedule a timer if one
-	 * is needed.
+	 * If this is the first time that the notifier has been used from a
+	 * modal loop, then create a communication window. Note that after this
+	 * point, the application needs to service events in a timely fashion
+	 * or Windows will hang waiting for the window to respond to
+	 * synchronous system messages. At some point, we may want to consider
+	 * destroying the window if we leave the modal loop, but for now we'll
+	 * leave it around.
 	 */
 
-	Tcl_AlertNotifier((ClientData)tsdPtr);
+	if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
+	    tsdPtr->hwnd = CreateWindowA("TclNotifier", "TclNotifier",
+		    WS_TILED, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(),
+		    NULL);
+
+	    /*
+	     * Send an initial message to the window to ensure that we wake up
+	     * the notifier once we get into the modal loop. This will force
+	     * the notifier to recompute the timeout value and schedule a timer
+	     * if one is needed.
+	     */
+
+	    Tcl_AlertNotifier((ClientData)tsdPtr);
+	}
     }
 }
 
@@ -420,105 +433,100 @@ int
 Tcl_WaitForEvent(
     Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
 {
-    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-    MSG msg;
-    DWORD timeout, result;
-    int status;
-
-    /*
-     * Allow the notifier to be hooked. This may not make sense on windows,
-     * but mirrors the UNIX hook.
-     */
-
-    if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
-	return tclStubs.tcl_WaitForEvent(timePtr);
-    }
-
-    /*
-     * Compute the timeout in milliseconds.
-     */
+    if (tclNotifierHooks.waitForEventProc) {
+	return tclNotifierHooks.waitForEventProc(timePtr);
+    } else {
+	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+	MSG msg;
+	DWORD timeout, result;
+	int status;
 
-    if (timePtr) {
 	/*
-	 * TIP #233 (Virtualized Time). Convert virtual domain delay to
-	 * real-time.
+	 * Compute the timeout in milliseconds.
 	 */
 
-	Tcl_Time myTime;
+	if (timePtr) {
+	    /*
+	     * TIP #233 (Virtualized Time). Convert virtual domain delay to
+	     * real-time.
+	     */
 
-	myTime.sec  = timePtr->sec;
-	myTime.usec = timePtr->usec;
+	    Tcl_Time myTime;
 
-	if (myTime.sec != 0 || myTime.usec != 0) {
-	    (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
-	}
+	    myTime.sec  = timePtr->sec;
+	    myTime.usec = timePtr->usec;
 
-	timeout = myTime.sec * 1000 + myTime.usec / 1000;
-    } else {
-	timeout = INFINITE;
-    }
+	    if (myTime.sec != 0 || myTime.usec != 0) {
+		(*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
+	    }
 
-    /*
-     * Check to see if there are any messages in the queue before waiting
-     * because MsgWaitForMultipleObjects will not wake up if there are events
-     * currently sitting in the queue.
-     */
+	    timeout = myTime.sec * 1000 + myTime.usec / 1000;
+	} else {
+	    timeout = INFINITE;
+	}
 
-    if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
 	/*
-	 * Wait for something to happen (a signal from another thread, a
-	 * message, or timeout) or loop servicing asynchronous procedure calls
-	 * queued to this thread.
+	 * Check to see if there are any messages in the queue before waiting
+	 * because MsgWaitForMultipleObjects will not wake up if there are
+	 * events currently sitting in the queue.
 	 */
 
-    again:
-	result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
-		QS_ALLINPUT, MWMO_ALERTABLE);
-	if (result == WAIT_IO_COMPLETION) {
-	    goto again;
-	} else if (result == WAIT_FAILED) {
-	    status = -1;
-	    goto end;
-	}
-    }
+	if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+	    /*
+	     * Wait for something to happen (a signal from another thread, a
+	     * message, or timeout) or loop servicing asynchronous procedure
+	     * calls queued to this thread.
+	     */
 
-    /*
-     * Check to see if there are any messages to process.
-     */
+	again:
+	    result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
+		    QS_ALLINPUT, MWMO_ALERTABLE);
+	    if (result == WAIT_IO_COMPLETION) {
+		goto again;
+	    } else if (result == WAIT_FAILED) {
+		status = -1;
+		goto end;
+	    }
+	}
 
-    if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
 	/*
-	 * Retrieve and dispatch the first message.
+	 * Check to see if there are any messages to process.
 	 */
 
-	result = GetMessage(&msg, NULL, 0, 0);
-	if (result == 0) {
-	    /*
-	     * We received a request to exit this thread (WM_QUIT), so
-	     * propagate the quit message and start unwinding.
-	     */
-
-	    PostQuitMessage((int) msg.wParam);
-	    status = -1;
-	} else if (result == -1) {
+	if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
 	    /*
-	     * We got an error from the system. I have no idea why this would
-	     * happen, so we'll just unwind.
+	     * Retrieve and dispatch the first message.
 	     */
 
-	    status = -1;
+	    result = GetMessage(&msg, NULL, 0, 0);
+	    if (result == 0) {
+		/*
+		 * We received a request to exit this thread (WM_QUIT), so
+		 * propagate the quit message and start unwinding.
+		 */
+
+		PostQuitMessage((int) msg.wParam);
+		status = -1;
+	    } else if (result == -1) {
+		/*
+		 * We got an error from the system. I have no idea why this
+		 * would happen, so we'll just unwind.
+		 */
+
+		status = -1;
+	    } else {
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+		status = 1;
+	    }
 	} else {
-	    TranslateMessage(&msg);
-	    DispatchMessage(&msg);
-	    status = 1;
+	    status = 0;
 	}
-    } else {
-	status = 0;
-    }
 
-  end:
-    ResetEvent(tsdPtr->event);
-    return status;
+      end:
+	ResetEvent(tsdPtr->event);
+	return status;
+    }
 }
 
 /*