diff options
author | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:24:04 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:24:04 (GMT) |
commit | 8a1d9a3be57af976d24c218db14975378927f125 (patch) | |
tree | f5ba35170e5f2a3ee16e5b126a174c35b114ac52 | |
parent | df949554f991f8fb4a399bdd248437012deebe40 (diff) | |
download | tcl-8a1d9a3be57af976d24c218db14975378927f125.zip tcl-8a1d9a3be57af976d24c218db14975378927f125.tar.gz tcl-8a1d9a3be57af976d24c218db14975378927f125.tar.bz2 |
[performance] much better handling for timer events within Tcl_ServiceEvent using timer marker in the queue and direct call of TclServiceTimerEvents if marker reached (instead of continuous adding handler event, polling it in the queue and removing hereafter);
this provides double performance increase in the service cycle;
-rw-r--r-- | generic/tclIndexObj.c | 16 | ||||
-rw-r--r-- | generic/tclInt.h | 1 | ||||
-rw-r--r-- | generic/tclNotify.c | 54 | ||||
-rw-r--r-- | generic/tclTimer.c | 118 |
4 files changed, 51 insertions, 138 deletions
diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 73ba515..ced7bd9 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -27,7 +27,7 @@ static void FreeIndex(Tcl_Obj *objPtr); * that can be invoked by generic object code. */ -static Tcl_ObjType indexType = { +Tcl_ObjType tclIndexType = { "index", /* name */ FreeIndex, /* freeIntRepProc */ DupIndex, /* dupIntRepProc */ @@ -105,7 +105,7 @@ Tcl_GetIndexFromObj( * the common case where the result is cached). */ - if (objPtr->typePtr == &indexType) { + if (objPtr->typePtr == &tclIndexType) { IndexRep *indexRep = objPtr->internalRep.twoPtrValue.ptr1; /* @@ -179,7 +179,7 @@ Tcl_GetIndexFromObjStruct( * See if there is a valid cached result from a previous lookup. */ - if (objPtr->typePtr == &indexType) { + if (objPtr->typePtr == &tclIndexType) { indexRep = objPtr->internalRep.twoPtrValue.ptr1; if (indexRep->tablePtr==tablePtr && indexRep->offset==offset) { *indexPtr = indexRep->index; @@ -240,13 +240,13 @@ Tcl_GetIndexFromObjStruct( * operation. */ - if (objPtr->typePtr == &indexType) { + if (objPtr->typePtr == &tclIndexType) { indexRep = objPtr->internalRep.twoPtrValue.ptr1; } else { TclFreeIntRep(objPtr); indexRep = (IndexRep *) ckalloc(sizeof(IndexRep)); objPtr->internalRep.twoPtrValue.ptr1 = indexRep; - objPtr->typePtr = &indexType; + objPtr->typePtr = &tclIndexType; } indexRep->tablePtr = (void *) tablePtr; indexRep->offset = offset; @@ -382,7 +382,7 @@ DupIndex( memcpy(dupIndexRep, srcIndexRep, sizeof(IndexRep)); dupPtr->internalRep.twoPtrValue.ptr1 = dupIndexRep; - dupPtr->typePtr = &indexType; + dupPtr->typePtr = &tclIndexType; } /* @@ -532,7 +532,7 @@ Tcl_WrongNumArgs( * Add the element, quoting it if necessary. */ - if (origObjv[i]->typePtr == &indexType) { + if (origObjv[i]->typePtr == &tclIndexType) { register IndexRep *indexRep = origObjv[i]->internalRep.twoPtrValue.ptr1; @@ -588,7 +588,7 @@ Tcl_WrongNumArgs( * Otherwise, just use the string rep. */ - if (objv[i]->typePtr == &indexType) { + if (objv[i]->typePtr == &tclIndexType) { register IndexRep *indexRep = objv[i]->internalRep.twoPtrValue.ptr1; Tcl_AppendStringsToObj(objPtr, EXPAND_OF(indexRep), NULL); diff --git a/generic/tclInt.h b/generic/tclInt.h index 4151f83..d0d1240 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2933,7 +2933,6 @@ MODULE_SCOPE TimerEntry* TclCreateTimerEntryEx( Tcl_TimerProc *proc, Tcl_TimerDeleteProc *deleteProc, size_t extraDataSize, int flags); MODULE_SCOPE void TclDeleteTimerEntry(TimerEntry *entryPtr); -MODULE_SCOPE int TclPeekEventQueued(int flags); MODULE_SCOPE int TclDefaultBgErrorHandlerObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); diff --git a/generic/tclNotify.c b/generic/tclNotify.c index e883071..89182ea 100644 --- a/generic/tclNotify.c +++ b/generic/tclNotify.c @@ -639,7 +639,7 @@ Tcl_ServiceEvent( /* * If timer marker reached, process timer events now. */ - if (tsdPtr->timerMarkerPtr == INT2PTR(-1) || !tsdPtr->firstEventPtr) { + if (tsdPtr->timerMarkerPtr == INT2PTR(-1)) { goto timer; } @@ -743,7 +743,7 @@ timer: /* * Process timer queue, if alloved and timers are enabled. */ - if ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerMarkerPtr) { + if (flags & TCL_TIMER_EVENTS && tsdPtr->timerMarkerPtr) { /* reset marker */ tsdPtr->timerMarkerPtr = NULL; @@ -762,36 +762,6 @@ timer: /* *---------------------------------------------------------------------- * - * TclPeekEventQueued -- - * - * Check whether some event (except idle) available (async, queued, timer). - * - * This will be used e. g. in TclServiceIdle to stop the processing of the - * the idle events if some "normal" event occurred. - * - * Results: - * Returns 1 if some event queued, 0 otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TclPeekEventQueued( - int flags) -{ - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - - return Tcl_AsyncReady() - || (tsdPtr->firstEventPtr) - || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerMarkerPtr); -} - -/* - *---------------------------------------------------------------------- - * * TclSetTimerEventMarker -- * * Set timer event marker to the last pending event in the queue. @@ -950,12 +920,21 @@ Tcl_DoOneEvent( * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or * others defined by event sources. */ { - int result = 0, oldMode, i = 0; + 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(NULL, 0); + return 1; + } + + /* * No event flags is equivalent to TCL_ALL_EVENTS. */ @@ -990,8 +969,7 @@ Tcl_DoOneEvent( } /* - * Ask Tcl to service any asynchronous event handlers or - * queued event, if there are any. + * Ask Tcl to service a queued event, if there are any. */ if (Tcl_ServiceEvent(flags)) { @@ -1008,8 +986,6 @@ Tcl_DoOneEvent( tsdPtr->blockTime.sec = 0; tsdPtr->blockTime.usec = 0; tsdPtr->blockTimeSet = 1; - timePtr = &tsdPtr->blockTime; - goto wait; /* for notifier resp. system events */ } else { tsdPtr->blockTimeSet = 0; } @@ -1028,7 +1004,7 @@ Tcl_DoOneEvent( } tsdPtr->inTraversal = 0; - if (tsdPtr->blockTimeSet) { + if ((flags & TCL_DONT_WAIT) || tsdPtr->blockTimeSet) { timePtr = &tsdPtr->blockTime; } else { timePtr = NULL; @@ -1038,7 +1014,7 @@ Tcl_DoOneEvent( * Wait for a new event or a timeout. If Tcl_WaitForEvent returns -1, * we should abort Tcl_DoOneEvent. */ - wait: + result = Tcl_WaitForEvent(timePtr); if (result < 0) { result = 0; diff --git a/generic/tclTimer.c b/generic/tclTimer.c index d3aa5aa..12b039f 100644 --- a/generic/tclTimer.c +++ b/generic/tclTimer.c @@ -121,7 +121,6 @@ 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 *); @@ -259,7 +258,7 @@ InitTimer(void) if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); - Tcl_CreateEventSource(TimerSetupProc, TimerCheckProc, tsdPtr); + Tcl_CreateEventSource(TimerSetupProc, NULL, tsdPtr); Tcl_CreateThreadExitHandler(TimerExitProc, NULL); } return tsdPtr; @@ -290,7 +289,7 @@ TimerExitProc( TclThreadDataKeyGet(&dataKey); if (tsdPtr != NULL) { - Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, tsdPtr); + Tcl_DeleteEventSource(TimerSetupProc, NULL, tsdPtr); while ((tsdPtr->lastPromptPtr) != NULL) { TclDeleteTimerEntry(tsdPtr->lastPromptPtr); @@ -583,7 +582,7 @@ TclDeleteTimerEntry( static void TimerSetupProc( - ClientData data, /* Specific data. */ + ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { Tcl_Time blockTime, *firstTime; @@ -591,11 +590,10 @@ TimerSetupProc( if (tsdPtr == NULL) { tsdPtr = InitTimer(); }; - if ( ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending) - || ((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList ) - ) { + if (((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList ) + || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending)) { /* - * There is a pending timer event or an idle handler, so just poll. + * There is an idle handler or a pending timer event, so just poll. */ blockTime.sec = 0; @@ -618,6 +616,15 @@ TimerSetupProc( blockTime.sec = 0; blockTime.usec = 0; } + + /* + * If the first timer has expired, stick an event on the queue. + */ + + if (!tsdPtr->timerPending && blockTime.sec == 0 && blockTime.usec == 0) { + TclSetTimerEventMarker(); + tsdPtr->timerPending = 1; + } } else { return; @@ -629,67 +636,6 @@ 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 @@ -839,7 +785,7 @@ done: /* Compute the next timeout (later via TimerSetupProc using the first timer). */ tsdPtr->timerPending = 0; - return 1; /* processing done, again later via TimerCheckProc */ + return 1; /* processing done, again later via TimerSetupProc */ } /* @@ -982,7 +928,7 @@ Tcl_CancelIdleCall( /* *---------------------------------------------------------------------- * - * TclServiceIdle -- , TclServiceIdleEx -- + * TclServiceIdle -- * * 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 @@ -999,14 +945,14 @@ Tcl_CancelIdleCall( */ int -TclServiceIdleEx( - int count) +TclServiceIdle(void) { TimerEntry *idlePtr; size_t currentGeneration; + Tcl_Time blockTime; ThreadSpecificData *tsdPtr = InitTimer(); - if ((idlePtr = tsdPtr->idleList) == NULL) { + if (tsdPtr->idleList == NULL) { return 0; } @@ -1029,7 +975,9 @@ TclServiceIdleEx( * during the call. */ - while (idlePtr->generation <= currentGeneration) { + while ((idlePtr = tsdPtr->idleList) != NULL + && idlePtr->generation <= currentGeneration + ) { /* detach entry from the owner's list */ TclSpliceOutEx(idlePtr, tsdPtr->idleList, tsdPtr->lastIdlePtr); @@ -1041,28 +989,18 @@ TclServiceIdleEx( (*idlePtr->deleteProc)(idlePtr->clientData); } ckfree((char *) idlePtr); - - /* stop processing idle if no more idle, count reached or other queued */ - if ( (idlePtr = tsdPtr->idleList) == NULL - || !--count - || TclPeekEventQueued(TCL_ALL_EVENTS) - ) { - 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(INT_MAX); -} /* *---------------------------------------------------------------------- |