📄 tclnotify.c
字号:
* * This procedure is invoked by event sources to tell the notifier * how long it may block the next time it blocks. The timePtr * argument gives a maximum time; the actual time may be less if * some other event source requested a smaller time. * * Results: * None. * * Side effects: * May reduce the length of the next sleep in the tsdPtr-> * *---------------------------------------------------------------------- */voidTcl_SetMaxBlockTime(timePtr) Tcl_Time *timePtr; /* Specifies a maximum elapsed time for * the next blocking operation in the * event tsdPtr-> */{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!tsdPtr->blockTimeSet || (timePtr->sec < tsdPtr->blockTime.sec) || ((timePtr->sec == tsdPtr->blockTime.sec) && (timePtr->usec < tsdPtr->blockTime.usec))) { tsdPtr->blockTime = *timePtr; tsdPtr->blockTimeSet = 1; } /* * If we are called outside an event source traversal, set the * timeout immediately. */ if (!tsdPtr->inTraversal) { if (tsdPtr->blockTimeSet) { Tcl_SetTimer(&tsdPtr->blockTime); } else { Tcl_SetTimer(NULL); } }}/* *---------------------------------------------------------------------- * * Tcl_DoOneEvent -- * * Process a single event of some sort. If there's no work to * do, wait for an event to occur, then process it. * * Results: * The return value is 1 if the procedure actually found an event * to process. If no processing occurred, then 0 is returned (this * can happen if the TCL_DONT_WAIT flag is set or if there are no * event handlers to wait for in the set specified by flags). * * Side effects: * May delay execution of process while waiting for an event, * unless TCL_DONT_WAIT is set in the flags argument. Event * sources are invoked to check for and queue events. Event * handlers may produce arbitrary side effects. * *---------------------------------------------------------------------- */intTcl_DoOneEvent(flags) int flags; /* Miscellaneous flag values: may be any * combination of TCL_DONT_WAIT, * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS, * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or * others defined by event sources. */{ int result = 0, oldMode; EventSource *sourcePtr; Tcl_Time *timePtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * The first thing we do is to service any asynchronous event * handlers. */ if (Tcl_AsyncReady()) { (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); return 1; } /* * No event flags is equivalent to TCL_ALL_EVENTS. */ if ((flags & TCL_ALL_EVENTS) == 0) { flags |= TCL_ALL_EVENTS; } /* * Set the service mode to none so notifier event routines won't * try to service events recursively. */ oldMode = tsdPtr->serviceMode; tsdPtr->serviceMode = TCL_SERVICE_NONE; /* * The core of this procedure is an infinite loop, even though * we only service one event. The reason for this is that we * may be processing events that don't do anything inside of Tcl. */ while (1) { /* * If idle events are the only things to service, skip the * main part of the loop and go directly to handle idle * events (i.e. don't wait even if TCL_DONT_WAIT isn't set). */ if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) { flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT; goto idleEvents; } /* * Ask Tcl to service a queued event, if there are any. */ if (Tcl_ServiceEvent(flags)) { result = 1; break; } /* * If TCL_DONT_WAIT is set, be sure to poll rather than * blocking, otherwise reset the block time to infinity. */ if (flags & TCL_DONT_WAIT) { tsdPtr->blockTime.sec = 0; tsdPtr->blockTime.usec = 0; tsdPtr->blockTimeSet = 1; } else { tsdPtr->blockTimeSet = 0; } /* * Set up all the event sources for new events. This will * cause the block time to be updated if necessary. */ tsdPtr->inTraversal = 1; for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->setupProc) { (sourcePtr->setupProc)(sourcePtr->clientData, flags); } } tsdPtr->inTraversal = 0; if ((flags & TCL_DONT_WAIT) || tsdPtr->blockTimeSet) { timePtr = &tsdPtr->blockTime; } else { timePtr = NULL; } /* * Wait for a new event or a timeout. If Tcl_WaitForEvent * returns -1, we should abort Tcl_DoOneEvent. */ result = Tcl_WaitForEvent(timePtr); if (result < 0) { result = 0; break; } /* * Check all the event sources for new events. */ for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->checkProc) { (sourcePtr->checkProc)(sourcePtr->clientData, flags); } } /* * Check for events queued by the notifier or event sources. */ if (Tcl_ServiceEvent(flags)) { result = 1; break; } /* * We've tried everything at this point, but nobody we know * about had anything to do. Check for idle events. If none, * either quit or go back to the top and try again. */ idleEvents: if (flags & TCL_IDLE_EVENTS) { if (TclServiceIdle()) { result = 1; break; } } if (flags & TCL_DONT_WAIT) { break; } /* * 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 system events. */ if (result) { break; } } tsdPtr->serviceMode = oldMode; return result;}/* *---------------------------------------------------------------------- * * Tcl_ServiceAll -- * * This routine checks all of the event sources, processes * events that are on the Tcl event queue, and then calls the * any idle handlers. Platform specific notifier callbacks that * generate events should call this routine before returning to * the system in order to ensure that Tcl gets a chance to * process the new events. * * Results: * Returns 1 if an event or idle handler was invoked, else 0. * * Side effects: * Anything that an event or idle handler may do. * *---------------------------------------------------------------------- */intTcl_ServiceAll(){ int result = 0; EventSource *sourcePtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (tsdPtr->serviceMode == TCL_SERVICE_NONE) { return result; } /* * We need to turn off event servicing like we to in Tcl_DoOneEvent, * to avoid recursive calls. */ tsdPtr->serviceMode = TCL_SERVICE_NONE; /* * Check async handlers first. */ if (Tcl_AsyncReady()) { (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); } /* * Make a single pass through all event sources, queued events, * and idle handlers. Note that we wait to update the notifier * timer until the end so we can avoid multiple changes. */ tsdPtr->inTraversal = 1; tsdPtr->blockTimeSet = 0; for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; sourcePtr = sourcePtr->nextPtr) { if (sourcePtr->setupProc) { (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); } } while (Tcl_ServiceEvent(0)) { result = 1; } if (TclServiceIdle()) { result = 1; } if (!tsdPtr->blockTimeSet) { Tcl_SetTimer(NULL); } else { Tcl_SetTimer(&tsdPtr->blockTime); } tsdPtr->inTraversal = 0; tsdPtr->serviceMode = TCL_SERVICE_ALL; return result;}/* *---------------------------------------------------------------------- * * Tcl_ThreadAlert -- * * This function wakes up the notifier associated with the * specified thread (if there is one). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */voidTcl_ThreadAlert(threadId) Tcl_ThreadId threadId; /* Identifier for thread to use. */{ ThreadSpecificData *tsdPtr; /* * Find the notifier associated with the specified thread. * Note that we need to hold the listLock while calling * Tcl_AlertNotifier to avoid a race condition where * the specified thread might destroy its notifier. */ Tcl_MutexLock(&listLock); for (tsdPtr = firstNotifierPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) { if (tsdPtr->threadId == threadId) { if (tclStubs.tcl_AlertNotifier) { tclStubs.tcl_AlertNotifier(tsdPtr->clientData); } break; } } Tcl_MutexUnlock(&listLock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -