diff options
author | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:24:36 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:24:36 (GMT) |
commit | 5daa7f610ab6e2ea43bca023cb3cfe96811b48b4 (patch) | |
tree | 19638c59cf680b3130f5960f2b1bb2dd8928f39d /generic/tclTimer.c | |
parent | ee8dccacb4206a0ac43f8cb427b86775cedc4684 (diff) | |
download | tcl-5daa7f610ab6e2ea43bca023cb3cfe96811b48b4.zip tcl-5daa7f610ab6e2ea43bca023cb3cfe96811b48b4.tar.gz tcl-5daa7f610ab6e2ea43bca023cb3cfe96811b48b4.tar.bz2 |
[performance] do one event (update / event servicing) cycle optimized (introduced threshold to prevent sourcing resp. waiting for new events by no-wait).
[enhancement] new event type introduced: TCL_ASYNC_EVENTS, command "update" becomes options to process only specified types, resp. to bypass some event types (including -idle/-noidle that in opposite to "idletasks" does not included window events);
test cases extended.
Diffstat (limited to 'generic/tclTimer.c')
-rw-r--r-- | generic/tclTimer.c | 122 |
1 files changed, 99 insertions, 23 deletions
diff --git a/generic/tclTimer.c b/generic/tclTimer.c index 12b039f..52a3073 100644 --- a/generic/tclTimer.c +++ b/generic/tclTimer.c @@ -121,6 +121,7 @@ static void FreeAfterPtr(ClientData clientData); static AfterInfo * GetAfterEvent(AfterAssocData *assocPtr, Tcl_Obj *objPtr); static ThreadSpecificData *InitTimer(void); static void TimerExitProc(ClientData clientData); +static void TimerCheckProc(ClientData clientData, int flags); static void TimerSetupProc(ClientData clientData, int flags); static void AfterObj_DupInternalRep(Tcl_Obj *, Tcl_Obj *); @@ -258,7 +259,7 @@ InitTimer(void) if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); - Tcl_CreateEventSource(TimerSetupProc, NULL, tsdPtr); + Tcl_CreateEventSource(TimerSetupProc, TimerCheckProc, tsdPtr); Tcl_CreateThreadExitHandler(TimerExitProc, NULL); } return tsdPtr; @@ -289,7 +290,7 @@ TimerExitProc( TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { - Tcl_DeleteEventSource(TimerSetupProc, NULL, tsdPtr); + Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, tsdPtr); while ((tsdPtr->lastPromptPtr) != NULL) { TclDeleteTimerEntry(tsdPtr->lastPromptPtr); @@ -582,7 +583,7 @@ TclDeleteTimerEntry( static void TimerSetupProc( - ClientData data, /* Not used. */ + ClientData data, /* Specific data. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { Tcl_Time blockTime, *firstTime; @@ -590,10 +591,11 @@ TimerSetupProc( if (tsdPtr == NULL) { tsdPtr = InitTimer(); }; - if (((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList ) - || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending)) { + if ( ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending) + || ((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList ) + ) { /* - * There is an idle handler or a pending timer event, so just poll. + * There is a pending timer event or an idle handler, so just poll. */ blockTime.sec = 0; @@ -616,11 +618,10 @@ TimerSetupProc( blockTime.sec = 0; blockTime.usec = 0; } - + /* - * If the first timer has expired, stick an event on the queue. - */ - + * If the first timer has expired, stick an event on the queue right now. + */ if (!tsdPtr->timerPending && blockTime.sec == 0 && blockTime.usec == 0) { TclSetTimerEventMarker(); tsdPtr->timerPending = 1; @@ -636,6 +637,67 @@ TimerSetupProc( /* *---------------------------------------------------------------------- * + * TimerCheckProc -- + * + * This function is called by Tcl_DoOneEvent to check the timer event + * source for events. This routine checks the first timer in the list. + * + * Results: + * None. + * + * Side effects: + * May queue an event and update the maximum notifier block time. + * + *---------------------------------------------------------------------- + */ + +static void +TimerCheckProc( + ClientData data, /* Specific data. */ + int flags) /* Event flags as passed to Tcl_DoOneEvent. */ +{ + Tcl_Time blockTime, *firstTime; + ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data; + + if (!(flags & TCL_TIMER_EVENTS)) { + return; + } + + if (tsdPtr == NULL) { tsdPtr = InitTimer(); }; + + /* If already pending */ + if (!tsdPtr->timerList || tsdPtr->timerPending) { + return; + } + + /* + * Verify the first timer on the queue. + */ + Tcl_GetTime(&blockTime); + firstTime = &(TimerEntry2TimerHandler(tsdPtr->timerList)->time); + blockTime.sec = firstTime->sec - blockTime.sec; + blockTime.usec = firstTime->usec - blockTime.usec; + if (blockTime.usec < 0) { + blockTime.sec -= 1; + blockTime.usec += 1000000; + } + if (blockTime.sec < 0) { + blockTime.sec = 0; + blockTime.usec = 0; + } + + /* + * If the first timer has expired, stick an event on the queue. + */ + if (blockTime.sec == 0 && blockTime.usec == 0) { + TclSetTimerEventMarker(); + tsdPtr->timerPending = 1; + } +} + +/* + *---------------------------------------------------------------------- + * * TclServiceTimerEvents -- * * This function is called by Tcl_ServiceEvent when a timer events should @@ -785,7 +847,7 @@ done: /* Compute the next timeout (later via TimerSetupProc using the first timer). */ tsdPtr->timerPending = 0; - return 1; /* processing done, again later via TimerSetupProc */ + return 1; /* processing done, again later via TimerCheckProc */ } /* @@ -928,7 +990,7 @@ Tcl_CancelIdleCall( /* *---------------------------------------------------------------------- * - * TclServiceIdle -- + * TclServiceIdle -- , TclServiceIdleEx -- * * This function is invoked by the notifier when it becomes idle. It will * invoke all idle handlers that are present at the time the call is @@ -945,14 +1007,15 @@ Tcl_CancelIdleCall( */ int -TclServiceIdle(void) +TclServiceIdleEx( + int flags, + int count) { TimerEntry *idlePtr; size_t currentGeneration; - Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); - if (tsdPtr->idleList == NULL) { + if ((idlePtr = tsdPtr->idleList) == NULL) { return 0; } @@ -975,9 +1038,7 @@ TclServiceIdle(void) * during the call. */ - while ((idlePtr = tsdPtr->idleList) != NULL - && idlePtr->generation <= currentGeneration - ) { + while (idlePtr->generation <= currentGeneration) { /* detach entry from the owner's list */ TclSpliceOutEx(idlePtr, tsdPtr->idleList, tsdPtr->lastIdlePtr); @@ -989,18 +1050,33 @@ TclServiceIdle(void) (*idlePtr->deleteProc)(idlePtr->clientData); } ckfree((char *) idlePtr); + + /* + * Stop processing idle if idle queue empty, count reached or other + * events queued (only if not idle events only to service). + */ + + if ( (idlePtr = tsdPtr->idleList) == NULL + || !--count + || ((flags & TCL_ALL_EVENTS) != TCL_IDLE_EVENTS + && TclPeekEventQueued(flags)) + ) { + break; + } } - if (tsdPtr->idleList) { - blockTime.sec = 0; - blockTime.usec = 0; - Tcl_SetMaxBlockTime(&blockTime); - } + /* Reset generation */ if (!tsdPtr->idleList) { tsdPtr->idleGeneration = 0; } return 1; } + +int +TclServiceIdle(void) +{ + return TclServiceIdleEx(TCL_ALL_EVENTS, INT_MAX); +} /* *---------------------------------------------------------------------- |