summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-03 13:24:04 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-03 13:24:04 (GMT)
commit8a1d9a3be57af976d24c218db14975378927f125 (patch)
treef5ba35170e5f2a3ee16e5b126a174c35b114ac52
parentdf949554f991f8fb4a399bdd248437012deebe40 (diff)
downloadtcl-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.c16
-rw-r--r--generic/tclInt.h1
-rw-r--r--generic/tclNotify.c54
-rw-r--r--generic/tclTimer.c118
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);
-}
/*
*----------------------------------------------------------------------