summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-03 13:31:40 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-03 13:31:40 (GMT)
commite7a4988c734f8a14028c271d4c6b147cbc6e635a (patch)
treececfcc6f624abc3f2b7fa9eeb046c17cbe8f6208 /generic
parent07b7b6eb37bb7ac079e3b55068fae7f96adbea4c (diff)
downloadtcl-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)
Diffstat (limited to 'generic')
-rw-r--r--generic/tclIO.c2
-rw-r--r--generic/tclNotify.c127
-rw-r--r--generic/tclTimer.c49
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 */
}
/*