Use a monotonic clock to compute timeouts #66242
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
assignee = None closed_at = <Date 2014-09-17.22:17:19.598> created_at = <Date 2014-07-23.02:10:01.628> labels = ['type-feature'] title = 'Use a monotonic clock to compute timeouts' updated_at = <Date 2014-09-17.22:17:19.596> user = 'https://github.com/vstinner'
activity = <Date 2014-09-17.22:17:19.596> actor = 'vstinner' assignee = 'none' closed = True closed_date = <Date 2014-09-17.22:17:19.598> closer = 'vstinner' components =  creation = <Date 2014-07-23.02:10:01.628> creator = 'vstinner' dependencies =  files = ['36041', '36176', '36177', '36504', '36513'] hgrepos =  issue_num = 22043 keywords = ['patch'] message_count = 18.0 messages = ['223715', '223716', '224365', '224390', '224392', '224393', '224456', '225969', '226064', '226065', '226066', '226067', '226175', '226283', '226284', '226301', '226302', '227016'] nosy_count = 4.0 nosy_names = ['belopolsky', 'vstinner', 'neologix', 'python-dev'] pr_nums =  priority = 'normal' resolution = 'fixed' stage = None status = 'closed' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue22043' versions = ['Python 3.5']
The text was updated successfully, but these errors were encountered:
Currently, socket methods (ex: accept, recv, recvfrom, recvmsg, send, sendto, sendmsg), threading.Lock.acquire() and threading.RLock.acquire() use the system clock to compute their timeout. It's fine for the first call. But if the call is interrupted and the timeout need to be recomputed, it can wait too short or too long. Timeouts must use a monotonic clock, not the system clock. See the PEP-418 for more information.
Python modules were already patched to use the time.monotonic() function implemented in Python 3.3.
Attached patch fixes also functions which still use the system clock to compute timeouts.
A major change of the patch is that a monotonic clock is now require to use Python 3.5. Last time I checked, there was only one OS without monotonic clock: GNU Hurd. Hurd maintainers can patch Python 3.5 to fallback on the system clock until Hurd provides a monotonic clock.
Another important change is that Python now depends on the librt on Solaris and on Linux with glibc older than 2.17 (clock_gettime is now available directly in the libc since glibc 2.17).
pymonotonic.patch is large and difficult to review. I prefer to split it into two parts:
pytimespec.patch removes *private* functions which were exposed in the stable ABI:
It also removes private macros:
In pymonotonic.patch, I reused the same name but I didn't notice that they were part of the stable ABI. In pymonotonic-2.patch, I changed names so the dynamic loader will not load a module and the compiler will complain that symbols are missing.
I aslo added new functions:
On overflow, _PyTimeSpec_add_sec() and _PyTimeSpec_add_us() sets the timestamp to the maximum value instead of returning an undefined value. I prefer functions over macros because I want to return an error on overflow (even if it's not used).
_PyTimeSpec_interval_us() also returns the maximum value in case of overflow.
_PyTimeSpec_interval_sec() should maybe take a mandatory round parameter instead of always rounding up.
I added _PyTime_unit_t for _threadmodule.c because acquire_timed() has a PY_TIMEOUT_T type which can be a long long. Maybe acquire_timed() can return an error if the timeout is too large, or loop? I would prefer to avoid this custom _PyTime_unit_t type.
I should maybe add unit tests for _PyTimeSpec_add_() and _PyTimeSpec_interval_() functions, as I did for _PyLong_FromTime_t(), _PyTime_ObjectToTimeval(), etc.
Ok, I prepared Python for monotonic clock, I attached an updated patch. It is now much simpler.