]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
sys: [Linux] remove/replace obsolete timing and sleep syscalls, slightly improve...
authorbones_was_here <bones_was_here@xonotic.au>
Tue, 9 Apr 2024 16:27:45 +0000 (02:27 +1000)
committerbones_was_here <bones_was_here@xonotic.au>
Thu, 11 Apr 2024 12:11:59 +0000 (22:11 +1000)
Uses CLOCK_MONOTONIC_RAW on Linux, this is unaffected by synchronisation
adjustments and is used by SDL_GetPerformanceCounter() (we'll use it
directly to support dedicated servers without SDL).

Removes gettimeofday() and usleep() which were marked obsolete and
removed in POSIX.1-2008 so the old comment // FIXME improve this check
was impossible to address. The gettimeofday() replacement is very well
tested now (sys_useclockgettime 1 is default even in div0-stable).

Removes host_maxwait as the problems it worked around were fixed.

Tidies up a little.

Signed-off-by: bones_was_here <bones_was_here@xonotic.au>
host.c
libcurl.c
libcurl.h
sys_shared.c

diff --git a/host.c b/host.c
index fbe40b6aa70d9ee5d3965ebc073082fe1a985268..3f06d38e8ead78a23507cd5424575a62bc7e399c 100644 (file)
--- a/host.c
+++ b/host.c
@@ -44,7 +44,6 @@ host_static_t host;
 cvar_t host_framerate = {CF_CLIENT | CF_SERVER, "host_framerate","0", "locks frame timing to this value in seconds, 0.05 is 20fps for example, note that this can easily run too fast, use cl_maxfps if you want to limit your framerate instead, or sys_ticrate to limit server speed"};
 // shows time used by certain subsystems
 cvar_t host_speeds = {CF_CLIENT | CF_SERVER, "host_speeds","0", "reports how much time is used in server/graphics/sound"};
-cvar_t host_maxwait = {CF_CLIENT | CF_SERVER, "host_maxwait","1000", "maximum sleep time requested from the operating system in millisecond. Larger sleeps will be done using multiple host_maxwait length sleeps. Lowering this value will increase CPU load, but may help working around problems with accuracy of sleep times."};
 
 cvar_t developer = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "developer","0", "shows debugging messages and information (recommended for all developers and level designers); the value -1 also suppresses buffering and logging these messages"};
 cvar_t developer_extra = {CF_CLIENT | CF_SERVER, "developer_extra", "0", "prints additional debugging messages, often very verbose!"};
@@ -278,7 +277,6 @@ static void Host_InitLocal (void)
        Cvar_RegisterVariable (&host_framerate);
        Cvar_RegisterCallback (&host_framerate, Host_Framerate_c);
        Cvar_RegisterVariable (&host_speeds);
-       Cvar_RegisterVariable (&host_maxwait);
        Cvar_RegisterVariable (&host_isclient);
 
        Cvar_RegisterVariable (&developer);
index 7454b24a05844b18d3e26b7f9091df189df98933..d4b2defce063377b6827b735a03bb0dd11bb988b 100644 (file)
--- a/libcurl.c
+++ b/libcurl.c
@@ -1260,7 +1260,7 @@ Returns 0 immediately if there's no transfers to wait for,
 or > 0 if a transfer is ready or the timeout was reached.
 ====================
 */
