summaryrefslogtreecommitdiffstats
path: root/generic/tclNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclNotify.c')
-rw-r--r--generic/tclNotify.c421
1 files changed, 68 insertions, 353 deletions
diff --git a/generic/tclNotify.c b/generic/tclNotify.c
index c724157..b45539a 100644
--- a/generic/tclNotify.c
+++ b/generic/tclNotify.c
@@ -7,10 +7,9 @@
* of the notifier is defined in the tcl*Notify.c files in each platform
* directory.
*
- * Copyright © 1995-1997 Sun Microsystems, Inc.
- * Copyright © 1998 Scriptics Corporation.
- * Copyright © 2003 Kevin B. Kenny. All rights reserved.
- * Copyright © 2021 Donal K. Fellows
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1998 by Scriptics Corporation.
+ * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -18,14 +17,7 @@
#include "tclInt.h"
-/*
- * Notifier hooks that are checked in the public wrappers for the default
- * notifier functions (for overriding via Tcl_SetNotifier).
- */
-
-static Tcl_NotifierProcs tclNotifierHooks = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+extern TclStubs tclStubs;
/*
* For each event source (created with Tcl_CreateEventSource) there is a
@@ -95,8 +87,8 @@ TCL_DECLARE_MUTEX(listLock)
* Declarations for routines used only in this file.
*/
-static int QueueEvent(ThreadSpecificData *tsdPtr,
- Tcl_Event *evPtr, int position);
+static void QueueEvent(ThreadSpecificData *tsdPtr,
+ Tcl_Event* evPtr, Tcl_QueuePosition position);
/*
*----------------------------------------------------------------------
@@ -134,7 +126,7 @@ TclInitNotifier(void)
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->threadId = threadId;
- tsdPtr->clientData = Tcl_InitNotifier();
+ tsdPtr->clientData = tclStubs.tcl_InitNotifier();
tsdPtr->initialized = 1;
tsdPtr->nextPtr = firstNotifierPtr;
firstNotifierPtr = tsdPtr;
@@ -175,14 +167,14 @@ TclFinalizeNotifier(void)
Tcl_Event *evPtr, *hold;
if (!tsdPtr->initialized) {
- return; /* Notifier not initialized for the current thread */
+ return; /* Notifier not initialized for the current thread */
}
Tcl_MutexLock(&(tsdPtr->queueMutex));
for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL; ) {
hold = evPtr;
evPtr = evPtr->nextPtr;
- ckfree(hold);
+ ckfree((char *) hold);
}
tsdPtr->firstEventPtr = NULL;
tsdPtr->lastEventPtr = NULL;
@@ -190,7 +182,9 @@ TclFinalizeNotifier(void)
Tcl_MutexLock(&listLock);
- Tcl_FinalizeNotifier(tsdPtr->clientData);
+ if (tclStubs.tcl_FinalizeNotifier) {
+ tclStubs.tcl_FinalizeNotifier(tsdPtr->clientData);
+ }
Tcl_MutexFinalize(&(tsdPtr->queueMutex));
for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {
@@ -217,49 +211,27 @@ TclFinalizeNotifier(void)
* None.
*
* Side effects:
- * Set the tclNotifierHooks global, which is checked in the default
- * notifier functions.
+ * 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.)
*
*----------------------------------------------------------------------
*/
void
Tcl_SetNotifier(
- const Tcl_NotifierProcs *notifierProcPtr)
+ Tcl_NotifierProcs *notifierProcPtr)
{
- tclNotifierHooks = *notifierProcPtr;
-
- /*
- * Don't allow hooks to refer to the hook point functions; avoids infinite
- * loop.
- */
-
- if (tclNotifierHooks.setTimerProc == Tcl_SetTimer) {
- tclNotifierHooks.setTimerProc = NULL;
- }
- if (tclNotifierHooks.waitForEventProc == Tcl_WaitForEvent) {
- tclNotifierHooks.waitForEventProc = NULL;
- }
- if (tclNotifierHooks.initNotifierProc == Tcl_InitNotifier) {
- tclNotifierHooks.initNotifierProc = NULL;
- }
- if (tclNotifierHooks.finalizeNotifierProc == Tcl_FinalizeNotifier) {
- tclNotifierHooks.finalizeNotifierProc = NULL;
- }
- if (tclNotifierHooks.alertNotifierProc == Tcl_AlertNotifier) {
- tclNotifierHooks.alertNotifierProc = NULL;
- }
- if (tclNotifierHooks.serviceModeHookProc == Tcl_ServiceModeHook) {
- tclNotifierHooks.serviceModeHookProc = NULL;
- }
-#ifndef _WIN32
- if (tclNotifierHooks.createFileHandlerProc == Tcl_CreateFileHandler) {
- tclNotifierHooks.createFileHandlerProc = NULL;
- }
- if (tclNotifierHooks.deleteFileHandlerProc == Tcl_DeleteFileHandler) {
- tclNotifierHooks.deleteFileHandlerProc = NULL;
- }
-#endif /* !_WIN32 */
+#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;
}
/*
@@ -309,7 +281,7 @@ Tcl_CreateEventSource(
* checkProc. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- EventSource *sourcePtr = (EventSource *)ckalloc(sizeof(EventSource));
+ EventSource *sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
sourcePtr->setupProc = setupProc;
sourcePtr->checkProc = checkProc;
@@ -330,7 +302,7 @@ Tcl_CreateEventSource(
* None.
*
* Side effects:
- * The given event source is canceled, so its function will never again
+ * The given event source is cancelled, so its function will never again
* be called. If no such source exists, nothing happens.
*
*----------------------------------------------------------------------
@@ -363,7 +335,7 @@ Tcl_DeleteEventSource(
} else {
prevPtr->nextPtr = sourcePtr->nextPtr;
}
- ckfree(sourcePtr);
+ ckfree((char *) sourcePtr);
return;
}
}
@@ -386,16 +358,15 @@ Tcl_DeleteEventSource(
void
Tcl_QueueEvent(
- Tcl_Event *evPtr, /* Event to add to queue. The storage space
+ Tcl_Event* evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (ckalloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
- int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
- * possibly combined with TCL_QUEUE_ALERT_IF_EMPTY. */
+ Tcl_QueuePosition position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
+ * TCL_QUEUE_MARK. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
QueueEvent(tsdPtr, evPtr, position);
}
@@ -423,8 +394,8 @@ Tcl_ThreadQueueEvent(
* malloc (ckalloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
- int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
- * possibly combined with TCL_QUEUE_ALERT_IF_EMPTY. */
+ Tcl_QueuePosition position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
+ * TCL_QUEUE_MARK. */
{
ThreadSpecificData *tsdPtr;
@@ -443,11 +414,9 @@ Tcl_ThreadQueueEvent(
*/
if (tsdPtr) {
- if (QueueEvent(tsdPtr, evPtr, position)) {
- Tcl_AlertNotifier(tsdPtr->clientData);
- }
+ QueueEvent(tsdPtr, evPtr, position);
} else {
- ckfree(evPtr);
+ ckfree((char *) evPtr);
}
Tcl_MutexUnlock(&listLock);
}
@@ -465,8 +434,7 @@ Tcl_ThreadQueueEvent(
* last-in-first-out order.
*
* Results:
- * For TCL_QUEUE_ALERT_IF_EMPTY the empty state before the
- * operation is returned.
+ * None.
*
* Side effects:
* None.
@@ -474,7 +442,7 @@ Tcl_ThreadQueueEvent(
*----------------------------------------------------------------------
*/
-static int
+static void
QueueEvent(
ThreadSpecificData *tsdPtr, /* Handle to thread local data that indicates
* which event queue to use. */
@@ -483,14 +451,11 @@ QueueEvent(
* malloc (ckalloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
- int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
- * possibly combined with TCL_QUEUE_ALERT_IF_EMPTY */
+ Tcl_QueuePosition position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
+ * TCL_QUEUE_MARK. */
{
Tcl_MutexLock(&(tsdPtr->queueMutex));
- if (tsdPtr->firstEventPtr != NULL) {
- position &= ~TCL_QUEUE_ALERT_IF_EMPTY;
- }
- if ((position & 3) == TCL_QUEUE_TAIL) {
+ if (position == TCL_QUEUE_TAIL) {
/*
* Append the event on the end of the queue.
*/
@@ -502,7 +467,7 @@ QueueEvent(
tsdPtr->lastEventPtr->nextPtr = evPtr;
}
tsdPtr->lastEventPtr = evPtr;
- } else if ((position & 3) == TCL_QUEUE_HEAD) {
+ } else if (position == TCL_QUEUE_HEAD) {
/*
* Push the event on the head of the queue.
*/
@@ -512,7 +477,7 @@ QueueEvent(
tsdPtr->lastEventPtr = evPtr;
}
tsdPtr->firstEventPtr = evPtr;
- } else if ((position & 3) == TCL_QUEUE_MARK) {
+ } else if (position == TCL_QUEUE_MARK) {
/*
* Insert the event after the current marker event and advance the
* marker to the new event.
@@ -531,7 +496,6 @@ QueueEvent(
}
}
Tcl_MutexUnlock(&(tsdPtr->queueMutex));
- return position & TCL_QUEUE_ALERT_IF_EMPTY;
}
/*
@@ -556,13 +520,14 @@ QueueEvent(
void
Tcl_DeleteEvents(
Tcl_EventDeleteProc *proc, /* The function to call. */
- ClientData clientData) /* The type-specific data. */
+ ClientData clientData) /* The type-specific data. */
{
Tcl_Event *evPtr; /* Pointer to the event being examined */
Tcl_Event *prevPtr; /* Pointer to evPtr's predecessor, or NULL if
* evPtr designates the first event in the
* queue for the thread. */
- Tcl_Event *hold;
+ Tcl_Event* hold;
+
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_MutexLock(&(tsdPtr->queueMutex));
@@ -575,7 +540,7 @@ Tcl_DeleteEvents(
prevPtr = NULL;
evPtr = tsdPtr->firstEventPtr;
while (evPtr != NULL) {
- if (proc(evPtr, clientData) == 1) {
+ if ((*proc)(evPtr, clientData) == 1) {
/*
* This event should be deleted. Unlink it.
*/
@@ -603,7 +568,7 @@ Tcl_DeleteEvents(
hold = evPtr;
evPtr = evPtr->nextPtr;
- ckfree(hold);
+ ckfree((char *) hold);
} else {
/*
* Event is to be retained.
@@ -707,7 +672,7 @@ Tcl_ServiceEvent(
*/
Tcl_MutexUnlock(&(tsdPtr->queueMutex));
- result = proc(evPtr, flags);
+ result = (*proc)(evPtr, flags);
Tcl_MutexLock(&(tsdPtr->queueMutex));
if (result) {
@@ -742,7 +707,7 @@ Tcl_ServiceEvent(
}
}
if (evPtr) {
- ckfree(evPtr);
+ ckfree((char *) evPtr);
}
Tcl_MutexUnlock(&(tsdPtr->queueMutex));
return 1;
@@ -809,7 +774,9 @@ Tcl_SetServiceMode(
oldMode = tsdPtr->serviceMode;
tsdPtr->serviceMode = mode;
- Tcl_ServiceModeHook(mode);
+ if (tclStubs.tcl_ServiceModeHook) {
+ tclStubs.tcl_ServiceModeHook(mode);
+ }
return oldMode;
}
@@ -834,7 +801,7 @@ Tcl_SetServiceMode(
void
Tcl_SetMaxBlockTime(
- const Tcl_Time *timePtr) /* Specifies a maximum elapsed time for the
+ Tcl_Time *timePtr) /* Specifies a maximum elapsed time for the
* next blocking operation in the event
* tsdPtr-> */
{
@@ -967,7 +934,7 @@ Tcl_DoOneEvent(
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
- sourcePtr->setupProc(sourcePtr->clientData, flags);
+ (sourcePtr->setupProc)(sourcePtr->clientData, flags);
}
}
tsdPtr->inTraversal = 0;
@@ -996,7 +963,7 @@ Tcl_DoOneEvent(
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->checkProc) {
- sourcePtr->checkProc(sourcePtr->clientData, flags);
+ (sourcePtr->checkProc)(sourcePtr->clientData, flags);
}
}
@@ -1027,12 +994,12 @@ Tcl_DoOneEvent(
}
/*
- * If Tcl_WaitForEvent has returned 1, indicating that one system event
- * has been dispatched (and thus that some Tcl code might have been
- * indirectly executed), we break out of the loop in order, e.g. to
- * give vwait a chance to determine whether that system event had the
- * side effect of changing the variable (so the vwait can return and
- * unwind properly).
+ * If Tcl_WaitForEvent has returned 1, indicating that one system
+ * event has been dispatched (and thus that some Tcl code might have
+ * been indirectly executed), we break out of the loop. We do this to
+ * give VwaitCmd for instance a chance to check if that system event
+ * had the side effect of changing the variable (so the vwait can
+ * return and unwind properly).
*
* NB: We will process idle events if any first, because otherwise we
* might never do the idle events if the notifier always gets
@@ -1080,7 +1047,7 @@ Tcl_ServiceAll(void)
}
/*
- * We need to turn off event servicing like we do in Tcl_DoOneEvent, to
+ * We need to turn off event servicing like we to in Tcl_DoOneEvent, to
* avoid recursive calls.
*/
@@ -1106,13 +1073,13 @@ Tcl_ServiceAll(void)
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
- sourcePtr->setupProc(sourcePtr->clientData, TCL_ALL_EVENTS);
+ (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
}
}
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->checkProc) {
- sourcePtr->checkProc(sourcePtr->clientData, TCL_ALL_EVENTS);
+ (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
}
}
@@ -1165,7 +1132,9 @@ Tcl_ThreadAlert(
Tcl_MutexLock(&listLock);
for (tsdPtr = firstNotifierPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
if (tsdPtr->threadId == threadId) {
- Tcl_AlertNotifier(tsdPtr->clientData);
+ if (tclStubs.tcl_AlertNotifier) {
+ tclStubs.tcl_AlertNotifier(tsdPtr->clientData);
+ }
break;
}
}
@@ -1173,260 +1142,6 @@ Tcl_ThreadAlert(
}
/*
- *----------------------------------------------------------------------
- *
- * Tcl_InitNotifier --
- *
- * Initializes the platform specific notifier state. Forwards to the
- * platform implementation when the hook is not enabled.
- *
- * Results:
- * Returns a handle to the notifier state for this thread..
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-ClientData
-Tcl_InitNotifier(void)
-{
- if (tclNotifierHooks.initNotifierProc) {
- return tclNotifierHooks.initNotifierProc();
- } else {
- return TclpInitNotifier();
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_FinalizeNotifier --
- *
- * This function is called to cleanup the notifier state before a thread
- * is terminated. Forwards to the platform implementation when the hook
- * is not enabled.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If no finalizeNotifierProc notifier hook exists, TclpFinalizeNotifier
- * is called.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_FinalizeNotifier(
- ClientData clientData)
-{
- if (tclNotifierHooks.finalizeNotifierProc) {
- tclNotifierHooks.finalizeNotifierProc(clientData);
- } else {
- TclpFinalizeNotifier(clientData);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_AlertNotifier --
- *
- * Wake up the specified notifier from any thread. This routine is called
- * by the platform independent notifier code whenever the Tcl_ThreadAlert
- * routine is called. This routine is guaranteed not to be called by Tcl
- * on a given notifier after Tcl_FinalizeNotifier is called for that
- * notifier. This routine is typically called from a thread other than
- * the notifier's thread. Forwards to the platform implementation when
- * the hook is not enabled.
- *
- * Results:
- * None.
- *
- * Side effects:
- * See the platform-specific implementations.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_AlertNotifier(
- ClientData clientData) /* Pointer to thread data. */
-{
- if (tclNotifierHooks.alertNotifierProc) {
- tclNotifierHooks.alertNotifierProc(clientData);
- } else {
- TclpAlertNotifier(clientData);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_ServiceModeHook --
- *
- * This function is invoked whenever the service mode changes. Forwards
- * to the platform implementation when the hook is not enabled.
- *
- * Results:
- * None.
- *
- * Side effects:
- * See the platform-specific implementations.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_ServiceModeHook(
- int mode) /* Either TCL_SERVICE_ALL, or
- * TCL_SERVICE_NONE. */
-{
- if (tclNotifierHooks.serviceModeHookProc) {
- tclNotifierHooks.serviceModeHookProc(mode);
- } else {
- TclpServiceModeHook(mode);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_SetTimer --
- *
- * This function sets the current notifier timer value. Forwards to the
- * platform implementation when the hook is not enabled.
- *
- * Results:
- * None.
- *
- * Side effects:
- * See the platform-specific implementations.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_SetTimer(
- const Tcl_Time *timePtr) /* Timeout value, may be NULL. */
-{
- if (tclNotifierHooks.setTimerProc) {
- tclNotifierHooks.setTimerProc(timePtr);
- } else {
- TclpSetTimer(timePtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_WaitForEvent --
- *
- * This function is called by Tcl_DoOneEvent to wait for new events on
- * the notifier's message queue. If the block time is 0, then
- * Tcl_WaitForEvent just polls without blocking. Forwards to the
- * platform implementation when the hook is not enabled.
- *
- * Results:
- * Returns -1 if the wait would block forever, 1 if an out-of-loop source
- * was processed (see platform-specific notes) and otherwise returns 0.
- *
- * Side effects:
- * Queues file events that are detected by the notifier.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_WaitForEvent(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
-{
- if (tclNotifierHooks.waitForEventProc) {
- return tclNotifierHooks.waitForEventProc(timePtr);
- } else {
- return TclpWaitForEvent(timePtr);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_CreateFileHandler --
- *
- * This function registers a file descriptor handler with the notifier.
- * Forwards to the platform implementation when the hook is not enabled.
- *
- * This function is not defined on Windows. The OS API there is too
- * different.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Creates a new file handler structure.
- *
- *----------------------------------------------------------------------
- */
-
-#ifndef _WIN32
-void
-Tcl_CreateFileHandler(
- int fd, /* Handle of stream to watch. */
- int mask, /* OR'ed combination of TCL_READABLE,
- * TCL_WRITABLE, and TCL_EXCEPTION: indicates
- * conditions under which proc should be
- * called. */
- Tcl_FileProc *proc, /* Function to call for each selected
- * event. */
- ClientData clientData) /* Arbitrary data to pass to proc. */
-{
- if (tclNotifierHooks.createFileHandlerProc) {
- tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
- } else {
- TclpCreateFileHandler(fd, mask, proc, clientData);
- }
-}
-#endif /* !_WIN32 */
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_DeleteFileHandler --
- *
- * Cancel a previously-arranged callback arrangement for a file
- * descriptor. Forwards to the platform implementation when the hook is
- * not enabled.
- *
- * This function is not defined on Windows. The OS API there is too
- * different.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If a callback was previously registered on the file descriptor, remove
- * it.
- *
- *----------------------------------------------------------------------
- */
-
-#ifndef _WIN32
-void
-Tcl_DeleteFileHandler(
- int fd) /* Stream id for which to remove callback
- * function. */
-{
- if (tclNotifierHooks.deleteFileHandlerProc) {
- tclNotifierHooks.deleteFileHandlerProc(fd);
- } else {
- TclpDeleteFileHandler(fd);
- }
-}
-#endif /* !_WIN32 */
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4