os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclNotify.c
Update contrib.
4 * This file implements the generic portion of the Tcl notifier.
5 * The notifier is lowest-level part of the event system. It
6 * manages an event queue that holds Tcl_Event structures. The
7 * platform specific portion of the notifier is defined in the
8 * tcl*Notify.c files in each platform directory.
10 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
11 * Copyright (c) 1998 by Scriptics Corporation.
12 * Copyright (c) 2003 by Kevin B. Kenny. All rights reserved.
13 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
15 * See the file "license.terms" for information on usage and redistribution
16 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * RCS: @(#) $Id: tclNotify.c,v 1.11.2.2 2005/04/26 00:46:02 das Exp $
23 #if defined(__SYMBIAN32__) && defined(__WINSCW__)
24 #include "tclSymbianGlobals.h"
25 #define dataKey getdataKey(5)
28 extern TclStubs tclStubs;
31 * For each event source (created with Tcl_CreateEventSource) there
32 * is a structure of the following type:
35 typedef struct EventSource {
36 Tcl_EventSetupProc *setupProc;
37 Tcl_EventCheckProc *checkProc;
38 ClientData clientData;
39 struct EventSource *nextPtr;
43 * The following structure keeps track of the state of the notifier on a
44 * per-thread basis. The first three elements keep track of the event queue.
45 * In addition to the first (next to be serviced) and last events in the queue,
46 * we keep track of a "marker" event. This provides a simple priority
47 * mechanism whereby events can be inserted at the front of the queue but
48 * behind all other high-priority events already in the queue (this is used for
49 * things like a sequence of Enter and Leave events generated during a grab in
50 * Tk). These elements are protected by the queueMutex so that any thread
51 * can queue an event on any notifier. Note that all of the values in this
52 * structure will be initialized to 0.
55 typedef struct ThreadSpecificData {
56 Tcl_Event *firstEventPtr; /* First pending event, or NULL if none. */
57 Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */
58 Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or
60 Tcl_Mutex queueMutex; /* Mutex to protect access to the previous
62 int serviceMode; /* One of TCL_SERVICE_NONE or
64 int blockTimeSet; /* 0 means there is no maximum block
65 * time: block forever. */
66 Tcl_Time blockTime; /* If blockTimeSet is 1, gives the
67 * maximum elapsed time for the next block. */
68 int inTraversal; /* 1 if Tcl_SetMaxBlockTime is being
69 * called during an event source traversal. */
70 EventSource *firstEventSourcePtr;
71 /* Pointer to first event source in
72 * list of event sources for this thread. */
73 Tcl_ThreadId threadId; /* Thread that owns this notifier instance. */
74 ClientData clientData; /* Opaque handle for platform specific
76 int initialized; /* 1 if notifier has been initialized. */
77 struct ThreadSpecificData *nextPtr;
78 /* Next notifier in global list of notifiers.
79 * Access is controlled by the listLock global
83 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
84 static Tcl_ThreadDataKey dataKey;
88 * Global list of notifiers. Access to this list is controlled by the
89 * listLock mutex. If this becomes a performance bottleneck, this could
90 * be replaced with a hashtable.
93 static ThreadSpecificData *firstNotifierPtr;
95 #define firstNotifierPtr (*(ThreadSpecificData**)get_firstNotifierPtr())
97 TCL_DECLARE_MUTEX(listLock)
100 * Declarations for routines used only in this file.
103 static void QueueEvent _ANSI_ARGS_((ThreadSpecificData *tsdPtr,
104 Tcl_Event* evPtr, Tcl_QueuePosition position));
107 *----------------------------------------------------------------------
111 * Initialize the thread local data structures for the notifier
118 * Adds the current thread to the global list of notifiers.
120 *----------------------------------------------------------------------
126 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
128 Tcl_MutexLock(&listLock);
130 tsdPtr->threadId = Tcl_GetCurrentThread();
131 tsdPtr->clientData = tclStubs.tcl_InitNotifier();
132 tsdPtr->initialized = 1;
133 tsdPtr->nextPtr = firstNotifierPtr;
134 firstNotifierPtr = tsdPtr;
136 Tcl_MutexUnlock(&listLock);
140 *----------------------------------------------------------------------
142 * TclFinalizeNotifier --
144 * Finalize the thread local data structures for the notifier
151 * Removes the notifier associated with the current thread from
152 * the global notifier list. This is done only if the notifier
153 * was initialized for this thread by call to TclInitNotifier().
154 * This is always true for threads which have been seeded with
155 * an Tcl interpreter, since the call to Tcl_CreateInterp will,
156 * among other things, call TclInitializeSubsystems() and this
157 * one will, in turn, call the TclInitNotifier() for the thread.
158 * For threads created without the Tcl interpreter, though,
159 * nobody is explicitly nor implicitly calling the TclInitNotifier
160 * hence, TclFinalizeNotifier should not be performed at all.
162 *----------------------------------------------------------------------
166 TclFinalizeNotifier()
168 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
169 ThreadSpecificData **prevPtrPtr;
170 Tcl_Event *evPtr, *hold;
172 if (!tsdPtr->initialized) {
173 return; /* Notifier not initialized for the current thread */
176 Tcl_MutexLock(&(tsdPtr->queueMutex));
177 for (evPtr = tsdPtr->firstEventPtr; evPtr != (Tcl_Event *) NULL; ) {
179 evPtr = evPtr->nextPtr;
180 ckfree((char *) hold);
182 tsdPtr->firstEventPtr = NULL;
183 tsdPtr->lastEventPtr = NULL;
184 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
186 Tcl_MutexLock(&listLock);
188 if (tclStubs.tcl_FinalizeNotifier) {
189 tclStubs.tcl_FinalizeNotifier(tsdPtr->clientData);
191 Tcl_MutexFinalize(&(tsdPtr->queueMutex));
192 for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
193 prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {
194 if (*prevPtrPtr == tsdPtr) {
195 *prevPtrPtr = tsdPtr->nextPtr;
199 tsdPtr->initialized = 0;
201 Tcl_MutexUnlock(&listLock);
205 *----------------------------------------------------------------------
209 * Install a set of alternate functions for use with the notifier.
210 # In particular, this can be used to install the Xt-based
211 * notifier for use with the Browser plugin.
217 * Overstomps part of the stub vector. This relies on hooks
218 * added to the default procedures in case those are called
219 * directly (i.e., not through the stub table.)
221 *----------------------------------------------------------------------
225 Tcl_SetNotifier(notifierProcPtr)
226 Tcl_NotifierProcs *notifierProcPtr;
228 #if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */
229 tclStubs.tcl_CreateFileHandler = notifierProcPtr->createFileHandlerProc;
230 tclStubs.tcl_DeleteFileHandler = notifierProcPtr->deleteFileHandlerProc;
232 tclStubs.tcl_SetTimer = notifierProcPtr->setTimerProc;
233 tclStubs.tcl_WaitForEvent = notifierProcPtr->waitForEventProc;
234 tclStubs.tcl_InitNotifier = notifierProcPtr->initNotifierProc;
235 tclStubs.tcl_FinalizeNotifier = notifierProcPtr->finalizeNotifierProc;
236 tclStubs.tcl_AlertNotifier = notifierProcPtr->alertNotifierProc;
237 tclStubs.tcl_ServiceModeHook = notifierProcPtr->serviceModeHookProc;
241 *----------------------------------------------------------------------
243 * Tcl_CreateEventSource --
245 * This procedure is invoked to create a new source of events.
246 * The source is identified by a procedure that gets invoked
247 * during Tcl_DoOneEvent to check for events on that source
255 * SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent
256 * runs out of things to do. SetupProc will be invoked before
257 * Tcl_DoOneEvent calls select or whatever else it uses to wait
258 * for events. SetupProc typically calls functions like
259 * Tcl_SetMaxBlockTime to indicate what to wait for.
261 * CheckProc is called after select or whatever operation was actually
262 * used to wait. It figures out whether anything interesting actually
263 * happened (e.g. by calling Tcl_AsyncReady), and then calls
264 * Tcl_QueueEvent to queue any events that are ready.
266 * Each of these procedures is passed two arguments, e.g.
267 * (*checkProc)(ClientData clientData, int flags));
268 * ClientData is the same as the clientData argument here, and flags
269 * is a combination of things like TCL_FILE_EVENTS that indicates
270 * what events are of interest: setupProc and checkProc use flags
271 * to figure out whether their events are relevant or not.
273 *----------------------------------------------------------------------
277 Tcl_CreateEventSource(setupProc, checkProc, clientData)
278 Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out
279 * what to wait for. */
280 Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting
281 * to see what happened. */
282 ClientData clientData; /* One-word argument to pass to
283 * setupProc and checkProc. */
285 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
286 EventSource *sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
288 sourcePtr->setupProc = setupProc;
289 sourcePtr->checkProc = checkProc;
290 sourcePtr->clientData = clientData;
291 sourcePtr->nextPtr = tsdPtr->firstEventSourcePtr;
292 tsdPtr->firstEventSourcePtr = sourcePtr;
296 *----------------------------------------------------------------------
298 * Tcl_DeleteEventSource --
300 * This procedure is invoked to delete the source of events
301 * given by proc and clientData.
307 * The given event source is cancelled, so its procedure will
308 * never again be called. If no such source exists, nothing
311 *----------------------------------------------------------------------
315 Tcl_DeleteEventSource(setupProc, checkProc, clientData)
316 Tcl_EventSetupProc *setupProc; /* Procedure to invoke to figure out
317 * what to wait for. */
318 Tcl_EventCheckProc *checkProc; /* Procedure to call after waiting
319 * to see what happened. */
320 ClientData clientData; /* One-word argument to pass to
321 * setupProc and checkProc. */
323 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
324 EventSource *sourcePtr, *prevPtr;
326 for (sourcePtr = tsdPtr->firstEventSourcePtr, prevPtr = NULL;
328 prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {
329 if ((sourcePtr->setupProc != setupProc)
330 || (sourcePtr->checkProc != checkProc)
331 || (sourcePtr->clientData != clientData)) {
334 if (prevPtr == NULL) {
335 tsdPtr->firstEventSourcePtr = sourcePtr->nextPtr;
337 prevPtr->nextPtr = sourcePtr->nextPtr;
339 ckfree((char *) sourcePtr);
345 *----------------------------------------------------------------------
349 * Queue an event on the event queue associated with the
358 *----------------------------------------------------------------------
362 Tcl_QueueEvent(evPtr, position)
363 Tcl_Event* evPtr; /* Event to add to queue. The storage
364 * space must have been allocated the caller
365 * with malloc (ckalloc), and it becomes
366 * the property of the event queue. It
367 * will be freed after the event has been
369 Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
372 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
373 QueueEvent(tsdPtr, evPtr, position);
377 *----------------------------------------------------------------------
379 * Tcl_ThreadQueueEvent --
381 * Queue an event on the specified thread's event queue.
389 *----------------------------------------------------------------------
393 Tcl_ThreadQueueEvent(threadId, evPtr, position)
394 Tcl_ThreadId threadId; /* Identifier for thread to use. */
395 Tcl_Event* evPtr; /* Event to add to queue. The storage
396 * space must have been allocated the caller
397 * with malloc (ckalloc), and it becomes
398 * the property of the event queue. It
399 * will be freed after the event has been
401 Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
404 ThreadSpecificData *tsdPtr;
407 * Find the notifier associated with the specified thread.
410 Tcl_MutexLock(&listLock);
411 for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId;
412 tsdPtr = tsdPtr->nextPtr) {
413 /* Empty loop body. */
417 * Queue the event if there was a notifier associated with the thread.
421 QueueEvent(tsdPtr, evPtr, position);
423 Tcl_MutexUnlock(&listLock);
427 *----------------------------------------------------------------------
431 * Insert an event into the specified thread's event queue at one
432 * of three positions: the head, the tail, or before a floating
433 * marker. Events inserted before the marker will be processed in
434 * first-in-first-out order, but before any events inserted at
435 * the tail of the queue. Events inserted at the head of the
436 * queue will be processed in last-in-first-out order.
444 *----------------------------------------------------------------------
448 QueueEvent(tsdPtr, evPtr, position)
449 ThreadSpecificData *tsdPtr; /* Handle to thread local data that indicates
450 * which event queue to use. */
451 Tcl_Event* evPtr; /* Event to add to queue. The storage
452 * space must have been allocated the caller
453 * with malloc (ckalloc), and it becomes
454 * the property of the event queue. It
455 * will be freed after the event has been
457 Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
460 Tcl_MutexLock(&(tsdPtr->queueMutex));
461 if (position == TCL_QUEUE_TAIL) {
463 * Append the event on the end of the queue.
466 evPtr->nextPtr = NULL;
467 if (tsdPtr->firstEventPtr == NULL) {
468 tsdPtr->firstEventPtr = evPtr;
470 tsdPtr->lastEventPtr->nextPtr = evPtr;
472 tsdPtr->lastEventPtr = evPtr;
473 } else if (position == TCL_QUEUE_HEAD) {
475 * Push the event on the head of the queue.
478 evPtr->nextPtr = tsdPtr->firstEventPtr;
479 if (tsdPtr->firstEventPtr == NULL) {
480 tsdPtr->lastEventPtr = evPtr;
482 tsdPtr->firstEventPtr = evPtr;
483 } else if (position == TCL_QUEUE_MARK) {
485 * Insert the event after the current marker event and advance
486 * the marker to the new event.
489 if (tsdPtr->markerEventPtr == NULL) {
490 evPtr->nextPtr = tsdPtr->firstEventPtr;
491 tsdPtr->firstEventPtr = evPtr;
493 evPtr->nextPtr = tsdPtr->markerEventPtr->nextPtr;
494 tsdPtr->markerEventPtr->nextPtr = evPtr;
496 tsdPtr->markerEventPtr = evPtr;
497 if (evPtr->nextPtr == NULL) {
498 tsdPtr->lastEventPtr = evPtr;
501 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
505 *----------------------------------------------------------------------
507 * Tcl_DeleteEvents --
509 * Calls a procedure for each event in the queue and deletes those
510 * for which the procedure returns 1. Events for which the
511 * procedure returns 0 are left in the queue. Operates on the
512 * queue associated with the current thread.
518 * Potentially removes one or more events from the event queue.
520 *----------------------------------------------------------------------
524 Tcl_DeleteEvents(proc, clientData)
525 Tcl_EventDeleteProc *proc; /* The procedure to call. */
526 ClientData clientData; /* type-specific data. */
528 Tcl_Event *evPtr, *prevPtr, *hold;
529 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
531 Tcl_MutexLock(&(tsdPtr->queueMutex));
532 for (prevPtr = (Tcl_Event *) NULL, evPtr = tsdPtr->firstEventPtr;
533 evPtr != (Tcl_Event *) NULL;
535 if ((*proc) (evPtr, clientData) == 1) {
536 if (tsdPtr->firstEventPtr == evPtr) {
537 tsdPtr->firstEventPtr = evPtr->nextPtr;
539 prevPtr->nextPtr = evPtr->nextPtr;
541 if (evPtr->nextPtr == (Tcl_Event *) NULL) {
542 tsdPtr->lastEventPtr = prevPtr;
544 if (tsdPtr->markerEventPtr == evPtr) {
545 tsdPtr->markerEventPtr = prevPtr;
548 evPtr = evPtr->nextPtr;
549 ckfree((char *) hold);
552 evPtr = evPtr->nextPtr;
555 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
559 *----------------------------------------------------------------------
561 * Tcl_ServiceEvent --
563 * Process one event from the event queue, or invoke an
564 * asynchronous event handler. Operates on event queue for
568 * The return value is 1 if the procedure actually found an event
569 * to process. If no processing occurred, then 0 is returned.
572 * Invokes all of the event handlers for the highest priority
573 * event in the event queue. May collapse some events into a
574 * single event or discard stale events.
576 *----------------------------------------------------------------------
580 Tcl_ServiceEvent(flags)
581 int flags; /* Indicates what events should be processed.
582 * May be any combination of TCL_WINDOW_EVENTS
583 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
584 * flags defined elsewhere. Events not
585 * matching this will be skipped for processing
588 Tcl_Event *evPtr, *prevPtr;
591 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
594 * Asynchronous event handlers are considered to be the highest
595 * priority events, and so must be invoked before we process events
596 * on the event queue.
599 if (Tcl_AsyncReady()) {
600 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
605 * No event flags is equivalent to TCL_ALL_EVENTS.
608 if ((flags & TCL_ALL_EVENTS) == 0) {
609 flags |= TCL_ALL_EVENTS;
613 * Loop through all the events in the queue until we find one
614 * that can actually be handled.
617 Tcl_MutexLock(&(tsdPtr->queueMutex));
618 for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL;
619 evPtr = evPtr->nextPtr) {
621 * Call the handler for the event. If it actually handles the
622 * event then free the storage for the event. There are two
623 * tricky things here, both stemming from the fact that the event
624 * code may be re-entered while servicing the event:
626 * 1. Set the "proc" field to NULL. This is a signal to ourselves
627 * that we shouldn't reexecute the handler if the event loop
629 * 2. When freeing the event, must search the queue again from the
630 * front to find it. This is because the event queue could
631 * change almost arbitrarily while handling the event, so we
632 * can't depend on pointers found now still being valid when
633 * the handler returns.
643 * Release the lock before calling the event procedure. This
644 * allows other threads to post events if we enter a recursive
645 * event loop in this thread. Note that we are making the assumption
646 * that if the proc returns 0, the event is still in the list.
649 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
650 result = (*proc)(evPtr, flags);
651 Tcl_MutexLock(&(tsdPtr->queueMutex));
655 * The event was processed, so remove it from the queue.
658 if (tsdPtr->firstEventPtr == evPtr) {
659 tsdPtr->firstEventPtr = evPtr->nextPtr;
660 if (evPtr->nextPtr == NULL) {
661 tsdPtr->lastEventPtr = NULL;
663 if (tsdPtr->markerEventPtr == evPtr) {
664 tsdPtr->markerEventPtr = NULL;
667 for (prevPtr = tsdPtr->firstEventPtr;
668 prevPtr && prevPtr->nextPtr != evPtr;
669 prevPtr = prevPtr->nextPtr) {
670 /* Empty loop body. */
673 prevPtr->nextPtr = evPtr->nextPtr;
674 if (evPtr->nextPtr == NULL) {
675 tsdPtr->lastEventPtr = prevPtr;
677 if (tsdPtr->markerEventPtr == evPtr) {
678 tsdPtr->markerEventPtr = prevPtr;
685 ckfree((char *) evPtr);
687 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
691 * The event wasn't actually handled, so we have to restore
692 * the proc field to allow the event to be attempted again.
698 Tcl_MutexUnlock(&(tsdPtr->queueMutex));
703 *----------------------------------------------------------------------
705 * Tcl_GetServiceMode --
707 * This routine returns the current service mode of the notifier.
710 * Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
715 *----------------------------------------------------------------------
721 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
723 return tsdPtr->serviceMode;
727 *----------------------------------------------------------------------
729 * Tcl_SetServiceMode --
731 * This routine sets the current service mode of the tsdPtr->
734 * Returns the previous service mode.
737 * Invokes the notifier service mode hook procedure.
739 *----------------------------------------------------------------------
743 Tcl_SetServiceMode(mode)
744 int mode; /* New service mode: TCL_SERVICE_ALL or
745 * TCL_SERVICE_NONE */
748 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
750 oldMode = tsdPtr->serviceMode;
751 tsdPtr->serviceMode = mode;
752 if (tclStubs.tcl_ServiceModeHook) {
753 tclStubs.tcl_ServiceModeHook(mode);
759 *----------------------------------------------------------------------
761 * Tcl_SetMaxBlockTime --
763 * This procedure is invoked by event sources to tell the notifier
764 * how long it may block the next time it blocks. The timePtr
765 * argument gives a maximum time; the actual time may be less if
766 * some other event source requested a smaller time.
772 * May reduce the length of the next sleep in the tsdPtr->
774 *----------------------------------------------------------------------
778 Tcl_SetMaxBlockTime(timePtr)
779 Tcl_Time *timePtr; /* Specifies a maximum elapsed time for
780 * the next blocking operation in the
783 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
785 if (!tsdPtr->blockTimeSet || (timePtr->sec < tsdPtr->blockTime.sec)
786 || ((timePtr->sec == tsdPtr->blockTime.sec)
787 && (timePtr->usec < tsdPtr->blockTime.usec))) {
788 tsdPtr->blockTime = *timePtr;
789 tsdPtr->blockTimeSet = 1;
793 * If we are called outside an event source traversal, set the
794 * timeout immediately.
797 if (!tsdPtr->inTraversal) {
798 if (tsdPtr->blockTimeSet) {
799 Tcl_SetTimer(&tsdPtr->blockTime);
807 *----------------------------------------------------------------------
811 * Process a single event of some sort. If there's no work to
812 * do, wait for an event to occur, then process it.
815 * The return value is 1 if the procedure actually found an event
816 * to process. If no processing occurred, then 0 is returned (this
817 * can happen if the TCL_DONT_WAIT flag is set or if there are no
818 * event handlers to wait for in the set specified by flags).
821 * May delay execution of process while waiting for an event,
822 * unless TCL_DONT_WAIT is set in the flags argument. Event
823 * sources are invoked to check for and queue events. Event
824 * handlers may produce arbitrary side effects.
826 *----------------------------------------------------------------------
830 Tcl_DoOneEvent(flags)
831 int flags; /* Miscellaneous flag values: may be any
832 * combination of TCL_DONT_WAIT,
833 * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
834 * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
835 * others defined by event sources. */
837 int result = 0, oldMode;
838 EventSource *sourcePtr;
840 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
843 * The first thing we do is to service any asynchronous event
847 if (Tcl_AsyncReady()) {
848 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
853 * No event flags is equivalent to TCL_ALL_EVENTS.
856 if ((flags & TCL_ALL_EVENTS) == 0) {
857 flags |= TCL_ALL_EVENTS;
861 * Set the service mode to none so notifier event routines won't
862 * try to service events recursively.
865 oldMode = tsdPtr->serviceMode;
866 tsdPtr->serviceMode = TCL_SERVICE_NONE;
869 * The core of this procedure is an infinite loop, even though
870 * we only service one event. The reason for this is that we
871 * may be processing events that don't do anything inside of Tcl.
877 * If idle events are the only things to service, skip the
878 * main part of the loop and go directly to handle idle
879 * events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
882 if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
883 flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
888 * Ask Tcl to service a queued event, if there are any.
891 if (Tcl_ServiceEvent(flags)) {
897 * If TCL_DONT_WAIT is set, be sure to poll rather than
898 * blocking, otherwise reset the block time to infinity.
901 if (flags & TCL_DONT_WAIT) {
902 tsdPtr->blockTime.sec = 0;
903 tsdPtr->blockTime.usec = 0;
904 tsdPtr->blockTimeSet = 1;
906 tsdPtr->blockTimeSet = 0;
910 * Set up all the event sources for new events. This will
911 * cause the block time to be updated if necessary.
914 tsdPtr->inTraversal = 1;
915 for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
916 sourcePtr = sourcePtr->nextPtr) {
917 if (sourcePtr->setupProc) {
918 (sourcePtr->setupProc)(sourcePtr->clientData, flags);
921 tsdPtr->inTraversal = 0;
923 if ((flags & TCL_DONT_WAIT) || tsdPtr->blockTimeSet) {
924 timePtr = &tsdPtr->blockTime;
930 * Wait for a new event or a timeout. If Tcl_WaitForEvent
931 * returns -1, we should abort Tcl_DoOneEvent.
934 result = Tcl_WaitForEvent(timePtr);
941 * Check all the event sources for new events.
944 for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
945 sourcePtr = sourcePtr->nextPtr) {
946 if (sourcePtr->checkProc) {
947 (sourcePtr->checkProc)(sourcePtr->clientData, flags);
952 * Check for events queued by the notifier or event sources.
955 if (Tcl_ServiceEvent(flags)) {
961 * We've tried everything at this point, but nobody we know
962 * about had anything to do. Check for idle events. If none,
963 * either quit or go back to the top and try again.
967 if (flags & TCL_IDLE_EVENTS) {
968 if (TclServiceIdle()) {
973 if (flags & TCL_DONT_WAIT) {
978 * If Tcl_WaitForEvent has returned 1,
979 * indicating that one system event has been dispatched
980 * (and thus that some Tcl code might have been indirectly executed),
981 * we break out of the loop.
982 * We do this to give VwaitCmd for instance a chance to check
983 * if that system event had the side effect of changing the
984 * variable (so the vwait can return and unwind properly).
986 * NB: We will process idle events if any first, because
987 * otherwise we might never do the idle events if the notifier
988 * always gets system events.
997 tsdPtr->serviceMode = oldMode;
1002 *----------------------------------------------------------------------
1006 * This routine checks all of the event sources, processes
1007 * events that are on the Tcl event queue, and then calls the
1008 * any idle handlers. Platform specific notifier callbacks that
1009 * generate events should call this routine before returning to
1010 * the system in order to ensure that Tcl gets a chance to
1011 * process the new events.
1014 * Returns 1 if an event or idle handler was invoked, else 0.
1017 * Anything that an event or idle handler may do.
1019 *----------------------------------------------------------------------
1026 EventSource *sourcePtr;
1027 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1029 if (tsdPtr->serviceMode == TCL_SERVICE_NONE) {
1034 * We need to turn off event servicing like we to in Tcl_DoOneEvent,
1035 * to avoid recursive calls.
1038 tsdPtr->serviceMode = TCL_SERVICE_NONE;
1041 * Check async handlers first.
1044 if (Tcl_AsyncReady()) {
1045 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
1049 * Make a single pass through all event sources, queued events,
1050 * and idle handlers. Note that we wait to update the notifier
1051 * timer until the end so we can avoid multiple changes.
1054 tsdPtr->inTraversal = 1;
1055 tsdPtr->blockTimeSet = 0;
1057 for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
1058 sourcePtr = sourcePtr->nextPtr) {
1059 if (sourcePtr->setupProc) {
1060 (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
1063 for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
1064 sourcePtr = sourcePtr->nextPtr) {
1065 if (sourcePtr->checkProc) {
1066 (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
1070 while (Tcl_ServiceEvent(0)) {
1073 if (TclServiceIdle()) {
1077 if (!tsdPtr->blockTimeSet) {
1080 Tcl_SetTimer(&tsdPtr->blockTime);
1082 tsdPtr->inTraversal = 0;
1083 tsdPtr->serviceMode = TCL_SERVICE_ALL;
1088 *----------------------------------------------------------------------
1090 * Tcl_ThreadAlert --
1092 * This function wakes up the notifier associated with the
1093 * specified thread (if there is one).
1101 *----------------------------------------------------------------------
1105 Tcl_ThreadAlert(threadId)
1106 Tcl_ThreadId threadId; /* Identifier for thread to use. */
1108 ThreadSpecificData *tsdPtr;
1111 * Find the notifier associated with the specified thread.
1112 * Note that we need to hold the listLock while calling
1113 * Tcl_AlertNotifier to avoid a race condition where
1114 * the specified thread might destroy its notifier.
1117 Tcl_MutexLock(&listLock);
1118 for (tsdPtr = firstNotifierPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
1119 if (tsdPtr->threadId == threadId) {
1120 if (tclStubs.tcl_AlertNotifier) {
1121 tclStubs.tcl_AlertNotifier(tsdPtr->clientData);
1126 Tcl_MutexUnlock(&listLock);