Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
Sleep.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#if qStroika_Foundation_Common_Platform_Windows
5#include <windows.h>
6#elif qStroika_Foundation_Common_Platform_POSIX
7#include <time.h>
8#include <unistd.h>
9#endif
10#include <cerrno>
11
13
15
16 //redeclare to avoid having to include Thread code
17 namespace Thread {
19 }
20
21 /*
22 ********************************************************************************
23 ******************************** Execution::Sleep ******************************
24 ********************************************************************************
25 */
26 inline void Sleep (Time::Duration seconds2Wait, Time::DurationSeconds* remainingInSleep)
27 {
28 // NB: even though this is complicated, its inlined because most of it is if constexpr, and eliminated and inlining
29 // makes it easier for optimizer to eliminate unused portions
30 Require (seconds2Wait >= 0.0s);
31 RequireNotNull (remainingInSleep); // else call the one-argument overload
33 // @todo lose if the #if stuff and use just if constexpr (but not working on msvc - complains about nanosleep undefined)
34#if qStroika_Foundation_Common_Platform_POSIX
35 if constexpr (qStroika_Foundation_Common_Platform_POSIX) {
36 constexpr long kNanoSecondsPerSecond = 1000L * 1000L * 1000L;
37 timespec ts;
38 ts.tv_sec = seconds2Wait.As<time_t> ();
39 ts.tv_nsec = static_cast<long> (kNanoSecondsPerSecond * (seconds2Wait.As<double> () - ts.tv_sec));
40 Assert (0 <= ts.tv_sec);
41 Assert (0 <= ts.tv_nsec and ts.tv_nsec < kNanoSecondsPerSecond);
42 timespec nextTS;
43 int nanoSleepResult = ::nanosleep (&ts, &nextTS);
44
45 // See https://github.com/microsoft/WSL/issues/4898 - workaround nanosleep EINVAL on Windows/WSL 1 with newer libc (like with ubuntu 20.04)
46#if _POSIX_C_SOURCE >= 200809L
47 if (nanoSleepResult < 0 and errno == EINVAL) {
48 if ((errno = ::clock_nanosleep (CLOCK_MONOTONIC, 0, &ts, &nextTS)) == 0) {
49 nanoSleepResult = 0;
50 }
51 }
52#endif
53 if (nanoSleepResult == 0) {
54 *remainingInSleep = 0s;
55 }
56 else {
57 Assert (errno == EINTR); // only in this case do they guarantee nextTS set properly
58 // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html doesn't clearly document allowed range for timespec
59 // https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html doesn't clearly document allowed range for output timespec (can results go negative)
60 WeakAssert (0 <= nextTS.tv_nsec and nextTS.tv_nsec < kNanoSecondsPerSecond); // docs not clear but I think this should always be true (on EINTR)... -- LGP 2020-05-29
61 WeakAssert (nextTS.tv_sec >= 0); // ""
62 *remainingInSleep =
63 Time::DurationSeconds{nextTS.tv_sec + static_cast<Time::DurationSeconds::rep> (nextTS.tv_nsec) / kNanoSecondsPerSecond};
64 }
65 }
66#elif qStroika_Foundation_Common_Platform_Windows
67 if constexpr (qStroika_Foundation_Common_Platform_Windows) {
68 Time::TimePointSeconds tc = Time::GetTickCount ();
69 if (::SleepEx (static_cast<int> (seconds2Wait.count () * 1000), true) == 0) {
70 *remainingInSleep = 0s;
71 }
72 else {
73 Time::DurationSeconds remaining = (tc + seconds2Wait) - Time::GetTickCount ();
74 if (remaining < 0s) {
75 remaining = 0s;
76 }
77 *remainingInSleep = remaining;
78 }
79 }
80#else
82#endif
83 Ensure (*remainingInSleep <= seconds2Wait);
84 Ensure (*remainingInSleep >= 0s);
85 // Consider if THIS is truly needed - doing BOTH at start and end appears excessive!
86 // But we don't want to wait at all if interrupted. And if we've waited a while and had low level sleep return because
87 // of a thread interruption, we want to translate that to an exception.
88 // So - maybe both really needed.
90 }
91
92 /*
93 ********************************************************************************
94 ***************************** Execution::Sleep *********************************
95 ********************************************************************************
96 */
97 inline void Sleep (Time::Duration seconds2Wait)
98 {
99 // to avoid accumulating error on total time waited, compute the UNTIL value and keep waiting UNTIL that point
100 Require (seconds2Wait >= 0s);
101 SleepUntil (Time::GetTickCount () + seconds2Wait);
102 }
103
104}
#define AssertNotImplemented()
Definition Assertions.h:401
#define RequireNotNull(p)
Definition Assertions.h:347
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
Definition Assertions.h:438
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
void Sleep(Time::Duration seconds2Wait)
Definition Sleep.inl:97
void SleepUntil(Time::TimePointSeconds untilTickCount)
Definition Sleep.cpp:19