-int Curl_Select(uint32_t microseconds)
+int Curl_Select(int timeout_ms)
 {
        CURLMcode err;
        int numfds;
@@ -1268,7 +1268,7 @@ int Curl_Select(uint32_t microseconds)
        if (List_Is_Empty(&downloads))
                return 0;
 
-       err = qcurl_multi_wait(curlm, NULL, 0, microseconds / 1000, &numfds);
+       err = qcurl_multi_wait(curlm, NULL, 0, timeout_ms, &numfds);
        if (err == CURLM_OK)
                return numfds;
        Con_Printf("curl_multi_wait() failed, code %d\n", err);
index 722981e2f7b914703df2baf536f6a03cd9c4dbbe..908bc4828f6c9b49c65dc0f94cece728cc986b14 100644 (file)
--- a/libcurl.h
+++ b/libcurl.h
@@ -14,7 +14,7 @@ typedef void (*curl_callback_t) (int status, size_t length_received, unsigned ch
 // code is one of the CURLCBSTATUS constants, or the HTTP error code (when > 0).
 
 void Curl_Frame(void);
-int Curl_Select(uint32_t microseconds);
+int Curl_Select(int timeout_ms);
 qbool Curl_Running(void);
 qbool Curl_Begin_ToFile(const char *URL, double maxspeed, const char *name, int loadtype, qbool forthismap);
 
index 0dcdd87556b8ed10211bf1938ee217e9ff57e99a..67dde09843d29b323732ded03d03191087a2a758 100644 (file)
@@ -268,30 +268,26 @@ void* Sys_GetProcAddress (dllhandle_t handle, const char* name)
 #endif
 }
 
+
+
 #ifdef WIN32
 # define HAVE_TIMEGETTIME 1
 # define HAVE_QUERYPERFORMANCECOUNTER 1
 # define HAVE_WIN32_USLEEP 1
 # define HAVE_Sleep 1
-#endif
-
-#ifndef WIN32
-#if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
-# define HAVE_CLOCKGETTIME 1
-#endif
-// FIXME improve this check, manpage hints to DST_NONE
-# define HAVE_GETTIMEOFDAY 1
+#else
+# if defined(CLOCK_MONOTONIC) || defined(CLOCK_HIRES)
+#  define HAVE_CLOCKGETTIME 1
+# endif
+# if _POSIX_VERSION >= 200112L
+#  define HAVE_CLOCK_NANOSLEEP 1
+# endif
 #endif
 
 #ifdef FD_SET
 # define HAVE_SELECT 1
 #endif
 
-#ifndef WIN32
-// FIXME improve this check
-# define HAVE_USLEEP 1
-#endif
-
 // these are referenced elsewhere
 cvar_t sys_usenoclockbutbenchmark = {CF_SHARED, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
 cvar_t sys_libdir = {CF_READONLY | CF_SHARED, "sys_libdir", "", "Default engine library directory"};
@@ -303,9 +299,6 @@ static cvar_t sys_usesdldelay = {CF_SHARED, "sys_usesdldelay", "0", "use SDL_Del
 #if HAVE_QUERYPERFORMANCECOUNTER
 static cvar_t sys_usequeryperformancecounter = {CF_SHARED | CF_ARCHIVE, "sys_usequeryperformancecounter", "1", "use windows QueryPerformanceCounter timer (which has issues on systems lacking constant-rate TSCs synchronised across all cores, such as ancient PCs or VMs) for timing rather than timeGetTime function (which is low precision and had issues on some old motherboards)"};
 #endif
-#if HAVE_CLOCKGETTIME
-static cvar_t sys_useclockgettime = {CF_SHARED | CF_ARCHIVE, "sys_useclockgettime", "1", "use POSIX clock_gettime function (not adjusted by NTP on some older Linux kernels) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
-#endif
 
 static cvar_t sys_stdout = {CF_SHARED, "sys_stdout", "1", "0: nothing is written to stdout (-nostdout cmdline option sets this), 1: normal messages are written to stdout, 2: normal messages are written to stderr (-stderr cmdline option sets this)"};
 #ifndef WIN32
@@ -353,7 +346,7 @@ void Sys_Init_Commands (void)
        Cvar_RegisterVariable(&sys_debugsleep);
        Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
        Cvar_RegisterVariable(&sys_libdir);
-#if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME || HAVE_GETTIMEOFDAY
+#if HAVE_TIMEGETTIME || HAVE_QUERYPERFORMANCECOUNTER || HAVE_CLOCKGETTIME
        if(sys_supportsdlgetticks)
        {
                Cvar_RegisterVariable(&sys_usesdlgetticks);
@@ -363,9 +356,7 @@ void Sys_Init_Commands (void)
 #if HAVE_QUERYPERFORMANCECOUNTER
        Cvar_RegisterVariable(&sys_usequeryperformancecounter);
 #endif
-#if HAVE_CLOCKGETTIME
-       Cvar_RegisterVariable(&sys_useclockgettime);
-#endif
+
        Cvar_RegisterVariable(&sys_stdout);
        Cvar_RegisterCallback(&sys_stdout, Sys_UpdateOutFD_c);
 #ifndef WIN32
@@ -427,6 +418,10 @@ double Sys_DirtyTime(void)
                        Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
                return benchmark_time * 0.000001;
        }
+
+       if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
+               return (double) Sys_SDL_GetTicks() / 1000.0;
+
 #if HAVE_QUERYPERFORMANCECOUNTER
        if (sys_usequeryperformancecounter.integer)
        {
@@ -457,11 +452,13 @@ double Sys_DirtyTime(void)
 #endif
 
 #if HAVE_CLOCKGETTIME
-       if (sys_useclockgettime.integer)
        {
                struct timespec ts;
-#  ifdef CLOCK_MONOTONIC
-               // linux
+#  ifdef CLOCK_MONOTONIC_RAW
+               // Linux-specific, SDL_GetPerformanceCounter() uses it
+               clock_gettime(CLOCK_MONOTONIC, &ts);
+#  elif defined(CLOCK_MONOTONIC)
+               // POSIX
                clock_gettime(CLOCK_MONOTONIC, &ts);
 #  else
                // sunos
@@ -472,15 +469,7 @@ double Sys_DirtyTime(void)
 #endif
 
        // now all the FALLBACK timers
-       if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
-               return (double) Sys_SDL_GetTicks() / 1000.0;
-#if HAVE_GETTIMEOFDAY
-       {
-               struct timeval tp;
-               gettimeofday(&tp, NULL);
-               return (double) tp.tv_sec + tp.tv_usec / 1000000.0;
-       }
-#elif HAVE_TIMEGETTIME
+#if HAVE_TIMEGETTIME
        {
                // timeGetTime
                // platform:
@@ -499,45 +488,39 @@ double Sys_DirtyTime(void)
 #endif
 }
 
-extern cvar_t host_maxwait;
 double Sys_Sleep(double time)
 {
        double dt;
-       uint32_t microseconds;
-
-       // convert to microseconds
-       time *= 1000000.0;
-
-       if(host_maxwait.value <= 0)
-               time = min(time, 1000000.0);
-       else
-               time = min(time, host_maxwait.value * 1000.0);
+       uint32_t msec, usec, nsec;
 
-       if (time < 1 || host.restless)
+       if (time < 1.0/1000000.0 || host.restless)
                return 0; // not sleeping this frame
-
-       microseconds = time; // post-validation to prevent overflow
+       if (time >= 1)
+               time = 0.999999; // ensure passed values are in range
+       msec = time * 1000;
+       usec = time * 1000000;
+       nsec = time * 1000000000;
 
        if(sys_usenoclockbutbenchmark.integer)
        {
                double old_benchmark_time = benchmark_time;
-               benchmark_time += microseconds;
+               benchmark_time += usec;
                if(benchmark_time == old_benchmark_time)
                        Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
                return 0;
        }
 
        if(sys_debugsleep.integer)
-               Con_Printf("sys_debugsleep: requesting %u ", microseconds);
+               Con_Printf("sys_debugsleep: requesting %u ", usec);
        dt = Sys_DirtyTime();
 
        // less important on newer libcurl so no need to disturb dedicated servers
-       if (cls.state != ca_dedicated && Curl_Select(microseconds))
+       if (cls.state != ca_dedicated && Curl_Select(msec))
        {
                // a transfer is ready or we finished sleeping
        }
        else if(sys_supportsdlgetticks && sys_usesdldelay.integer)
-               Sys_SDL_Delay(microseconds / 1000);
+               Sys_SDL_Delay(msec);
 #if HAVE_SELECT
        else if (cls.state == ca_dedicated && sv_checkforpacketsduringsleep.integer)
        {
@@ -560,16 +543,21 @@ double Sys_Sleep(double time)
        #endif
                        }
                }
-               tv.tv_sec = microseconds / 1000000;
-               tv.tv_usec = microseconds % 1000000;
+               tv.tv_sec = 0;
+               tv.tv_usec = usec;
                // on Win32, select() cannot be used with all three FD list args being NULL according to MSDN
                // (so much for POSIX...), not with an empty fd_set either.
                select(lastfd + 1, &fdreadset, NULL, NULL, &tv);
        }
 #endif
-#if HAVE_USLEEP
+#if HAVE_CLOCK_NANOSLEEP
        else
-               usleep(microseconds);
+       {
+               struct timespec ts;
+               ts.tv_sec = 0;
+               ts.tv_nsec = nsec;
+               clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+       }
 #elif HAVE_WIN32_USLEEP // Windows XP/2003 minimum
        else
        {
@@ -577,7 +565,7 @@ double Sys_Sleep(double time)
                LARGE_INTEGER sleeptime;
 
                // takes 100ns units, negative indicates relative time
-               sleeptime.QuadPart = -(10 * (int64_t)microseconds);
+               sleeptime.QuadPart = -((int64_t)nsec / 100);
                timer = CreateWaitableTimer(NULL, true, NULL);
                SetWaitableTimer(timer, &sleeptime, 0, NULL, NULL, 0);
                WaitForSingleObject(timer, INFINITE);
@@ -585,15 +573,15 @@ double Sys_Sleep(double time)
        }
 #elif HAVE_Sleep
        else
-               Sleep(microseconds / 1000);
+               Sleep(msec);
 #else
        else
-               Sys_SDL_Delay(microseconds / 1000);
+               Sys_SDL_Delay(msec);
 #endif
 
        dt = Sys_DirtyTime() - dt;
        if(sys_debugsleep.integer)
-               Con_Printf(" got %u oversleep %d\n", (unsigned int)(dt * 1000000), (unsigned int)(dt * 1000000) - microseconds);
+               Con_Printf(" got %u oversleep %d\n", (unsigned int)(dt * 1000000), (unsigned int)(dt * 1000000) - usec);
        return (dt < 0 || dt >= 1800) ? 0 : dt;
 }