Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | [1e2c6ce4] Monotonic clock for MS-Windows. Extracted from branch [tkt3328635-posix-monotonic-clock] and corresponding ticket [3328635]. Thanks, Christian! |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | 1e2c6ce4-mswin-monotonic-clock |
Files: | files | file ages | folders |
SHA3-256: |
8ea9c4081c39b8bf9e2be7da23be2f03 |
User & Date: | oehhar 2025-05-13 19:58:46.740 |
Context
2025-05-21
| ||
13:02 | [1e2c6ce4], TIP 723: document interp limit to be dependent on monotonic clock on Windows platform Leaf check-in: 8c56c95f93 user: oehhar tags: 1e2c6ce4-mswin-monotonic-clock | |
2025-05-13
| ||
19:58 | [1e2c6ce4] Monotonic clock for MS-Windows. Extracted from branch [tkt3328635-posix-monotonic-clock] ... check-in: 8ea9c4081c user: oehhar tags: 1e2c6ce4-mswin-monotonic-clock | |
2025-05-12
| ||
11:33 | Remove Tcl_GetString() stub entry: it isn't used anywhere any more check-in: fdcf6c024c user: jan.nijtmans tags: trunk, main | |
Changes
Changes to generic/tclInt.h.
︙ | ︙ | |||
3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 | * optimization (fragile on changes) in one place. */ MODULE_SCOPE int TclIsSpaceProc(int byte); #define TclIsSpaceProcM(byte) \ (((byte) > 0x20) ? 0 : TclIsSpaceProc(byte)) /* *---------------------------------------------------------------- * Command procedures in the generic core: *---------------------------------------------------------------- */ MODULE_SCOPE Tcl_ObjCmdProc Tcl_AfterObjCmd; | > > > > > > > > > | 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 | * optimization (fragile on changes) in one place. */ MODULE_SCOPE int TclIsSpaceProc(int byte); #define TclIsSpaceProcM(byte) \ (((byte) > 0x20) ? 0 : TclIsSpaceProc(byte)) /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 MODULE_SCOPE int TclpGetMonotonicTime(Tcl_Time *timePtr); #endif /* *---------------------------------------------------------------- * Command procedures in the generic core: *---------------------------------------------------------------- */ MODULE_SCOPE Tcl_ObjCmdProc Tcl_AfterObjCmd; |
︙ | ︙ |
Changes to generic/tclInterp.c.
︙ | ︙ | |||
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 | } if ((iPtr->limit.active & TCL_LIMIT_TIME) && ((iPtr->limit.timeGranularity == 1) || (ticker % iPtr->limit.timeGranularity == 0))) { Tcl_Time now; Tcl_GetTime(&now); if (iPtr->limit.time.sec < now.sec || (iPtr->limit.time.sec == now.sec && iPtr->limit.time.usec < now.usec)) { iPtr->limit.exceeded |= TCL_LIMIT_TIME; Tcl_Preserve(interp); RunLimitHandlers(iPtr->limit.timeHandlers, interp); if (iPtr->limit.time.sec > now.sec || | > > > > > > > > > | 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 | } if ((iPtr->limit.active & TCL_LIMIT_TIME) && ((iPtr->limit.timeGranularity == 1) || (ticker % iPtr->limit.timeGranularity == 0))) { Tcl_Time now; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&now); #else Tcl_GetTime(&now); #endif if (iPtr->limit.time.sec < now.sec || (iPtr->limit.time.sec == now.sec && iPtr->limit.time.usec < now.usec)) { iPtr->limit.exceeded |= TCL_LIMIT_TIME; Tcl_Preserve(interp); RunLimitHandlers(iPtr->limit.timeHandlers, interp); if (iPtr->limit.time.sec > now.sec || |
︙ | ︙ | |||
3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 | void Tcl_LimitSetTime( Tcl_Interp *interp, Tcl_Time *timeLimitPtr) { Interp *iPtr = (Interp *) interp; Tcl_Time nextMoment; memcpy(&iPtr->limit.time, timeLimitPtr, sizeof(Tcl_Time)); if (iPtr->limit.timeEvent != NULL) { Tcl_DeleteTimerHandler(iPtr->limit.timeEvent); } nextMoment.sec = timeLimitPtr->sec; nextMoment.usec = timeLimitPtr->usec+10; | > > > > > > > > > > > > > > > > > > > > > > > > > > | 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 | void Tcl_LimitSetTime( Tcl_Interp *interp, Tcl_Time *timeLimitPtr) { Interp *iPtr = (Interp *) interp; Tcl_Time nextMoment; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 Tcl_Time mono, real, limit; if (TclpGetMonotonicTime(&mono)) { Tcl_GetTime(&real); limit = *timeLimitPtr; limit.sec -= real.sec; limit.usec -= real.usec; if (limit.usec < 0) { limit.sec -= 1; limit.usec += 1000000; } limit.sec += mono.sec; limit.usec += mono.usec; if (limit.usec >= 1000000) { limit.sec += 1; limit.usec -= 1000000; } timeLimitPtr = &limit; } #endif memcpy(&iPtr->limit.time, timeLimitPtr, sizeof(Tcl_Time)); if (iPtr->limit.timeEvent != NULL) { Tcl_DeleteTimerHandler(iPtr->limit.timeEvent); } nextMoment.sec = timeLimitPtr->sec; nextMoment.usec = timeLimitPtr->usec+10; |
︙ | ︙ | |||
4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 | void Tcl_LimitGetTime( Tcl_Interp *interp, Tcl_Time *timeLimitPtr) { Interp *iPtr = (Interp *) interp; memcpy(timeLimitPtr, &iPtr->limit.time, sizeof(Tcl_Time)); } /* *---------------------------------------------------------------------- * * Tcl_LimitSetGranularity -- | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 | void Tcl_LimitGetTime( Tcl_Interp *interp, Tcl_Time *timeLimitPtr) { Interp *iPtr = (Interp *) interp; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 Tcl_Time mono, real, limit; if (TclpGetMonotonicTime(&mono)) { Tcl_GetTime(&real); limit = iPtr->limit.time; limit.sec -= mono.sec; limit.usec -= mono.usec; if (limit.usec < 0) { limit.sec -= 1; limit.usec += 1000000; } limit.sec += real.sec; limit.usec += real.usec; if (limit.usec >= 1000000) { limit.sec += 1; limit.usec -= 1000000; } memcpy(timeLimitPtr, &limit, sizeof(Tcl_Time)); return; } #endif memcpy(timeLimitPtr, &iPtr->limit.time, sizeof(Tcl_Time)); } /* *---------------------------------------------------------------------- * * Tcl_LimitSetGranularity -- |
︙ | ︙ |
Changes to generic/tclTimer.c.
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | { Tcl_Time time; /* * Compute when the event should fire. */ Tcl_GetTime(&time); time.sec += milliseconds/1000; time.usec += (milliseconds%1000)*1000; if (time.usec >= 1000000) { time.usec -= 1000000; time.sec += 1; } return TclCreateAbsoluteTimerHandler(&time, proc, clientData); | > > > > > > > > > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | { Tcl_Time time; /* * Compute when the event should fire. */ /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&time); #else Tcl_GetTime(&time); #endif time.sec += milliseconds/1000; time.usec += (milliseconds%1000)*1000; if (time.usec >= 1000000) { time.usec -= 1000000; time.sec += 1; } return TclCreateAbsoluteTimerHandler(&time, proc, clientData); |
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | blockTime.sec = 0; blockTime.usec = 0; } else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ Tcl_GetTime(&blockTime); blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } | > > > > > > > > > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 | blockTime.sec = 0; blockTime.usec = 0; } else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&blockTime); #else Tcl_GetTime(&blockTime); #endif blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } |
︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | ThreadSpecificData *tsdPtr = InitTimer(); if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ Tcl_GetTime(&blockTime); blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } | > > > > > > > > > | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | ThreadSpecificData *tsdPtr = InitTimer(); if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) { /* * Compute the timeout for the next timer on the list. */ /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&blockTime); #else Tcl_GetTime(&blockTime); #endif blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec; blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec - blockTime.usec; if (blockTime.usec < 0) { blockTime.sec -= 1; blockTime.usec += 1000000; } |
︙ | ︙ | |||
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | * most recently created handler appearing after earlier ones with the * same expiration time, we don't have to worry about newer generation * timers appearing before later ones. */ tsdPtr->timerPending = 0; currentTimerId = tsdPtr->lastTimerId; Tcl_GetTime(&time); while (1) { nextPtrPtr = &tsdPtr->firstTimerHandlerPtr; timerHandlerPtr = tsdPtr->firstTimerHandlerPtr; if (timerHandlerPtr == NULL) { break; } | > > > > > > > > > > | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | * most recently created handler appearing after earlier ones with the * same expiration time, we don't have to worry about newer generation * timers appearing before later ones. */ tsdPtr->timerPending = 0; currentTimerId = tsdPtr->lastTimerId; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&time); #else Tcl_GetTime(&time); #endif while (1) { nextPtrPtr = &tsdPtr->firstTimerHandlerPtr; timerHandlerPtr = tsdPtr->firstTimerHandlerPtr; if (timerHandlerPtr == NULL) { break; } |
︙ | ︙ | |||
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 | * the future, and wrap-around is unlikely to occur in less than about * 1-10 years. Thus it's unlikely that any old ids will still be * around when wrap-around occurs. */ afterPtr->id = tsdPtr->afterId; tsdPtr->afterId += 1; Tcl_GetTime(&wakeup); wakeup.sec += ms / 1000; wakeup.usec += ms % 1000 * 1000; if (wakeup.usec > 1000000) { wakeup.sec++; wakeup.usec -= 1000000; } afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup, | > > > > > > > > > > | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | * the future, and wrap-around is unlikely to occur in less than about * 1-10 years. Thus it's unlikely that any old ids will still be * around when wrap-around occurs. */ afterPtr->id = tsdPtr->afterId; tsdPtr->afterId += 1; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&wakeup); #else Tcl_GetTime(&wakeup); #endif wakeup.sec += ms / 1000; wakeup.usec += ms % 1000 * 1000; if (wakeup.usec > 1000000) { wakeup.sec++; wakeup.usec -= 1000000; } afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup, |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 | Tcl_WideInt ms) { Interp *iPtr = (Interp *) interp; Tcl_Time endTime, now; Tcl_WideInt diff; Tcl_GetTime(&now); endTime = now; endTime.sec += (ms / 1000); endTime.usec += (ms % 1000) * 1000; if (endTime.usec >= 1000000) { endTime.sec++; endTime.usec -= 1000000; } | > > > > > > > > > > | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 | Tcl_WideInt ms) { Interp *iPtr = (Interp *) interp; Tcl_Time endTime, now; Tcl_WideInt diff; /* * Monotonic time independent on the wall clock * MS-WIndows part extracted from ticket [3328635fff] */ #ifdef WIN32 TclpGetMonotonicTime(&now); #else Tcl_GetTime(&now); #endif endTime = now; endTime.sec += (ms / 1000); endTime.usec += (ms % 1000) * 1000; if (endTime.usec >= 1000000) { endTime.sec++; endTime.usec -= 1000000; } |
︙ | ︙ | |||
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { return TCL_ERROR; } if (Tcl_LimitCheck(interp) != TCL_OK) { return TCL_ERROR; } } Tcl_GetTime(&now); } while (TCL_TIME_BEFORE(now, endTime)); return TCL_OK; } /* *---------------------------------------------------------------------- * | > > > > > | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { return TCL_ERROR; } if (Tcl_LimitCheck(interp) != TCL_OK) { return TCL_ERROR; } } #ifdef WIN32 TclpGetMonotonicTime(&now); #else Tcl_GetTime(&now); #endif } while (TCL_TIME_BEFORE(now, endTime)); return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ |
Changes to win/tclWinInit.c.
︙ | ︙ | |||
690 691 692 693 694 695 696 697 698 699 700 701 702 703 | *lengthPtr = i; done: Tcl_DStringFree(&envString); Tcl_Free(nameUpper); return result; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | *lengthPtr = i; done: Tcl_DStringFree(&envString); Tcl_Free(nameUpper); return result; } /* *---------------------------------------------------------------------- * * TclpGetMononoticTime -- * * Like Tcl_GetTime() but return a monotonic clock source, * * Results: * 1 if monotonic. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclpGetMonotonicTime(Tcl_Time *timePtr) { ULONGLONG ms; ms = GetTickCount64(); timePtr->sec = (long)(ms/1000); timePtr->usec = ((long)(ms%1000))*1000; return 1; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: |
︙ | ︙ |
Changes to win/tclWinNotify.c.
︙ | ︙ | |||
472 473 474 475 476 477 478 | int status; /* * Compute the timeout in milliseconds. */ if (timePtr) { | < < < < | < | < < | < < | < < | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | int status; /* * Compute the timeout in milliseconds. */ if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; if (timeout == INFINITE) { timeout--; } } else { timeout = INFINITE; } /* * Check to see if there are any messages in the queue before waiting * because MsgWaitForMultipleObjects will not wake up if there are events |
︙ | ︙ | |||
593 594 595 596 597 598 599 | Tcl_Time vdelay; /* Time to sleep, for scaling virtual -> * real. */ DWORD sleepTime; /* Time to sleep, real-time */ vdelay.sec = ms / 1000; vdelay.usec = (ms % 1000) * 1000; | | > > > | > > > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | Tcl_Time vdelay; /* Time to sleep, for scaling virtual -> * real. */ DWORD sleepTime; /* Time to sleep, real-time */ vdelay.sec = ms / 1000; vdelay.usec = (ms % 1000) * 1000; TclpGetMonotonicTime(&now); desired.sec = now.sec + vdelay.sec; desired.usec = now.usec + vdelay.usec; if (desired.usec > 1000000) { ++desired.sec; desired.usec -= 1000000; } /* * TIP #233: Scale delay from virtual to real-time. */ TclScaleTime(&vdelay); sleepTime = (DWORD)vdelay.sec * 1000 + (unsigned long)vdelay.usec / 1000; if (sleepTime == INFINITE) { --sleepTime; } for (;;) { SleepEx(sleepTime, TRUE); TclpGetMonotonicTime(&now); if (now.sec > desired.sec) { break; } else if ((now.sec == desired.sec) && (now.usec >= desired.usec)) { break; } vdelay.sec = desired.sec - now.sec; vdelay.usec = desired.usec - now.usec; TclScaleTime(&vdelay); sleepTime = (DWORD)vdelay.sec * 1000 + (unsigned long)vdelay.usec / 1000; if (sleepTime == INFINITE) { --sleepTime; } } } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to win/tclWinTime.c.
︙ | ︙ | |||
1195 1196 1197 1198 1199 1200 1201 | void Tcl_SetTimeProc( Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData) { | < < < | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | void Tcl_SetTimeProc( Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData) { } /* *---------------------------------------------------------------------- * * Tcl_QueryTimeProc -- * |
︙ | ︙ |