c11: Improve timespec_get to support TIME_MONOTONIC TIME_ACTIVE TIME_THREAD_ACTIVE...
authorYonggang Luo <luoyonggang@gmail.com>
Sat, 11 Feb 2023 16:15:19 +0000 (00:15 +0800)
committerMarge Bot <emma+marge@anholt.net>
Tue, 20 Jun 2023 00:05:48 +0000 (00:05 +0000)
As c11 already provided timespec_get, to avoid symbol conflict, use c23_timespec_get as the function name
and define timespec_get c23_timespec_get to achieve that

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Acked-by: David Heidelberg <david.heidelberg@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23733>

meson.build
src/c11/impl/time.c
src/c11/time.h

index ad5070e..5238d6f 100644 (file)
@@ -1282,7 +1282,6 @@ endforeach
 functions_to_detect = {
   'strtof': '',
   'mkostemp': '',
-  'timespec_get': '#include <time.h>',
   'memfd_create': '',
   'random_r': '',
   'flock': '',
index f99788c..55575cb 100644 (file)
 
 #include "c11/time.h"
 
-#ifndef HAVE_TIMESPEC_GET
+#ifdef _TIMESPEC_GET_NEED_IMPL
 
 #if defined(_WIN32) && !defined(HAVE_PTHREAD)
 
+#include "c11/threads.h"
 #include <windows.h>
 
+static LARGE_INTEGER frequency;
+
+static
+void
+c23_timespec_get_init(void)
+{
+    QueryPerformanceFrequency(&frequency);
+}
+
 int
-timespec_get(struct timespec *ts, int base)
+c23_timespec_get(struct timespec *ts, int base)
 {
 /* difference between 1970 and 1601 */
 #define _TIMESPEC_IMPL_UNIX_EPOCH_IN_TICKS 116444736000000000ull
@@ -57,6 +67,25 @@ timespec_get(struct timespec *ts, int base)
         ts->tv_sec = ticks / _TIMESPEC_IMPL_TICKS_PER_SECONDS;
         ts->tv_nsec = (ticks % _TIMESPEC_IMPL_TICKS_PER_SECONDS) * 100;
         return base;
+    } else if (base == TIME_MONOTONIC || base == TIME_MONOTONIC_RAW) {
+        if (frequency.QuadPart == 0) {
+            static once_flag once = ONCE_FLAG_INIT;
+            call_once(&once, c23_timespec_get_init);
+        }
+        if (frequency.QuadPart != 0) {
+            LARGE_INTEGER now;
+            LONGLONG sec;
+            LONGLONG nsec;
+            QueryPerformanceCounter(&now);
+            sec = now.QuadPart / frequency.QuadPart;
+            nsec = (now.QuadPart - sec * frequency.QuadPart)
+                * 1000000000UL / frequency.QuadPart;
+            ts->tv_sec = (time_t)sec;
+            ts->tv_nsec = (long)nsec;
+            return base;
+        }
+        /* Otherwise timespec_get with TIME_MONOTONIC or TIME_MONOTONIC_RAW failed */
+        return 0;
     }
     return 0;
 #undef _TIMESPEC_IMPL_UNIX_EPOCH_IN_TICKS
@@ -65,14 +94,42 @@ timespec_get(struct timespec *ts, int base)
 
 #else
 
-int
-timespec_get(struct timespec *ts, int base)
+int c23_timespec_get(struct timespec *ts, int base)
 {
     if (!ts)
         return 0;
-    if (base == TIME_UTC) {
-        clock_gettime(CLOCK_REALTIME, ts);
-        return base;
+    switch (base)
+    {
+    case TIME_UTC:
+        if (clock_gettime(CLOCK_REALTIME, ts) == 0)
+            return base;
+        break;
+#ifdef CLOCK_MONOTONIC
+    case TIME_MONOTONIC:
+        if (clock_gettime(CLOCK_MONOTONIC, ts) == 0)
+            return base;
+        break;
+#endif
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+    case TIME_ACTIVE:
+        if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ts) == 0)
+            return base;
+        break;
+#endif
+#ifdef CLOCK_THREAD_CPUTIME_ID
+    case TIME_THREAD_ACTIVE:
+        if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts) == 0)
+            return base;
+        break;
+#endif
+#ifdef CLOCK_MONOTONIC_RAW
+    case TIME_MONOTONIC_RAW:
+        if (clock_gettime(CLOCK_MONOTONIC_RAW, ts) == 0)
+            return base;
+        break;
+#endif
+    default:
+        break;
     }
     return 0;
 }
index b9f779c..33762f8 100644 (file)
 
 /*---------------------------- macros ---------------------------*/
 
-#ifndef TIME_UTC
+/* Refer to https://htmlpreview.github.io/?https://icube-forge.unistra.fr/icps/c23-library/-/raw/main/README.html#time_monotonic-time_active-time_thread_active */
+#if defined(TIME_UTC) && \
+   defined(TIME_MONOTONIC) && \
+   defined(TIME_ACTIVE) && \
+   defined(TIME_THREAD_ACTIVE) && \
+   defined(TIME_MONOTONIC_RAW)
+/* all needed time base is implemented */
+#else
+#define _TIMESPEC_GET_NEED_IMPL
+#endif
+
+#ifdef _TIMESPEC_GET_NEED_IMPL
+#undef TIME_UTC
+#undef TIME_MONOTONIC
+#undef TIME_ACTIVE
+#undef TIME_THREAD_ACTIVE
+#undef TIME_MONOTONIC_RAW
+/* c11 */
 #define TIME_UTC 1
+/* c23 */
+#define TIME_MONOTONIC 2
+#define TIME_ACTIVE 3
+#define TIME_THREAD_ACTIVE 4
+#define TIME_MONOTONIC_RAW 5
+#define timespec_get c23_timespec_get
 #endif
 
 #ifdef __cplusplus
@@ -37,22 +60,22 @@ struct timespec
 
 /*-------------------------- functions --------------------------*/
 
-#if !defined(HAVE_TIMESPEC_GET)
-#define _HAVE_TIMESPEC_GET_NEED_DECL
+#if defined(_TIMESPEC_GET_NEED_IMPL)
+#define _TIMESPEC_GET_NEED_DECL
 #elif defined(__APPLE__) && defined(__cplusplus) && (__cplusplus < 201703L)
 /* On macOS, the guard for declaration of timespec_get is by
  * (defined(__cplusplus) && __cplusplus >= 201703L),
  * fix the declaration for C++14 and lower here
  */
-#define _HAVE_TIMESPEC_GET_NEED_DECL
+#define _TIMESPEC_GET_NEED_DECL
 #endif
 
-#ifdef _HAVE_TIMESPEC_GET_NEED_DECL
+#ifdef _TIMESPEC_GET_NEED_DECL
 /*-------------------- 7.25.7 Time functions --------------------*/
 // 7.25.6.1
 int
 timespec_get(struct timespec *ts, int base);
-#undef _HAVE_TIMESPEC_GET_NEED_DECL
+#undef _TIMESPEC_GET_NEED_DECL
 #endif
 
 #ifdef __cplusplus