Skip to content

Instantly share code, notes, and snippets.

@haukex
Last active April 16, 2023 11:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haukex/f3955421834b3aacda963e73ab58f74e to your computer and use it in GitHub Desktop.
Save haukex/f3955421834b3aacda963e73ab58f74e to your computer and use it in GitHub Desktop.
Test adjusting system clock during sleep_until
igbpyutils >= 0.0.3
sleep_until
Linux hostname 4.15.0-206-generic #217-Ubuntu SMP Fri Feb 3 19:10:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-10T08:23:27.994331+00:00, now sleep_until for 0:01:00 to 2023-04-10T08:24:27.994331+00:00
30.030s Settime Thread adjusting time from 2023-04-10T08:23:58.024569+00:00 by -0:00:30 to 2023-04-10T08:23:28.024569+00:00
30.032s Settime Thread time adjusted, is now 2023-04-10T08:23:28.026422+00:00
90.000s Sleep Thread woke at 2023-04-10T08:24:27.994588+00:00
Threads joined.
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-10T08:24:27.995984+00:00, now sleep_until for 0:01:00 to 2023-04-10T08:25:27.995984+00:00
30.030s Settime Thread adjusting time from 2023-04-10T08:24:58.026027+00:00 by 0:00:30 to 2023-04-10T08:25:28.026027+00:00
30.030s Settime Thread time adjusted, is now 2023-04-10T08:25:28.026162+00:00
30.031s Sleep Thread woke at 2023-04-10T08:25:28.026445+00:00
Threads joined.
Linux devbox 5.15.0-67-generic #74-Ubuntu SMP Wed Feb 22 14:14:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-09T19:52:10.353283+00:00, now sleep_until for 0:01:00 to 2023-04-09T19:53:10.353283+00:00
30.002s Settime Thread adjusting time from 2023-04-09T19:52:40.355004+00:00 by -0:00:30 to 2023-04-09T19:52:10.355004+00:00
30.006s Settime Thread time adjusted, is now 2023-04-09T19:52:10.359449+00:00
90.002s Sleep Thread woke at 2023-04-09T19:53:10.354548+00:00
Threads joined.
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-09T19:53:10.355118+00:00, now sleep_until for 0:01:00 to 2023-04-09T19:54:10.355118+00:00
30.001s Settime Thread adjusting time from 2023-04-09T19:53:40.356573+00:00 by 0:00:30 to 2023-04-09T19:54:10.356573+00:00
30.002s Settime Thread time adjusted, is now 2023-04-09T19:54:10.356718+00:00
30.006s Sleep Thread woke at 2023-04-09T19:54:10.361206+00:00
Threads joined.
Windows 10 Pro 22H2 19045.2364 Feature Experience Pack 120.2212.4190.0
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-10T08:34:28.630212+00:00, now sleep_until for 0:01:00 to 2023-04-10T08:35:28.630212+00:00
30.000s Settime Thread adjusting time from 2023-04-10T08:34:58.632306+00:00 by -0:00:30 to 2023-04-10T08:34:28.632306+00:00
30.000s Settime Thread time adjusted, is now 2023-04-10T08:34:28.632000+00:00
90.000s Sleep Thread woke at 2023-04-10T08:35:28.629865+00:00
Threads joined.
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-10T08:35:28.629865+00:00, now sleep_until for 0:01:00 to 2023-04-10T08:36:28.629865+00:00
30.000s Settime Thread adjusting time from 2023-04-10T08:35:58.633071+00:00 by 0:00:30 to 2023-04-10T08:36:28.633071+00:00
30.000s Settime Thread time adjusted, is now 2023-04-10T08:36:28.633175+00:00
30.000s Sleep Thread woke at 2023-04-10T08:36:28.633175+00:00
Threads joined.
Windows 10 Pro 22H2 19045.2486 Feature Experience Pack 120.2212.4190.0
(this VM was under heavy load, which probably accounts for the jitter in some of the timestamps below)
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-09T19:53:20.274309+00:00, now sleep_until for 0:01:00 to 2023-04-09T19:54:20.274309+00:00
30.016s Settime Thread adjusting time from 2023-04-09T19:53:45.188019+00:00 by -0:00:30 to 2023-04-09T19:53:15.188019+00:00
30.016s Settime Thread time adjusted, is now 2023-04-09T19:53:15.188000+00:00
90.000s Sleep Thread woke at 2023-04-09T19:54:31.057276+00:00
Threads joined.
Starting threads...
0.000s Settime Thread started, sleeping 30s until adjustment
0.000s Sleep Thread started at 2023-04-09T19:54:31.057276+00:00, now sleep_until for 0:01:00 to 2023-04-09T19:55:31.057276+00:00
30.032s Settime Thread adjusting time from 2023-04-09T19:55:16.091157+00:00 by 0:00:30 to 2023-04-09T19:55:46.091157+00:00
30.047s Settime Thread time adjusted, is now 2023-04-09T19:55:46.091424+00:00
30.047s Sleep Thread woke at 2023-04-09T19:55:46.091424+00:00
Threads joined.
#!/usr/bin/env python3
"""Test to confirm what happens when the system clock is adjusted during sleep_until.
The Windows documentation at
<https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setwaitabletimerex>
says regarding SetWaitableTimerEx:
"If the system time is adjusted, the due time of any outstanding absolute timers is adjusted."
The Ubuntu Linux documentation at
<https://manpages.ubuntu.com/manpages/kinetic/en/man2/clock_nanosleep.2.html#notes>
says regarding clock_nanosleep:
"POSIX.1 specifies that after changing the value of the CLOCK_REALTIME clock via
clock_settime(2), the new clock value shall be used to determine the time at which a
thread blocked on an absolute clock_nanosleep() will wake up; if the new clock value falls
past the end of the sleep interval, then the clock_nanosleep() call will return immediately."
Results (in the results_*.txt files) confirm this.
"""
import sys
from threading import Thread, Barrier
from datetime import datetime, timedelta, timezone
from time import sleep, monotonic
from sleep_until import sleep_until
# noinspection PyPackageRequirements
from igbpyutils.dt import timedelta_str
bar = Barrier(3)
class TimeSetThread(Thread):
def __init__(self, delay_s, adjustment):
super().__init__()
self.delay_s = delay_s
self.adj = adjustment
def run(self):
if sys.platform.startswith('win32'):
# noinspection PyPackageRequirements,PyUnresolvedReferences
import win32api
def mysettime(dt :datetime):
win32api.SetSystemTime( dt.year, dt.month, dt.isoweekday()%7, dt.day,
dt.hour, dt.minute, dt.second, dt.microsecond//1000 )
else:
from time import clock_settime, CLOCK_REALTIME
def mysettime(dt :datetime):
clock_settime(CLOCK_REALTIME, dt.timestamp())
bar.wait()
monostart_s = monotonic()
print(f"{monotonic()-monostart_s:6.3f}s Settime Thread started, sleeping {self.delay_s}s until adjustment")
sleep(self.delay_s)
now = datetime.now(timezone.utc)
newtime = now + self.adj
print(f"{monotonic()-monostart_s:6.3f}s Settime Thread adjusting time from {now.isoformat()} by {timedelta_str(self.adj)} to {newtime.isoformat()}")
mysettime(newtime)
print(f"{monotonic()-monostart_s:6.3f}s Settime Thread time adjusted, is now {datetime.now(timezone.utc).isoformat()}")
class SleeperThread(Thread):
def __init__(self, relative):
super().__init__()
self.relative = relative
def run(self):
bar.wait()
monostart_s = monotonic()
now = datetime.now(timezone.utc)
sleepto = now + self.relative
print(f"{monotonic()-monostart_s:6.3f}s Sleep Thread started at {now.isoformat()}, now sleep_until for {timedelta_str(self.relative)} to {sleepto.isoformat()}")
sleep_until( sleepto.timestamp() )
print(f"{monotonic()-monostart_s:6.3f}s Sleep Thread woke at {datetime.now(timezone.utc).isoformat()}")
for adj in ( timedelta(seconds=-30), timedelta(seconds=30) ):
print("Starting threads...")
th1 = TimeSetThread( 30, adj )
th2 = SleeperThread( timedelta(minutes=1) )
th1.start()
th2.start()
bar.wait()
th1.join()
th2.join()
print("Threads joined.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment