diff options
Diffstat (limited to 'generic/tclNotify.c')
| -rw-r--r-- | generic/tclNotify.c | 677 | 
1 files changed, 369 insertions, 308 deletions
| diff --git a/generic/tclNotify.c b/generic/tclNotify.c index 2ce8f72..e76bca8 100644 --- a/generic/tclNotify.c +++ b/generic/tclNotify.c @@ -1,29 +1,34 @@ -/*  +/*   * tclNotify.c --   * - *	This file implements the generic portion of the Tcl notifier. - *	The notifier is lowest-level part of the event system.  It - *	manages an event queue that holds Tcl_Event structures.  The - *	platform specific portion of the notifier is defined in the - *	tcl*Notify.c files in each platform directory. + *	This file implements the generic portion of the Tcl notifier. The + *	notifier is lowest-level part of the event system. It manages an event + *	queue that holds Tcl_Event structures. The platform specific portion + *	of the notifier is defined in the tcl*Notify.c files in each platform + *	directory.   *   * 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. - * - * RCS: @(#) $Id: tclNotify.c,v 1.6 1999/07/02 21:50:04 redman Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclInt.h" -#include "tclPort.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 structure of the following type: + * For each event source (created with Tcl_CreateEventSource) there is a + * structure of the following type:   */  typedef struct EventSource { @@ -36,37 +41,38 @@ typedef struct EventSource {  /*   * The following structure keeps track of the state of the notifier on a   * per-thread basis. The first three elements keep track of the event queue. - * In addition to the first (next to be serviced) and last events in the queue, - * we keep track of a "marker" event.  This provides a simple priority + * In addition to the first (next to be serviced) and last events in the + * queue, we keep track of a "marker" event. This provides a simple priority   * mechanism whereby events can be inserted at the front of the queue but - * behind all other high-priority events already in the queue (this is used for - * things like a sequence of Enter and Leave events generated during a grab in - * Tk).  These elements are protected by the queueMutex so that any thread - * can queue an event on any notifier.  Note that all of the values in this - * structure will be initialized to 0. + * behind all other high-priority events already in the queue (this is used + * for things like a sequence of Enter and Leave events generated during a + * grab in Tk). These elements are protected by the queueMutex so that any + * thread can queue an event on any notifier. Note that all of the values in + * this structure will be initialized to 0.   */  typedef struct ThreadSpecificData {      Tcl_Event *firstEventPtr;	/* First pending event, or NULL if none. */      Tcl_Event *lastEventPtr;	/* Last pending event, or NULL if none. */ -    Tcl_Event *markerEventPtr;	/* Last high-priority event in queue, or -				 * NULL if none. */ +    Tcl_Event *markerEventPtr;	/* Last high-priority event in queue, or NULL +				 * if none. */      Tcl_Mutex queueMutex;	/* Mutex to protect access to the previous  				 * three fields. */      int serviceMode;		/* One of TCL_SERVICE_NONE or  				 * TCL_SERVICE_ALL. */ -    int blockTimeSet;		/* 0 means there is no maximum block -				 * time:  block forever. */ -    Tcl_Time blockTime;		/* If blockTimeSet is 1, gives the -				 * maximum elapsed time for the next block. */ -    int inTraversal;		/* 1 if Tcl_SetMaxBlockTime is being -				 * called during an event source traversal. */ +    int blockTimeSet;		/* 0 means there is no maximum block time: +				 * block forever. */ +    Tcl_Time blockTime;		/* If blockTimeSet is 1, gives the maximum +				 * elapsed time for the next block. */ +    int inTraversal;		/* 1 if Tcl_SetMaxBlockTime is being called +				 * during an event source traversal. */      EventSource *firstEventSourcePtr; -				/* Pointer to first event source in -				 * list of event sources for this thread. */ +				/* Pointer to first event source in list of +				 * event sources for this thread. */      Tcl_ThreadId threadId;	/* Thread that owns this notifier instance. */      ClientData clientData;	/* Opaque handle for platform specific  				 * notifier. */ +    int initialized;		/* 1 if notifier has been initialized. */      struct ThreadSpecificData *nextPtr;  				/* Next notifier in global list of notifiers.  				 * Access is controlled by the listLock global @@ -76,20 +82,20 @@ typedef struct ThreadSpecificData {  static Tcl_ThreadDataKey dataKey;  /* - * Global list of notifiers.  Access to this list is controlled by the - * listLock mutex.  If this becomes a performance bottleneck, this could - * be replaced with a hashtable. + * Global list of notifiers. Access to this list is controlled by the listLock + * mutex. If this becomes a performance bottleneck, this could be replaced + * with a hashtable.   */ -static ThreadSpecificData *firstNotifierPtr; +static ThreadSpecificData *firstNotifierPtr = NULL;  TCL_DECLARE_MUTEX(listLock)  /*   * Declarations for routines used only in this file.   */ -static void		QueueEvent _ANSI_ARGS_((ThreadSpecificData *tsdPtr, -			    Tcl_Event* evPtr, Tcl_QueuePosition position)); +static void		QueueEvent(ThreadSpecificData *tsdPtr, +			    Tcl_Event *evPtr, Tcl_QueuePosition position);  /*   *---------------------------------------------------------------------- @@ -109,17 +115,29 @@ static void		QueueEvent _ANSI_ARGS_((ThreadSpecificData *tsdPtr,   */  void -TclInitNotifier() +TclInitNotifier(void)  { -    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); +    ThreadSpecificData *tsdPtr; +    Tcl_ThreadId threadId = Tcl_GetCurrentThread();      Tcl_MutexLock(&listLock); +    for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId; +	    tsdPtr = tsdPtr->nextPtr) { +	/* Empty loop body. */ +    } -    tsdPtr->threadId = Tcl_GetCurrentThread(); -    tsdPtr->clientData = Tcl_InitNotifier(); -    tsdPtr->nextPtr = firstNotifierPtr; -    firstNotifierPtr = tsdPtr; +    if (NULL == tsdPtr) { +	/* +	 * Notifier not yet initialized in this thread. +	 */ +	tsdPtr = TCL_TSD_INIT(&dataKey); +	tsdPtr->threadId = threadId; +	tsdPtr->clientData = Tcl_InitNotifier(); +	tsdPtr->initialized = 1; +	tsdPtr->nextPtr = firstNotifierPtr; +	firstNotifierPtr = tsdPtr; +    }      Tcl_MutexUnlock(&listLock);  } @@ -128,36 +146,59 @@ TclInitNotifier()   *   * TclFinalizeNotifier --   * - *	Finalize the thread local data structures for the notifier - *	subsystem. + *	Finalize the thread local data structures for the notifier subsystem.   *   * Results: - *	None.	 + *	None.   *   * Side effects: - *	Removes the notifier associated with the current thread from - *	the global notifier list. + *	Removes the notifier associated with the current thread from the + *	global notifier list. This is done only if the notifier was + *	initialized for this thread by call to TclInitNotifier(). This is + *	always true for threads which have been seeded with an Tcl + *	interpreter, since the call to Tcl_CreateInterp will, among other + *	things, call TclInitializeSubsystems() and this one will, in turn, + *	call the TclInitNotifier() for the thread. For threads created without + *	the Tcl interpreter, though, nobody is explicitly nor implicitly + *	calling the TclInitNotifier hence, TclFinalizeNotifier should not be + *	performed at all.   *   *----------------------------------------------------------------------   */  void -TclFinalizeNotifier() +TclFinalizeNotifier(void)  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      ThreadSpecificData **prevPtrPtr; +    Tcl_Event *evPtr, *hold; + +    if (!tsdPtr->initialized) { +	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); +    } +    tsdPtr->firstEventPtr = NULL; +    tsdPtr->lastEventPtr = NULL; +    Tcl_MutexUnlock(&(tsdPtr->queueMutex));      Tcl_MutexLock(&listLock);      Tcl_FinalizeNotifier(tsdPtr->clientData); -    TclFinalizeMutex(&(tsdPtr->queueMutex)); +    Tcl_MutexFinalize(&(tsdPtr->queueMutex));      for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL; -	 prevPtrPtr = &((*prevPtrPtr)->nextPtr)) { +	    prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {  	if (*prevPtrPtr == tsdPtr) {  	    *prevPtrPtr = tsdPtr->nextPtr;  	    break;  	}      } +    tsdPtr->initialized = 0;      Tcl_MutexUnlock(&listLock);  } @@ -167,31 +208,25 @@ TclFinalizeNotifier()   *   * Tcl_SetNotifier --   * - *	Install a set of alternate functions for use with the notifier. - #	In particular, this can be used to install the Xt-based - *	notifier for use with the Browser plugin. + *	Install a set of alternate functions for use with the notifier. In + *	particular, this can be used to install the Xt-based notifier for use + *	with the Browser plugin.   *   * Results:   *	None.   *   * Side effects: - *	Overstomps part of the stub vector.  This relies on hooks - *	added to the default procedures 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.   *   *----------------------------------------------------------------------   */  void -Tcl_SetNotifier(notifierProcPtr) -    Tcl_NotifierProcs *notifierProcPtr; +Tcl_SetNotifier( +    Tcl_NotifierProcs *notifierProcPtr)  { -#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ -    tclStubs.tcl_CreateFileHandler = notifierProcPtr->createFileHandlerProc; -    tclStubs.tcl_DeleteFileHandler = notifierProcPtr->deleteFileHandlerProc; -#endif -    tclStubs.tcl_SetTimer = notifierProcPtr->setTimerProc; -    tclStubs.tcl_WaitForEvent = notifierProcPtr->waitForEventProc; +    tclNotifierHooks = *notifierProcPtr;  }  /* @@ -199,10 +234,9 @@ Tcl_SetNotifier(notifierProcPtr)   *   * Tcl_CreateEventSource --   * - *	This procedure is invoked to create a new source of events. - *	The source is identified by a procedure that gets invoked - *	during Tcl_DoOneEvent to check for events on that source - *	and queue them. + *	This function is invoked to create a new source of events. The source + *	is identified by a function that gets invoked during Tcl_DoOneEvent to + *	check for events on that source and queue them.   *   *   * Results: @@ -210,37 +244,39 @@ Tcl_SetNotifier(notifierProcPtr)   *   * Side effects:   *	SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent - *	runs out of things to do.  SetupProc will be invoked before - *	Tcl_DoOneEvent calls select or whatever else it uses to wait - *	for events.  SetupProc typically calls functions like - *	Tcl_SetMaxBlockTime to indicate what to wait for. + *	runs out of things to do. SetupProc will be invoked before + *	Tcl_DoOneEvent calls select or whatever else it uses to wait for + *	events. SetupProc typically calls functions like Tcl_SetMaxBlockTime + *	to indicate what to wait for.   *   *	CheckProc is called after select or whatever operation was actually - *	used to wait.  It figures out whether anything interesting actually + *	used to wait. It figures out whether anything interesting actually   *	happened (e.g. by calling Tcl_AsyncReady), and then calls   *	Tcl_QueueEvent to queue any events that are ready.   * - *	Each of these procedures is passed two arguments, e.g. + *	Each of these functions is passed two arguments, e.g.   *		(*checkProc)(ClientData clientData, int flags)); - *	ClientData is the same as the clientData argument here, and flags - *	is a combination of things like TCL_FILE_EVENTS that indicates - *	what events are of interest:  setupProc and checkProc use flags - *	to figure out whether their events are relevant or not. + *	ClientData is the same as the clientData argument here, and flags is a + *	combination of things like TCL_FILE_EVENTS that indicates what events + *	are of interest: setupProc and checkProc use flags to figure out + *	whether their events are relevant or not.   *   *----------------------------------------------------------------------   */  void -Tcl_CreateEventSource(setupProc, checkProc, clientData) -    Tcl_EventSetupProc *setupProc;	/* Procedure to invoke to figure out -					 * what to wait for. */ -    Tcl_EventCheckProc *checkProc;	/* Procedure to call after waiting -					 * to see what happened. */ -    ClientData clientData;		/* One-word argument to pass to -					 * setupProc and checkProc. */ +Tcl_CreateEventSource( +    Tcl_EventSetupProc *setupProc, +				/* Function to invoke to figure out what to +				 * wait for. */ +    Tcl_EventCheckProc *checkProc, +				/* Function to call after waiting to see what +				 * happened. */ +    ClientData clientData)	/* One-word argument to pass to setupProc and +				 * checkProc. */  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); -    EventSource *sourcePtr = (EventSource *) ckalloc(sizeof(EventSource)); +    EventSource *sourcePtr = ckalloc(sizeof(EventSource));      sourcePtr->setupProc = setupProc;      sourcePtr->checkProc = checkProc; @@ -254,28 +290,29 @@ Tcl_CreateEventSource(setupProc, checkProc, clientData)   *   * Tcl_DeleteEventSource --   * - *	This procedure is invoked to delete the source of events - *	given by proc and clientData. + *	This function is invoked to delete the source of events given by proc + *	and clientData.   *   * Results:   *	None.   *   * Side effects: - *	The given event source is cancelled, so its procedure will - *	never again be called.  If no such source exists, nothing - *	happens. + *	The given event source is canceled, so its function will never again + *	be called. If no such source exists, nothing happens.   *   *----------------------------------------------------------------------   */  void -Tcl_DeleteEventSource(setupProc, checkProc, clientData) -    Tcl_EventSetupProc *setupProc;	/* Procedure to invoke to figure out -					 * what to wait for. */ -    Tcl_EventCheckProc *checkProc;	/* Procedure to call after waiting -					 * to see what happened. */ -    ClientData clientData;		/* One-word argument to pass to -					 * setupProc and checkProc. */ +Tcl_DeleteEventSource( +    Tcl_EventSetupProc *setupProc, +				/* Function to invoke to figure out what to +				 * wait for. */ +    Tcl_EventCheckProc *checkProc, +				/* Function to call after waiting to see what +				 * happened. */ +    ClientData clientData)	/* One-word argument to pass to setupProc and +				 * checkProc. */  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      EventSource *sourcePtr, *prevPtr; @@ -293,7 +330,7 @@ Tcl_DeleteEventSource(setupProc, checkProc, clientData)  	} else {  	    prevPtr->nextPtr = sourcePtr->nextPtr;  	} -	ckfree((char *) sourcePtr); +	ckfree(sourcePtr);  	return;      }  } @@ -303,8 +340,7 @@ Tcl_DeleteEventSource(setupProc, checkProc, clientData)   *   * Tcl_QueueEvent --   * - *	Queue an event on the event queue associated with the - *	current thread. + *	Queue an event on the event queue associated with the current thread.   *   * Results:   *	None. @@ -316,17 +352,17 @@ Tcl_DeleteEventSource(setupProc, checkProc, clientData)   */  void -Tcl_QueueEvent(evPtr, position) -    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. */ -    Tcl_QueuePosition position;	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, +Tcl_QueueEvent( +    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. */ +    Tcl_QueuePosition position)	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,  				 * TCL_QUEUE_MARK. */  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); +      QueueEvent(tsdPtr, evPtr, position);  } @@ -347,15 +383,14 @@ Tcl_QueueEvent(evPtr, position)   */  void -Tcl_ThreadQueueEvent(threadId, evPtr, position) -    Tcl_ThreadId threadId;	/* Identifier for thread to use. */ -    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. */ -    Tcl_QueuePosition position;	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, +Tcl_ThreadQueueEvent( +    Tcl_ThreadId threadId,	/* Identifier for thread to use. */ +    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. */ +    Tcl_QueuePosition position)	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,  				 * TCL_QUEUE_MARK. */  {      ThreadSpecificData *tsdPtr; @@ -366,7 +401,7 @@ Tcl_ThreadQueueEvent(threadId, evPtr, position)      Tcl_MutexLock(&listLock);      for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId; -	     tsdPtr = tsdPtr->nextPtr) { +	    tsdPtr = tsdPtr->nextPtr) {  	/* Empty loop body. */      } @@ -376,6 +411,8 @@ Tcl_ThreadQueueEvent(threadId, evPtr, position)      if (tsdPtr) {  	QueueEvent(tsdPtr, evPtr, position); +    } else { +	ckfree(evPtr);      }      Tcl_MutexUnlock(&listLock);  } @@ -385,12 +422,12 @@ Tcl_ThreadQueueEvent(threadId, evPtr, position)   *   * QueueEvent --   * - *	Insert an event into the specified thread's event queue at one - *	of three positions: the head, the tail, or before a floating - *	marker. Events inserted before the marker will be processed in - *	first-in-first-out order, but before any events inserted at - *	the tail of the queue.  Events inserted at the head of the - *	queue will be processed in last-in-first-out order. + *	Insert an event into the specified thread's event queue at one of + *	three positions: the head, the tail, or before a floating marker. + *	Events inserted before the marker will be processed in first-in- + *	first-out order, but before any events inserted at the tail of the + *	queue. Events inserted at the head of the queue will be processed in + *	last-in-first-out order.   *   * Results:   *	None. @@ -402,16 +439,15 @@ Tcl_ThreadQueueEvent(threadId, evPtr, position)   */  static void -QueueEvent(tsdPtr, evPtr, position) -    ThreadSpecificData *tsdPtr;	/* Handle to thread local data that indicates +QueueEvent( +    ThreadSpecificData *tsdPtr,	/* Handle to thread local data that indicates  				 * which event queue to use. */ -    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. */ -    Tcl_QueuePosition position;	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, +    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. */ +    Tcl_QueuePosition position)	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,  				 * TCL_QUEUE_MARK. */  {      Tcl_MutexLock(&(tsdPtr->queueMutex)); @@ -435,12 +471,12 @@ QueueEvent(tsdPtr, evPtr, position)  	evPtr->nextPtr = tsdPtr->firstEventPtr;  	if (tsdPtr->firstEventPtr == NULL) {  	    tsdPtr->lastEventPtr = evPtr; -	}	     +	}  	tsdPtr->firstEventPtr = evPtr;      } else if (position == TCL_QUEUE_MARK) {  	/* -	 * Insert the event after the current marker event and advance -	 * the marker to the new event. +	 * Insert the event after the current marker event and advance the +	 * marker to the new event.  	 */  	if (tsdPtr->markerEventPtr == NULL) { @@ -463,10 +499,10 @@ QueueEvent(tsdPtr, evPtr, position)   *   * Tcl_DeleteEvents --   * - *	Calls a procedure for each event in the queue and deletes those - *	for which the procedure returns 1. Events for which the - *	procedure returns 0 are left in the queue.  Operates on the - *	queue associated with the current thread. + *	Calls a function for each event in the queue and deletes those for + *	which the function returns 1. Events for which the function returns 0 + *	are left in the queue. Operates on the queue associated with the + *	current thread.   *   * Results:   *	None. @@ -478,36 +514,64 @@ QueueEvent(tsdPtr, evPtr, position)   */  void -Tcl_DeleteEvents(proc, clientData) -    Tcl_EventDeleteProc *proc;		/* The procedure to call. */ -    ClientData clientData;    		/* type-specific data. */ +Tcl_DeleteEvents( +    Tcl_EventDeleteProc *proc,	/* The function to call. */ +    ClientData clientData)	/* The type-specific data. */  { -    Tcl_Event *evPtr, *prevPtr, *hold; +    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;      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      Tcl_MutexLock(&(tsdPtr->queueMutex)); -    for (prevPtr = (Tcl_Event *) NULL, evPtr = tsdPtr->firstEventPtr; -             evPtr != (Tcl_Event *) NULL; -             ) { -        if ((*proc) (evPtr, clientData) == 1) { -            if (tsdPtr->firstEventPtr == evPtr) { -                tsdPtr->firstEventPtr = evPtr->nextPtr; -                if (evPtr->nextPtr == (Tcl_Event *) NULL) { -                    tsdPtr->lastEventPtr = prevPtr; -                } -		if (tsdPtr->markerEventPtr == evPtr) { -		    tsdPtr->markerEventPtr = prevPtr; -		} -            } else { -                prevPtr->nextPtr = evPtr->nextPtr; -            } -            hold = evPtr; -            evPtr = evPtr->nextPtr; -            ckfree((char *) hold); -        } else { -            prevPtr = evPtr; -            evPtr = evPtr->nextPtr; -        } + +    /* +     * Walk the queue of events for the thread, applying 'proc' to each to +     * decide whether to eliminate the event. +     */ + +    prevPtr = NULL; +    evPtr = tsdPtr->firstEventPtr; +    while (evPtr != NULL) { +	if (proc(evPtr, clientData) == 1) { +	    /* +	     * This event should be deleted. Unlink it. +	     */ + +	    if (prevPtr == NULL) { +		tsdPtr->firstEventPtr = evPtr->nextPtr; +	    } else { +		prevPtr->nextPtr = evPtr->nextPtr; +	    } + +	    /* +	     * Update 'last' and 'marker' events if either has been deleted. +	     */ + +	    if (evPtr->nextPtr == NULL) { +		tsdPtr->lastEventPtr = prevPtr; +	    } +	    if (tsdPtr->markerEventPtr == evPtr) { +		tsdPtr->markerEventPtr = prevPtr; +	    } + +	    /* +	     * Delete the event data structure. +	     */ + +	    hold = evPtr; +	    evPtr = evPtr->nextPtr; +	    ckfree(hold); +	} else { +	    /* +	     * Event is to be retained. +	     */ + +	    prevPtr = evPtr; +	    evPtr = evPtr->nextPtr; +	}      }      Tcl_MutexUnlock(&(tsdPtr->queueMutex));  } @@ -517,30 +581,29 @@ Tcl_DeleteEvents(proc, clientData)   *   * Tcl_ServiceEvent --   * - *	Process one event from the event queue, or invoke an - *	asynchronous event handler.  Operates on event queue for - *	current thread. + *	Process one event from the event queue, or invoke an asynchronous + *	event handler. Operates on event queue for current thread.   *   * Results: - *	The return value is 1 if the procedure actually found an event - *	to process.  If no processing occurred, then 0 is returned. + *	The return value is 1 if the function actually found an event to + *	process. If no processing occurred, then 0 is returned.   *   * Side effects: - *	Invokes all of the event handlers for the highest priority - *	event in the event queue.  May collapse some events into a - *	single event or discard stale events. + *	Invokes all of the event handlers for the highest priority event in + *	the event queue. May collapse some events into a single event or + *	discard stale events.   *   *----------------------------------------------------------------------   */  int -Tcl_ServiceEvent(flags) -    int flags;			/* Indicates what events should be processed. +Tcl_ServiceEvent( +    int flags)			/* Indicates what events should be processed.  				 * May be any combination of TCL_WINDOW_EVENTS  				 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other -				 * flags defined elsewhere.  Events not -				 * matching this will be skipped for processing -				 * later. */ +				 * flags defined elsewhere. Events not +				 * matching this will be skipped for +				 * processing later. */  {      Tcl_Event *evPtr, *prevPtr;      Tcl_EventProc *proc; @@ -548,46 +611,46 @@ Tcl_ServiceEvent(flags)      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      /* -     * Asynchronous event handlers are considered to be the highest -     * priority events, and so must be invoked before we process events -     * on the event queue. +     * Asynchronous event handlers are considered to be the highest priority +     * events, and so must be invoked before we process events on the event +     * queue.       */ -     +      if (Tcl_AsyncReady()) { -	(void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); +	(void) Tcl_AsyncInvoke(NULL, 0);  	return 1;      }      /*       * No event flags is equivalent to TCL_ALL_EVENTS.       */ -     +      if ((flags & TCL_ALL_EVENTS) == 0) {  	flags |= TCL_ALL_EVENTS;      }      /* -     * Loop through all the events in the queue until we find one -     * that can actually be handled. +     * Loop through all the events in the queue until we find one that can +     * actually be handled.       */      Tcl_MutexLock(&(tsdPtr->queueMutex));      for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL; -	 evPtr = evPtr->nextPtr) { +	    evPtr = evPtr->nextPtr) {  	/* -	 * Call the handler for the event.  If it actually handles the -	 * event then free the storage for the event.  There are two -	 * tricky things here, both stemming from the fact that the event -	 * code may be re-entered while servicing the event: +	 * Call the handler for the event. If it actually handles the event +	 * then free the storage for the event. There are two tricky things +	 * here, both stemming from the fact that the event code may be +	 * re-entered while servicing the event:  	 *  	 * 1. Set the "proc" field to NULL.  This is a signal to ourselves -	 *    that we shouldn't reexecute the handler if the event loop -	 *    is re-entered. +	 *    that we shouldn't reexecute the handler if the event loop is +	 *    re-entered.  	 * 2. When freeing the event, must search the queue again from the -	 *    front to find it.  This is because the event queue could -	 *    change almost arbitrarily while handling the event, so we -	 *    can't depend on pointers found now still being valid when -	 *    the handler returns. +	 *    front to find it. This is because the event queue could change +	 *    almost arbitrarily while handling the event, so we can't depend +	 *    on pointers found now still being valid when the handler +	 *    returns.  	 */  	proc = evPtr->proc; @@ -597,14 +660,14 @@ Tcl_ServiceEvent(flags)  	evPtr->proc = NULL;  	/* -	 * Release the lock before calling the event procedure.  This -	 * allows other threads to post events if we enter a recursive -	 * event loop in this thread.  Note that we are making the assumption -	 * that if the proc returns 0, the event is still in the list. +	 * Release the lock before calling the event function. This allows +	 * other threads to post events if we enter a recursive event loop in +	 * this thread. Note that we are making the assumption that if the +	 * proc returns 0, the event is still in the list.  	 */  	Tcl_MutexUnlock(&(tsdPtr->queueMutex)); -	result = (*proc)(evPtr, flags); +	result = proc(evPtr, flags);  	Tcl_MutexLock(&(tsdPtr->queueMutex));  	if (result) { @@ -622,8 +685,8 @@ Tcl_ServiceEvent(flags)  		}  	    } else {  		for (prevPtr = tsdPtr->firstEventPtr; -		     prevPtr && prevPtr->nextPtr != evPtr; -		     prevPtr = prevPtr->nextPtr) { +			prevPtr && prevPtr->nextPtr != evPtr; +			prevPtr = prevPtr->nextPtr) {  		    /* Empty loop body. */  		}  		if (prevPtr) { @@ -639,14 +702,14 @@ Tcl_ServiceEvent(flags)  		}  	    }  	    if (evPtr) { -		ckfree((char *) evPtr); +		ckfree(evPtr);  	    }  	    Tcl_MutexUnlock(&(tsdPtr->queueMutex));  	    return 1;  	} else {  	    /* -	     * The event wasn't actually handled, so we have to restore -	     * the proc field to allow the event to be attempted again. +	     * The event wasn't actually handled, so we have to restore the +	     * proc field to allow the event to be attempted again.  	     */  	    evPtr->proc = proc; @@ -673,7 +736,7 @@ Tcl_ServiceEvent(flags)   */  int -Tcl_GetServiceMode() +Tcl_GetServiceMode(void)  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -691,14 +754,14 @@ Tcl_GetServiceMode()   *	Returns the previous service mode.   *   * Side effects: - *	Invokes the notifier service mode hook procedure. + *	Invokes the notifier service mode hook function.   *   *----------------------------------------------------------------------   */  int -Tcl_SetServiceMode(mode) -    int mode;			/* New service mode: TCL_SERVICE_ALL or +Tcl_SetServiceMode( +    int mode)			/* New service mode: TCL_SERVICE_ALL or  				 * TCL_SERVICE_NONE */  {      int oldMode; @@ -715,10 +778,10 @@ Tcl_SetServiceMode(mode)   *   * Tcl_SetMaxBlockTime --   * - *	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. + *	This function 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. @@ -730,10 +793,10 @@ Tcl_SetServiceMode(mode)   */  void -Tcl_SetMaxBlockTime(timePtr) -    Tcl_Time *timePtr;		/* Specifies a maximum elapsed time for -				 * the next blocking operation in the -				 * event tsdPtr-> */ +Tcl_SetMaxBlockTime( +    const Tcl_Time *timePtr)		/* Specifies a maximum elapsed time for the +				 * next blocking operation in the event +				 * tsdPtr-> */  {      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -745,16 +808,12 @@ Tcl_SetMaxBlockTime(timePtr)      }      /* -     * If we are called outside an event source traversal, set the -     * timeout immediately. +     * 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_SetTimer(&tsdPtr->blockTime);      }  } @@ -763,27 +822,27 @@ Tcl_SetMaxBlockTime(timePtr)   *   * 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. + *	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). + *	The return value is 1 if the function 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. + *	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.   *   *----------------------------------------------------------------------   */  int -Tcl_DoOneEvent(flags) -    int flags;			/* Miscellaneous flag values:  may be any +Tcl_DoOneEvent( +    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 @@ -795,47 +854,45 @@ Tcl_DoOneEvent(flags)      ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);      /* -     * The first thing we do is to service any asynchronous event -     * handlers. +     * The first thing we do is to service any asynchronous event handlers.       */ -     +      if (Tcl_AsyncReady()) { -	(void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); +	(void) Tcl_AsyncInvoke(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. +     * 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. +     * The core of this function 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 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; +	    flags = TCL_IDLE_EVENTS | TCL_DONT_WAIT;  	    goto idleEvents;  	} @@ -844,13 +901,13 @@ Tcl_DoOneEvent(flags)  	 */  	if (Tcl_ServiceEvent(flags)) { -	    result = 1;	     +	    result = 1;  	    break;  	}  	/* -	 * If TCL_DONT_WAIT is set, be sure to poll rather than -	 * blocking, otherwise reset the block time to infinity. +	 * 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) { @@ -862,15 +919,15 @@ Tcl_DoOneEvent(flags)  	}  	/* -	 * Set up all the event sources for new events.  This will -	 * cause the block time to be updated if necessary. +	 * 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) { +		sourcePtr = sourcePtr->nextPtr) {  	    if (sourcePtr->setupProc) { -		(sourcePtr->setupProc)(sourcePtr->clientData, flags); +		sourcePtr->setupProc(sourcePtr->clientData, flags);  	    }  	}  	tsdPtr->inTraversal = 0; @@ -882,8 +939,8 @@ Tcl_DoOneEvent(flags)  	}  	/* -	 * Wait for a new event or a timeout.  If Tcl_WaitForEvent -	 * returns -1, we should abort Tcl_DoOneEvent. +	 * Wait for a new event or a timeout. If Tcl_WaitForEvent returns -1, +	 * we should abort Tcl_DoOneEvent.  	 */  	result = Tcl_WaitForEvent(timePtr); @@ -897,9 +954,9 @@ Tcl_DoOneEvent(flags)  	 */  	for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL; -	     sourcePtr = sourcePtr->nextPtr) { +		sourcePtr = sourcePtr->nextPtr) {  	    if (sourcePtr->checkProc) { -		(sourcePtr->checkProc)(sourcePtr->clientData, flags); +		sourcePtr->checkProc(sourcePtr->clientData, flags);  	    }  	} @@ -913,12 +970,12 @@ Tcl_DoOneEvent(flags)  	}  	/* -	 * 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. +	 * 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: +    idleEvents:  	if (flags & TCL_IDLE_EVENTS) {  	    if (TclServiceIdle()) {  		result = 1; @@ -930,23 +987,21 @@ Tcl_DoOneEvent(flags)  	}  	/* -	 * 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). +	 * 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. +	 * 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; @@ -958,12 +1013,11 @@ Tcl_DoOneEvent(flags)   *   * 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. + *	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. @@ -975,7 +1029,7 @@ Tcl_DoOneEvent(flags)   */  int -Tcl_ServiceAll() +Tcl_ServiceAll(void)  {      int result = 0;      EventSource *sourcePtr; @@ -986,10 +1040,10 @@ Tcl_ServiceAll()      }      /* -     * We need to turn off event servicing like we to in Tcl_DoOneEvent, -     * to avoid recursive calls. +     * We need to turn off event servicing like we to in Tcl_DoOneEvent, to +     * avoid recursive calls.       */ -     +      tsdPtr->serviceMode = TCL_SERVICE_NONE;      /* @@ -997,28 +1051,28 @@ Tcl_ServiceAll()       */      if (Tcl_AsyncReady()) { -	(void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0); +	(void) Tcl_AsyncInvoke(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. +     * 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) { +	    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) { +	    sourcePtr = sourcePtr->nextPtr) {  	if (sourcePtr->checkProc) { -	    (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS); +	    sourcePtr->checkProc(sourcePtr->clientData, TCL_ALL_EVENTS);  	}      } @@ -1044,8 +1098,8 @@ Tcl_ServiceAll()   *   * Tcl_ThreadAlert --   * - *	This function wakes up the notifier associated with the - *	specified thread (if there is one).   + *	This function wakes up the notifier associated with the specified + *	thread (if there is one).   *   * Results:   *	None. @@ -1057,16 +1111,15 @@ Tcl_ServiceAll()   */  void -Tcl_ThreadAlert(threadId) -    Tcl_ThreadId threadId;	/* Identifier for thread to use. */ +Tcl_ThreadAlert( +    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. +     * 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); @@ -1078,3 +1131,11 @@ Tcl_ThreadAlert(threadId)      }      Tcl_MutexUnlock(&listLock);  } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ | 
