diff options
Diffstat (limited to 'generic/tclNotify.c')
| -rw-r--r-- | generic/tclNotify.c | 421 |
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 |
