summaryrefslogtreecommitdiffstats
path: root/win/tclWinNotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinNotify.c')
-rw-r--r--win/tclWinNotify.c212
1 files changed, 99 insertions, 113 deletions
diff --git a/win/tclWinNotify.c b/win/tclWinNotify.c
index d22373e..bd3b384 100644
--- a/win/tclWinNotify.c
+++ b/win/tclWinNotify.c
@@ -631,12 +631,13 @@ Tcl_WaitForEvent(
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
MSG msg;
- DWORD timeout, result = WAIT_TIMEOUT;
+ DWORD timeout = INFINITE, result = WAIT_TIMEOUT;
int status = 0;
- Tcl_Time waitTime = {0, 0};
- Tcl_Time lastNow, endTime;
+ Tcl_WideInt waitTime = 0;
+ Tcl_WideInt lastNow = 0, endTime = 0;
long tolerance = 0;
unsigned long actualResolution = 0;
+ size_t timeJumpEpoch = 0;
/*
* Allow the notifier to be hooked. This may not make sense on windows,
@@ -653,47 +654,44 @@ Tcl_WaitForEvent(
if (timePtr) {
- waitTime.sec = timePtr->sec;
- waitTime.usec = timePtr->usec;
+ waitTime = timePtr->sec * 1000000 + timePtr->usec;
/* if no wait */
- if (waitTime.sec <= 0 && waitTime.usec <= 0) {
+ if (waitTime <= 0) {
result = 0;
goto peek;
}
- #ifdef TMR_RES_TOLERANCE
- /* calculate possible maximal tolerance (in usec) of original wait-time */
- tolerance = ((waitTime.sec <= 0) ? waitTime.usec : 1000000) *
- (TMR_RES_TOLERANCE / 100);
- #endif
-
/* calculate end of wait */
- Tcl_GetTime(&endTime);
- lastNow = endTime;
- endTime.sec += waitTime.sec;
- endTime.usec += waitTime.usec;
- if (endTime.usec > 1000000) {
- endTime.usec -= 1000000;
- endTime.sec++;
- }
+ lastNow = TclpGetMicroseconds();
+ endTime = lastNow + waitTime;
+ timeJumpEpoch = TclpGetLastTimeJumpEpoch();
if (timerResolution.available == -1) {
InitTimerResolution();
}
+ #ifdef TMR_RES_TOLERANCE
+ /* calculate possible maximal tolerance (in usec) of original wait-time */
+ tolerance = ((waitTime <= 1000000) ? waitTime : 1000000) *
+ TMR_RES_TOLERANCE / 100;
+ if (tolerance > timerResolution.maxDelay) {
+ tolerance = timerResolution.maxDelay;
+ }
+ #endif
+
repeat:
/*
* TIP #233 (Virtualized Time). Convert virtual domain delay to
* real-time.
*/
- (*tclScaleTimeProcPtr) (&waitTime, tclTimeClientData);
+ waitTime = TclpScaleUTime(waitTime);
/* No wait if timeout too small (because windows may wait too long) */
- if (!waitTime.sec && waitTime.usec < (long)timerResolution.minDelay) {
+ if (waitTime < (long)timerResolution.minDelay) {
+ timeout = 0;
/* prevent busy wait */
- if (waitTime.usec >= 10) {
- timeout = 0;
+ if (waitTime >= 10) {
goto wait;
}
Sleep(0);
@@ -701,25 +699,23 @@ Tcl_WaitForEvent(
}
if (timerResolution.available) {
- if (waitTime.sec || waitTime.usec + tolerance > timerResolution.maxDelay) {
- long usec;
- timeout = waitTime.sec * 1000;
- usec = (timeout * 1000) + waitTime.usec + tolerance;
- if (usec > 1000000) {
- usec -= 1000000;
- timeout += 1000;
- }
- timeout += (usec - (usec % timerResolution.maxDelay)) / 1000;
+ long overhead = (tolerance < 100 ? tolerance/2 : 50);
+ Tcl_WideInt waitTimeWithOverhead = waitTime + overhead;
+ if (waitTimeWithOverhead > timerResolution.maxDelay) {
+ /* floor (truncate) using max delay as base (follow timeout better) */
+ timeout = (waitTimeWithOverhead
+ / timerResolution.maxDelay)
+ * timerResolution.maxDelay / 1000;
} else {
/* calculate resolution up to 1000 microseconds
* (don't use highest, because of too large CPU load) */
ULONG res;
- if (waitTime.usec >= 10000) {
+ if (waitTimeWithOverhead >= 10000) {
res = 10000 * TMR_RES_MICROSEC;
} else {
res = 1000 * TMR_RES_MICROSEC;
}
- timeout = waitTime.usec / 1000;
+ timeout = waitTimeWithOverhead / 1000;
/* set more precise timer resolution for minimal delay */
if (!actualResolution || res < timerResolution.curRes) {
actualResolution = SetTimerResolution(
@@ -727,11 +723,8 @@ Tcl_WaitForEvent(
}
}
} else {
- timeout = waitTime.sec * 1000 + waitTime.usec / 1000;
+ timeout = waitTime / 1000;
}
-
- } else {
- timeout = INFINITE;
}
/*
@@ -796,31 +789,28 @@ Tcl_WaitForEvent(
else
if (result == WAIT_TIMEOUT && timeout != INFINITE) {
/* Check the wait should be repeated, and correct time for wait */
- Tcl_Time now;
+ Tcl_WideInt now;
- Tcl_GetTime(&now);
+ now = TclpGetMicroseconds();
/*
* Note time can be switched backwards, certainly adjust end-time
- * by possible time-jumps back.
+ * by possible time-jumps.
*/
- if (TCL_TIME_BEFORE(now, lastNow)) {
- /* backwards time-jump - simply shift wakeup-time */
- endTime.sec -= (lastNow.sec - now.sec);
- endTime.usec -= (lastNow.usec - now.usec);
- if (endTime.usec < 0) {
- endTime.usec += 1000000;
- endTime.sec--;
- }
+ if ((waitTime = TclpGetLastTimeJump(&timeJumpEpoch)) != 0) {
+ /* we know time-jump, adjust end-time using this offset */
+ endTime += waitTime;
+ }
+ else
+ if ((waitTime = (now - lastNow)) < 0) {
+ /* recognized backwards time-jump - simply shift wakeup-time *
+ * considering timeout also, assume we've reached it completely */
+ endTime += (waitTime - (timeout * 1000));
}
lastNow = now;
/* calculate new waitTime */
- waitTime.sec = (endTime.sec - now.sec);
- if ((waitTime.usec = (endTime.usec - now.usec)) < 0) {
- waitTime.usec += 1000000;
- waitTime.sec--;
- }
- if (waitTime.sec < 0 || !waitTime.sec && waitTime.usec <= tolerance) {
+ waitTime = endTime - now;
+ if (waitTime <= tolerance) {
goto end;
}
/* Repeat wait with more precise timer resolution (or using sleep) */
@@ -841,9 +831,11 @@ Tcl_WaitForEvent(
/*
*----------------------------------------------------------------------
*
- * Tcl_Sleep --
+ * Tcl_Sleep --, TclpUSleep --
*
- * Delay execution for the specified number of milliseconds.
+ * Delay execution for the specified number of milliseconds (or microsec.).
+ *
+ * TclpUSleep in contrast to Tcl_Sleep is more precise (microseconds).
*
* Results:
* None.
@@ -858,6 +850,13 @@ void
Tcl_Sleep(
int ms) /* Number of milliseconds to sleep. */
{
+ TclpUSleep((Tcl_WideInt)ms * 1000);
+}
+
+void
+TclpUSleep(
+ Tcl_WideInt usec) /* Number of microseconds to sleep. */
+{
/*
* Simply calling 'Sleep' for the requisite number of milliseconds can
* make the process appear to wake up early because it isn't synchronized
@@ -868,72 +867,67 @@ Tcl_Sleep(
* requisite amount.
*/
- Tcl_Time lastNow, now; /* Current wall clock time. */
- Tcl_Time desired; /* Desired wakeup time. */
- Tcl_Time vdelay; /* Time to sleep, for scaling virtual ->
- * real. */
+ Tcl_WideInt lastNow, now; /* Current wall clock time. */
+ Tcl_WideInt desired; /* Desired wakeup time. */
DWORD sleepTime; /* Time to sleep, real-time */
long tolerance = 0;
unsigned long actualResolution = 0;
+ size_t timeJumpEpoch = 0;
- if (ms <= 0) {
- /* causes context switch only */
- Sleep(0);
- return;
+ if (usec <= 9) { /* too short to start whole sleep process */
+ do {
+ /* causes context switch only (shortest waiting) */
+ Sleep(0);
+ } while (--usec > 0);
+ return;
}
if (timerResolution.available == -1) {
InitTimerResolution();
}
- vdelay.sec = ms / 1000;
- vdelay.usec = (ms % 1000) * 1000;
-
- Tcl_GetTime(&now);
- lastNow = now;
- desired.sec = now.sec + vdelay.sec;
- desired.usec = now.usec + vdelay.usec;
- if (desired.usec > 1000000) {
- desired.usec -= 1000000;
- desired.sec++;
- }
+ lastNow = now = TclpGetMicroseconds();
+ desired = now + usec;
+ timeJumpEpoch = TclpGetLastTimeJumpEpoch();
#ifdef TMR_RES_TOLERANCE
/* calculate possible maximal tolerance (in usec) of original wait-time */
- tolerance = ((vdelay.sec <= 0) ? vdelay.usec : 1000000) *
- (TMR_RES_TOLERANCE / 100);
+ tolerance = ((usec <= 1000000) ? usec : 1000000) *
+ TMR_RES_TOLERANCE / 100;
+ if (tolerance > timerResolution.maxDelay) {
+ tolerance = timerResolution.maxDelay;
+ }
#endif
- /*
- * TIP #233: Scale delay from virtual to real-time.
- */
-
for (;;) {
- tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
+ /*
+ * TIP #233: Scale delay from virtual to real-time.
+ */
+ usec = TclpScaleUTime(usec);
/* No wait if sleep time too small (because windows may wait too long) */
- if (!vdelay.sec && vdelay.usec < (long)timerResolution.minDelay) {
+ if (usec < (long)timerResolution.minDelay) {
sleepTime = 0;
goto wait;
}
if (timerResolution.available) {
- if (vdelay.sec || vdelay.usec > timerResolution.maxDelay) {
- long usec;
- sleepTime = vdelay.sec * 1000;
- usec = ((sleepTime * 1000) + vdelay.usec) % 1000000;
- sleepTime += (usec - (usec % timerResolution.maxDelay)) / 1000;
+ if (usec > timerResolution.maxDelay) {
+ /* floor (truncate) using max delay as base (follow timeout better) */
+ sleepTime = (usec
+ / timerResolution.maxDelay)
+ * timerResolution.maxDelay / 1000;
} else {
/* calculate resolution up to 1000 microseconds
* (don't use highest, because of too large CPU load) */
ULONG res;
- if (vdelay.usec >= 10000) {
+ if (usec >= 10000) {
res = 10000 * TMR_RES_MICROSEC;
} else {
res = 1000 * TMR_RES_MICROSEC;
}
- sleepTime = vdelay.usec / 1000;
+ sleepTime = usec / 1000;
/* set more precise timer resolution for minimal delay */
if (!actualResolution || res < timerResolution.curRes) {
actualResolution = SetTimerResolution(
@@ -941,37 +935,29 @@ Tcl_Sleep(
}
}
} else {
- sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
+ sleepTime = usec / 1000;
}
wait:
Sleep(sleepTime);
- Tcl_GetTime(&now);
+ now = TclpGetMicroseconds();
/*
* Note time can be switched backwards, certainly adjust end-time
- * by possible time-jumps back.
+ * by possible time-jumps.
*/
- if (TCL_TIME_BEFORE(now, lastNow)) {
- /* backwards time-jump - simply shift wakeup-time */
- desired.sec -= (lastNow.sec - now.sec);
- desired.usec -= (lastNow.usec - now.usec);
- if (desired.usec < 0) {
- desired.usec += 1000000;
- desired.sec--;
- }
+ if ((usec = TclpGetLastTimeJump(&timeJumpEpoch)) != 0) {
+ /* we know time-jump, adjust end-time using this offset */
+ desired += usec;
}
- lastNow = now;
-
- vdelay.sec = desired.sec - now.sec;
- vdelay.usec = desired.usec - now.usec;
- if (vdelay.usec < 0) {
- vdelay.usec += 1000000;
- vdelay.sec--;
+ else
+ if ((usec = (now - lastNow)) < 0) {
+ /* recognized backwards time-jump - simply shift wakeup-time *
+ * considering sleep-time also, assume we've reached it completely */
+ desired += (usec - (sleepTime * 1000));
}
+ lastNow = now;
- if (vdelay.sec < 0) {
- break;
- } else if ((vdelay.sec == 0) && (vdelay.usec <= tolerance)) {
+ if ((usec = (desired - now)) <= tolerance) {
break;
}
}