diff options
author | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:31:40 (GMT) |
---|---|---|
committer | sebres <sebres@users.sourceforge.net> | 2017-07-03 13:31:40 (GMT) |
commit | e7a4988c734f8a14028c271d4c6b147cbc6e635a (patch) | |
tree | cecfcc6f624abc3f2b7fa9eeb046c17cbe8f6208 | |
parent | 07b7b6eb37bb7ac079e3b55068fae7f96adbea4c (diff) | |
download | tcl-e7a4988c734f8a14028c271d4c6b147cbc6e635a.zip tcl-e7a4988c734f8a14028c271d4c6b147cbc6e635a.tar.gz tcl-e7a4988c734f8a14028c271d4c6b147cbc6e635a.tar.bz2 |
interim commit: trying to pass test-cases - timer-3.*, chan-io-29.34, socket-2.12 (busy prompt timer, unexpected too early timer event, wrong timer-marker usage)
-rw-r--r-- | generic/tclIO.c | 2 | ||||
-rw-r--r-- | generic/tclNotify.c | 127 | ||||
-rw-r--r-- | generic/tclTimer.c | 49 |
3 files changed, 118 insertions, 60 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index e4bfd35..aa22698 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -8138,7 +8138,7 @@ ChannelTimerProc( * before UpdateInterest gets called by Tcl_NotifyChannel. */ - statePtr->timer = TclpProlongTimerEvent(statePtr->timer, 0, 0); + statePtr->timer = TclpProlongTimerEvent(statePtr->timer, 0, TCL_TMREV_PROMPT); if (!statePtr->timer) { statePtr->timer = TclpCreatePromptTimerEvent(ChannelTimerProc, FreeChannelTimerProc, 0, TCL_TMREV_PROMPT); diff --git a/generic/tclNotify.c b/generic/tclNotify.c index 01bf18f..c6978cb 100644 --- a/generic/tclNotify.c +++ b/generic/tclNotify.c @@ -32,6 +32,14 @@ typedef struct EventSource { } EventSource; /* + * Used for performance purposes, threshold to bypass check source (if don't wait) + * Values under 1000 should be approximately under 1ms, e. g. 5 is ca. 0.005ms + */ +#ifndef TCL_CHECK_EVENT_SOURCE_THRESHOLD + #define TCL_CHECK_EVENT_SOURCE_THRESHOLD 5 +#endif + +/* * 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 @@ -72,25 +80,20 @@ typedef struct ThreadSpecificData { /* Next notifier in global list of notifiers. * Access is controlled by the listLock global * mutex. */ -#ifndef TCL_WIDE_CLICKS /* Last "time" source checked, used as threshold */ +#if TCL_CHECK_EVENT_SOURCE_THRESHOLD + /* Last "time" source checked, used as threshold + * to avoid checking for events too often */ + #ifndef TCL_WIDE_CLICKS unsigned long lastCheckClicks; -#else + #else Tcl_WideInt lastCheckClicks; + #endif #endif } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* - * Used for performance purposes, threshold to bypass check source (if don't wait) - * Values under 1000 should be approximately under 1ms, e. g. 10 is ca. 0.01ms - */ -#ifndef CHECK_EVENT_SOURCE_THRESHOLD - #define CHECK_EVENT_SOURCE_THRESHOLD 10 -#endif - - -/* * 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. @@ -662,13 +665,17 @@ Tcl_ServiceEvent( /* * If timer marker reached, process timer events now. */ - if ( (flags & TCL_TIMER_EVENTS) /* timer allowed */ - && ( tsdPtr->timerMarkerPtr == INT2PTR(-1) /* timer-event reached */ - || !tsdPtr->firstEventPtr /* no another events at all */ - || ((flags & TCL_ALL_EVENTS) == TCL_TIMER_EVENTS) /* timers only */ - ) - ) { - goto timer; + if (flags & TCL_TIMER_EVENTS) { /* timer allowed */ + if (tsdPtr->timerMarkerPtr == INT2PTR(-1)) { /* timer-event reached */ + goto processTimer; + } +#if 0 + if ( !tsdPtr->firstEventPtr /* no another events at all */ + || ((flags & TCL_ALL_EVENTS) == TCL_TIMER_EVENTS) /* timers only */ + ) { + goto timer; + } +#endif } /* @@ -681,13 +688,6 @@ Tcl_ServiceEvent( evPtr = evPtr->nextPtr) { /* - * If timer marker reached, next cycle will process timer events. - */ - if (evPtr == tsdPtr->timerMarkerPtr) { - tsdPtr->timerMarkerPtr = INT2PTR(-1); - } - - /* * 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 @@ -725,6 +725,9 @@ Tcl_ServiceEvent( * The event was processed, so remove it from the queue. */ + if (tsdPtr->timerMarkerPtr == evPtr) { + tsdPtr->timerMarkerPtr = INT2PTR(-1); /* timer marker reached */ + } if (tsdPtr->firstEventPtr == evPtr) { tsdPtr->firstEventPtr = evPtr->nextPtr; if (evPtr->nextPtr == NULL) { @@ -773,8 +776,36 @@ Tcl_ServiceEvent( if (flags & TCL_TIMER_EVENTS) { timer: +#if 1 /* If available pending timer-events of new generation */ if (tsdPtr->timerMarkerPtr == INT2PTR(-2)) { + /* no other events - process timer-events (next cycle) */ + if (!tsdPtr->lastEventPtr) { /* no other events */ + goto processTimer; + } else { + tsdPtr->timerMarkerPtr = tsdPtr->lastEventPtr; + } + return 0; + } +#else +#if 1 + /* If available pending timer-events of new generation */ + if ( tsdPtr->timerMarkerPtr == INT2PTR(-2) + || !tsdPtr->firstEventPtr /* no other events */ + ) { + /* no other events - process timer-events (next cycle) */ + if (tsdPtr->timerMarkerPtr == INT2PTR(-2)) { + tsdPtr->timerMarkerPtr = INT2PTR(-1); + } else { + tsdPtr->timerMarkerPtr = INT2PTR(-2); + } + return 0; + } +#else + /* If available pending timer-events of new generation */ + if ( tsdPtr->timerMarkerPtr == INT2PTR(-2) + || !tsdPtr->lastEventPtr + ) { /* if other events available */ if ((tsdPtr->timerMarkerPtr = tsdPtr->lastEventPtr)) { /* process timer-events after it (next cycle) */ @@ -783,7 +814,8 @@ timer: /* no other events - process timer-events now */ goto processTimer; } - +#endif +#endif if (tsdPtr->timerMarkerPtr == INT2PTR(-1)) { processTimer: @@ -850,23 +882,31 @@ TclPeekEventQueued( */ if ( Tcl_AsyncReady() || (tsdPtr->firstEventPtr) - || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerMarkerPtr) + || ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerMarkerPtr == INT2PTR(-1)) ) { return 1; } + /* once from here */ + if (!repeat) { + break; + } + if (flags & TCL_DONT_WAIT) { + #if TCL_CHECK_EVENT_SOURCE_THRESHOLD /* don't need to wait/check for events too often */ -#ifndef TCL_WIDE_CLICKS - unsigned long clicks = TclpGetClicks(); -#else - Tcl_WideInt clicks = TclpGetWideClicks(); -#endif - - if ((clicks - tsdPtr->lastCheckClicks) <= CHECK_EVENT_SOURCE_THRESHOLD) { + #ifndef TCL_WIDE_CLICKS + unsigned long clickdiff, clicks = TclpGetClicks(); + #else + Tcl_WideInt clickdiff, clicks = TclpGetWideClicks(); + #endif + /* considering possible clicks-jump */ + if ( (clickdiff = (clicks - tsdPtr->lastCheckClicks)) >= 0 + && clickdiff <= TCL_CHECK_EVENT_SOURCE_THRESHOLD) { return 0; } tsdPtr->lastCheckClicks = clicks; + #endif } /* @@ -907,7 +947,7 @@ TclSetTimerEventMarker( { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (tsdPtr->timerMarkerPtr == NULL) { + if (tsdPtr->timerMarkerPtr == NULL || tsdPtr->timerMarkerPtr == INT2PTR(-2)) { /* marker to last event in the queue */ if (head || !(tsdPtr->timerMarkerPtr = tsdPtr->lastEventPtr)) { /* @@ -1133,16 +1173,21 @@ Tcl_DoOneEvent( */ if (flags & TCL_DONT_WAIT) { + /* don't need to wait/check for events too often */ -#ifndef TCL_WIDE_CLICKS - unsigned long clicks = TclpGetClicks(); -#else - Tcl_WideInt clicks = TclpGetWideClicks(); -#endif - if ((clicks - tsdPtr->lastCheckClicks) <= CHECK_EVENT_SOURCE_THRESHOLD) { + #if TCL_CHECK_EVENT_SOURCE_THRESHOLD + #ifndef TCL_WIDE_CLICKS + unsigned long clickdiff, clicks = TclpGetClicks(); + #else + Tcl_WideInt clickdiff, clicks = TclpGetWideClicks(); + #endif + /* considering possible clicks-jump */ + if ( (clickdiff = (clicks - tsdPtr->lastCheckClicks)) >= 0 + && clickdiff <= TCL_CHECK_EVENT_SOURCE_THRESHOLD) { goto idleEvents; } tsdPtr->lastCheckClicks = clicks; + #endif tsdPtr->blockTime.sec = 0; tsdPtr->blockTime.usec = 0; diff --git a/generic/tclTimer.c b/generic/tclTimer.c index e6b0799..bb13c39 100644 --- a/generic/tclTimer.c +++ b/generic/tclTimer.c @@ -270,7 +270,7 @@ AttachTimerEvent( /* attach to the prompt queue */ TclSpliceTailEx(tmrEvent, tsdPtr->promptList, tsdPtr->promptTail); /* execute immediately: signal pending and set timer marker */ - tsdPtr->timerPending++; + tsdPtr->timerPending = 1; TclSetTimerEventMarker(0); return; } @@ -918,10 +918,11 @@ TimerSetupProc( { Tcl_Time blockTime; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data; + Tcl_WideInt entryTime = 0; if (tsdPtr == NULL) { tsdPtr = InitTimer(); }; - if ( ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending) + if ( ((flags & TCL_TIMER_EVENTS) && (tsdPtr->timerPending || tsdPtr->promptList)) || ((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList ) ) { /* @@ -940,7 +941,7 @@ TimerSetupProc( */ Tcl_WideInt now = TclpGetMicroseconds(); - Tcl_WideInt entryTime = 0x7FFFFFFFFFFFFFFFL; + entryTime = 0x7FFFFFFFFFFFFFFFL; if (tsdPtr->relTimerList) { entryTime = TimerGetDueTime(tsdPtr, @@ -968,18 +969,18 @@ TimerSetupProc( blockTime.usec = 0; } - /* - * If the first timer has expired, stick an event on the queue right now. - */ - if (!tsdPtr->timerPending && entryTime <= 0) { - TclSetTimerEventMarker(0); - tsdPtr->timerPending = 1; - } - } else { return; } + /* + * If the first timer has expired, stick an event on the queue right now. + */ + if (!tsdPtr->timerPending && entryTime <= 0) { + TclSetTimerEventMarker(0); + tsdPtr->timerPending = 1; + } + Tcl_SetMaxBlockTime(&blockTime); } @@ -1005,7 +1006,7 @@ TimerCheckProc( ClientData data, /* Specific data. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { - Tcl_WideInt now, entryTime = 0x7FFFFFFFFFFFFFFFL; + Tcl_WideInt now, entryTime = 0; ThreadSpecificData *tsdPtr = (ThreadSpecificData *)data; if (!(flags & TCL_TIMER_EVENTS)) { @@ -1015,13 +1016,20 @@ TimerCheckProc( if (tsdPtr == NULL) { tsdPtr = InitTimer(); }; /* If already pending (or no timer-events) */ - if (tsdPtr->timerPending || !tsdPtr->relTimerList) { - return; + if (tsdPtr->timerPending) { + return; + } + if (tsdPtr->promptList) { + goto mark; + } + if (!tsdPtr->relTimerList && !tsdPtr->absTimerList) { + return; } /* * Verify the first timer on the queue. */ + entryTime = 0x7FFFFFFFFFFFFFFFL; now = TclpGetMicroseconds(); if (tsdPtr->relTimerList) { entryTime = TimerGetDueTime(tsdPtr, @@ -1043,7 +1051,8 @@ TimerCheckProc( /* * If the first timer has expired, stick an event on the queue. */ - if (entryTime <= 0) { + if (!tsdPtr->timerPending && entryTime <= 0) { + mark: TclSetTimerEventMarker(0); tsdPtr->timerPending = 1; } @@ -1076,6 +1085,7 @@ TclServiceTimerEvents(void) { TclTimerEvent *tmrEvent, *relTimerList, *absTimerList; size_t currentGeneration, currentEpoch; + int result = 0; int prevTmrPending; ThreadSpecificData *tsdPtr = InitTimer(); @@ -1107,6 +1117,7 @@ TclServiceTimerEvents(void) */ currentGeneration = tsdPtr->timerGeneration++; + tsdPtr->timerPending = 0; /* First process all prompt (immediate) events */ while ((tmrEvent = tsdPtr->promptList) != NULL @@ -1121,6 +1132,7 @@ TclServiceTimerEvents(void) tsdPtr->timerPending = 0; /* execute event */ (*tmrEvent->proc)(tmrEvent->clientData); + result = 1; /* restore current timer pending */ tsdPtr->timerPending += prevTmrPending; /* unfreeze / if used somewhere else (nested) or prolongation (reattached) */ @@ -1207,6 +1219,7 @@ TclServiceTimerEvents(void) tsdPtr->timerPending = 0; /* invoke timer proc */ (*tmrEvent->proc)(tmrEvent->clientData); + result = 1; /* restore current timer pending */ tsdPtr->timerPending += prevTmrPending; /* unfreeze / if used somewhere else (nested) or prolongation (reattached) */ @@ -1230,20 +1243,20 @@ TclServiceTimerEvents(void) } /* pending timer events, so mark (queue) timer events */ - if (tsdPtr->timerPending > 1) { + if (tsdPtr->timerPending >= 1) { tsdPtr->timerPending = 1; return -1; } /* Reset generation if both timer queue are empty */ - if (!tsdPtr->relTimerList && !tsdPtr->absTimerList) { + if (!tsdPtr->promptList && !tsdPtr->relTimerList && !tsdPtr->absTimerList) { tsdPtr->timerGeneration = 0; } /* Compute the next timeout (later via TimerSetupProc using the first timer). */ tsdPtr->timerPending = 0; - return 1; /* processing done, again later via TimerCheckProc */ + return result; /* processing done, again later via TimerCheckProc */ } /* |