summaryrefslogtreecommitdiffstats
path: root/generic/tclTimer.c
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-03 13:24:36 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-03 13:24:36 (GMT)
commit5daa7f610ab6e2ea43bca023cb3cfe96811b48b4 (patch)
tree19638c59cf680b3130f5960f2b1bb2dd8928f39d /generic/tclTimer.c
parentee8dccacb4206a0ac43f8cb427b86775cedc4684 (diff)
downloadtcl-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.c122
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);
+}
/*
*----------------------------------------------------------------------