https://bugs.winehq.org/show_bug.cgi?id=57035
Bug ID: 57035 Summary: syscalls taking absolute timeouts may resume prematurely Product: Wine Version: 9.0 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: lh_mouse@126.com Distribution: ---
testcase: ```c // x86_64-w64-mingw32-gcc test.c -Wall -Wextra -O2 -lntdll #include <windows.h> #include <winternl.h> #include <stdio.h>
int main(void) { LARGE_INTEGER t1, t2;
// Get current time and round up to a one-second boundary. GetSystemTimeAsFileTime((FILETIME*) &t1); t1.QuadPart /= 10000000; t1.QuadPart *= 10000000; t1.QuadPart += 20000000;
// Wait for the current process itself (effectively sleep). printf("sleep until %lld\n", t1.QuadPart); NtWaitForSingleObject((HANDLE) -1, FALSE, &t1);
// Check current time. GetSystemTimeAsFileTime((FILETIME*) &t2); printf("current time %lld\n", t2.QuadPart); } ```
On Wine 9.0 the `NtWaitForSingleObject` syscall may resume before the timeout: ``` $ wine ./a.exe sleep until 133673207280000000 current time 133673207279998808
$ wine --version wine-9.0 (Ubuntu 9.0~repack-4build3) ```
This behavior was not observed on Wine 6.0 (Ubuntu "Jammy" 22.04 LTS), and is not observed on any physical installation of Windows 10 on x86-64, nor on Windows 11 on x86-64 or ARM64.
https://bugs.winehq.org/show_bug.cgi?id=57035
Fabian Maurer dark.shadow4@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dark.shadow4@web.de
--- Comment #1 from Fabian Maurer dark.shadow4@web.de --- (133673207280000000-133673207279998808)*100 = 119200 ns = 0.1192 ms
FWIW, I get
sleep until 133673597400000000 current time 133673597400001445
Both are very well within the margin or error, sleeps are never perfectly accurate. Is there an actual error this causes?
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #2 from LIU Hao lh_mouse@126.com ---
Both are very well within the margin or error, sleeps are never perfectly accurate.
Is there an actual error this causes?
No. I have implemented timed mutex, condition variable, and sleep functions that rely on such behavior, and my tests start to fail since Wine 9.0 because of this.
Not sure about Windows though, let's take POSIX for example: (https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.h...)
DESCRIPTION (p3) The suspension time caused by this function may be longer than requested because the argument value is rounded up to an integer multiple of the sleep resolution, ...
So if a 'sleep resolution' (schduling gradularity, I suspect) exists, the timeout shall be rounded up, and the suspension may be longer than requested; in no case shall it be shorter.
Also see message of https://github.com/mingw-w64/mingw-w64/commit/52f2ce12c6182bd239e4f1bbffcd42...
https://bugs.winehq.org/show_bug.cgi?id=57035
Zeb Figura z.figura12@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |z.figura12@gmail.com
--- Comment #3 from Zeb Figura z.figura12@gmail.com --- Does POSIX guarantee that if a process sleeps until absolute time X, that its next query for time will be greater than or equal to X? It's not clear to me whether clock_nanosleep() actually guarantees this.
If process A sleeps until absolute time X, wakes up process B, and process B checks time, is it guaranteed to be greater than or equal to X?
If process A gets time X, sleeps for C ms, then wakes up process B, does B get at least X+C?
The last one is the situation we're dealing with here (process A is wineserver; C is correctly calculated to always round up). If POSIX guarantees this, then it's a host (Linux) bug. If POSIX does not guarantee this, then I don't think there's anything we can do.
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #4 from LIU Hao lh_mouse@126.com --- (In reply to Zeb Figura from comment #3)
Does POSIX guarantee that if a process sleeps until absolute time X, that its next query for time will be greater than or equal to X? It's not clear to me whether clock_nanosleep() actually guarantees this.
If process A sleeps until absolute time X, wakes up process B, and process B checks time, is it guaranteed to be greater than or equal to X?
If process A gets time X, sleeps for C ms, then wakes up process B, does B get at least X+C?
This sounds to me like a question that, if `clock_nanosleep()` has exceeded an absolute time point, is a subsequent call to `clock_gettime` allowed to return a value less than the argument to `clock_nanosleep`?
The last one is the situation we're dealing with here (process A is wineserver; C is correctly calculated to always round up). If POSIX guarantees this, then it's a host (Linux) bug. If POSIX does not guarantee this, then I don't think there's anything we can do.
This is clearly not a host issue. There is no such issue on Wine 6 on Linux Mint 21 but there is such an issue on Wine 9 on the same system.
And on my current Linux Mint 22 (bug) installation I create this program to test the host system:
```c // x86_64-linux-gnu-gcc test.c -Wall -Wextra -O2 #include <pthread.h> #include <time.h> #include <stdio.h>
int main(void) { struct timespec t1, t2;
// Get current time and round up to a one-second boundary. clock_gettime(CLOCK_REALTIME, &t1); t1.tv_sec += 2; t1.tv_nsec = 0;
// Wait for the current process itself (effectively sleep). printf("sleep until %ld\n", t1.tv_sec * 1000000000 + t1.tv_nsec); clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &t1, NULL);
// Check current time. clock_gettime(CLOCK_REALTIME, &t2); printf("current time %ld\n", t2.tv_sec * 1000000000 + t2.tv_nsec); } ```
and `clock_nanosleep` never resumes prematurely:
``` lh_mouse@lhmouse-xps ~/Desktop $ x86_64-linux-gnu-gcc test.c -Wall -Wextra -O2
lh_mouse@lhmouse-xps ~/Desktop $ ./a.out sleep until 1722915802000000000 current time 1722915802000076765
lh_mouse@lhmouse-xps ~/Desktop $ ./a.out sleep until 1722915804000000000 current time 1722915804000115219
lh_mouse@lhmouse-xps ~/Desktop $ ./a.out sleep until 1722915806000000000 current time 1722915806000087441
lh_mouse@lhmouse-xps ~/Desktop $ ./a.out sleep until 1722915808000000000 current time 1722915808000032686
lh_mouse@lhmouse-xps ~/Desktop $ ./a.out sleep until 1722915810000000000 current time 1722915810000037128 ```
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #5 from Zeb Figura z.figura12@gmail.com --- (In reply to LIU Hao from comment #4)
(In reply to Zeb Figura from comment #3)
The last one is the situation we're dealing with here (process A is wineserver; C is correctly calculated to always round up). If POSIX guarantees this, then it's a host (Linux) bug. If POSIX does not guarantee this, then I don't think there's anything we can do.
This is clearly not a host issue. There is no such issue on Wine 6 on Linux Mint 21 but there is such an issue on Wine 9 on the same system.
Hmm, I'm not sure where things could be going wrong in Wine code, but it sounds like it may be bisectable then?
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #6 from LIU Hao lh_mouse@126.com --- Wine 8.0 on Debian Bookworm also doesn't have this issue.
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #7 from Zeb Figura z.figura12@gmail.com --- (In reply to Fabian Maurer from comment #1)
(133673207280000000-133673207279998808)*100 = 119200 ns = 0.1192 ms
FWIW, I get
sleep until 133673597400000000 current time 133673597400001445
Both are very well within the margin or error, sleeps are never perfectly accurate. Is there an actual error this causes?
I can't reproduce this either. I don't think it's going to be possible to debug without reproducing, or at least a bisect.
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #8 from LIU Hao lh_mouse@126.com --- (In reply to Zeb Figura from comment #7)
I can't reproduce this either. I don't think it's going to be possible to debug without reproducing, or at least a bisect.
Would it be helpful if I provide more detailed information about my system, such as CPU model and kernel version?
https://bugs.winehq.org/show_bug.cgi?id=57035
--- Comment #9 from LIU Hao lh_mouse@126.com --- This is clearly reproducible on a refresh installation of Ubuntu 24.04:
https://github.com/lhmouse/winehq-playground/actions/runs/10398802912/job/28...
By the way, I really hope that your wine package doesn't depend on the 32-bit one, so it's possible to install 64-bit wine without pulling in a number of unwanted 32-bit packages. This is only the case if I install wine packages from Ubuntu APT sources, but not from WineHQ APT sources.