[PATCH v2] time: Add TIME_MONOTONIC, TIME_ACTIVE, and TIME_THREAD_ACTIVE

Adhemerval Zanella adhemerval.zanella@linaro.org
Mon Nov 24 18:29:09 GMT 2025


The TIME_MONOTONIC maps to POSIX's CLOCK_MONOTONIC, TIME_ACTIVE to
CLOCK_PROCESS_CPUTIME_ID, and TIME_THREAD_ACTIVE to
CLOCK_THREAD_CPUTIME_ID.

No Linux specific timer are added as extension.

Co-authored-by: Yonggang Luo <luoyonggang@gmail.com>

--
Changes from v1:
* Fixed new timers on ABIs with 32 bit time_t support.
* Dropped support for the Linux specific timers.

---
 NEWS                                      |  3 ++
 include/time.h                            | 15 +++++++++
 sysdeps/unix/sysv/linux/timespec_get.c    | 18 ++++------
 sysdeps/unix/sysv/linux/timespec_getres.c | 22 ++++++-------
 time/time.h                               |  5 +++
 time/timespec_get.c                       |  5 +--
 time/timespec_getres.c                    |  5 +--
 time/tst-timespec_get.c                   | 24 +++++++-------
 time/tst-timespec_getres.c                | 40 ++++++++++++++---------
 9 files changed, 83 insertions(+), 54 deletions(-)

diff --git a/NEWS b/NEWS
index 92c2b2d78a..9a47e51f74 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,9 @@ Major new features:
 * The ISO C23 functions free_sized and free_aligned_sized are now
   supported in <stdlib.h>.
 
+* The ISO C23 optimal time base TIME_MONOTONIC, TIME_ACTIVE, and
+  TIME_THREAD_ACTIVE have been added.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * Support for dumped heaps has been removed - malloc_set_state() now always
diff --git a/include/time.h b/include/time.h
index f599eeed4e..fb76055cc7 100644
--- a/include/time.h
+++ b/include/time.h
@@ -536,6 +536,21 @@ time64_now (void)
   return ts.tv_sec;
 }
 
+/* Helper that convert from c11 timebase to posix clockid_t,
+   when the mapping not exist, return -1 */
+static inline clockid_t
+clock_from_timebase (int timebase)
+{
+  switch (timebase)
+    {
+    case TIME_UTC:           return CLOCK_REALTIME;
+    case TIME_MONOTONIC:     return CLOCK_MONOTONIC;
+    case TIME_ACTIVE:        return CLOCK_PROCESS_CPUTIME_ID;
+    case TIME_THREAD_ACTIVE: return CLOCK_THREAD_CPUTIME_ID;
+    default:                 return -1;
+    }
+}
+
 #define NSEC_PER_SEC    1000000000L  /* Nanoseconds per second.  */
 #define USEC_PER_SEC    1000000L     /* Microseconds per second.  */
 #define NSEC_PER_USEC   1000L        /* Nanoseconds per microsecond.  */
diff --git a/sysdeps/unix/sysv/linux/timespec_get.c b/sysdeps/unix/sysv/linux/timespec_get.c
index 9ed49a63e4..fe55a15386 100644
--- a/sysdeps/unix/sysv/linux/timespec_get.c
+++ b/sysdeps/unix/sysv/linux/timespec_get.c
@@ -23,12 +23,10 @@
 int
 __timespec_get64 (struct __timespec64 *ts, int base)
 {
-  if (base == TIME_UTC)
-    {
-      __clock_gettime64 (CLOCK_REALTIME, ts);
-      return base;
-    }
-  return 0;
+  clockid_t clockid = clock_from_timebase (base);
+  if (clockid < 0)
+    return 0;
+  return __clock_gettime64 (clockid, ts) == 0 ? base : 0;
 }
 
 #if __TIMESIZE != 64
@@ -37,12 +35,9 @@ libc_hidden_def (__timespec_get64)
 int
 __timespec_get (struct timespec *ts, int base)
 {
-  int ret;
   struct __timespec64 tp64;
 
-  ret = __timespec_get64 (&tp64, base);
-
-  if (ret == TIME_UTC)
+  if (__timespec_get64 (&tp64, base) != 0)
     {
       if (! in_time_t_range (tp64.tv_sec))
         {
@@ -51,9 +46,10 @@ __timespec_get (struct timespec *ts, int base)
         }
 
       *ts = valid_timespec64_to_timespec (tp64);
+      return base;
     }
 
-  return ret;
+  return 0;
 }
 #endif
 strong_alias (__timespec_get, timespec_get);
diff --git a/sysdeps/unix/sysv/linux/timespec_getres.c b/sysdeps/unix/sysv/linux/timespec_getres.c
index f1c915d729..dc0dbbbfc6 100644
--- a/sysdeps/unix/sysv/linux/timespec_getres.c
+++ b/sysdeps/unix/sysv/linux/timespec_getres.c
@@ -22,12 +22,10 @@
 int
 __timespec_getres64 (struct __timespec64 *ts, int base)
 {
-  if (base == TIME_UTC)
-    {
-      __clock_getres64 (CLOCK_REALTIME, ts);
-      return base;
-    }
-  return 0;
+  clockid_t clockid = clock_from_timebase (base);
+  if (clockid < 0)
+    return 0;
+  return __clock_getres64 (clockid, ts) == 0 ? base : 0;
 }
 
 #if __TIMESIZE != 64
@@ -36,15 +34,15 @@ libc_hidden_def (__timespec_getres64)
 int
 __timespec_getres (struct timespec *ts, int base)
 {
-  int ret;
   struct __timespec64 tp64;
 
-  ret = __timespec_getres64 (&tp64, base);
+  if (__timespec_getres64 (&tp64, base) != 0 && ts != NULL)
+    {
+      *ts = valid_timespec64_to_timespec (tp64);
+      return base;
+    }
 
-  if (ret == TIME_UTC && ts != NULL)
-    *ts = valid_timespec64_to_timespec (tp64);
-
-  return ret;
+  return 0;
 }
 #endif
 strong_alias (__timespec_getres, timespec_getres);
diff --git a/time/time.h b/time/time.h
index 4913508d86..423ca4bdab 100644
--- a/time/time.h
+++ b/time/time.h
@@ -64,6 +64,11 @@ typedef __pid_t pid_t;
 /* Time base values for timespec_get.  */
 # define TIME_UTC 1
 #endif
+#if __GLIBC_USE (ISOC23)
+# define TIME_MONOTONIC          2
+# define TIME_ACTIVE             3
+# define TIME_THREAD_ACTIVE      4
+#endif
 
 __BEGIN_DECLS
 
diff --git a/time/timespec_get.c b/time/timespec_get.c
index 1f85c9d428..9d3fd7c9e0 100644
--- a/time/timespec_get.c
+++ b/time/timespec_get.c
@@ -22,9 +22,10 @@
 int
 timespec_get (struct timespec *ts, int base)
 {
-  if (base == TIME_UTC)
+  clockid_t clockid = clock_from_timebase (base);
+  if (clockid >= 0)
     {
-      __clock_gettime (CLOCK_REALTIME, ts);
+      __clock_gettime (clockid, ts);
       return base;
     }
   return 0;
diff --git a/time/timespec_getres.c b/time/timespec_getres.c
index 0c3a18f6aa..5ec309023e 100644
--- a/time/timespec_getres.c
+++ b/time/timespec_getres.c
@@ -23,9 +23,10 @@
 int
 timespec_getres (struct timespec *ts, int base)
 {
-  if (base == TIME_UTC)
+  clockid_t clockid = clock_from_timebase (base);
+  if (clockid >= 0)
     {
-      __clock_getres (CLOCK_REALTIME, ts);
+      __clock_getres (clockid, ts);
       return base;
     }
   return 0;
diff --git a/time/tst-timespec_get.c b/time/tst-timespec_get.c
index 0d2f9a1678..6e055b7c07 100644
--- a/time/tst-timespec_get.c
+++ b/time/tst-timespec_get.c
@@ -19,20 +19,22 @@
 #include <time.h>
 #include <support/check.h>
 
+static void
+test_timespec_get (int timebase)
+{
+  struct timespec ts;
+  TEST_COMPARE (timespec_get (&ts, timebase), timebase);
+  TEST_VERIFY (ts.tv_nsec >= 0);
+  TEST_VERIFY (ts.tv_nsec < 1000000000);
+}
+
 static int
 do_test (void)
 {
-  {
-    struct timespec ts;
-    TEST_COMPARE (timespec_get (&ts, 0), 0);
-  }
-
-  {
-    struct timespec ts;
-    TEST_COMPARE (timespec_get (&ts, TIME_UTC), TIME_UTC);
-    TEST_VERIFY (ts.tv_nsec >= 0);
-    TEST_VERIFY (ts.tv_nsec < 1000000000);
-  }
+  test_timespec_get (TIME_UTC);
+  test_timespec_get (TIME_MONOTONIC);
+  test_timespec_get (TIME_ACTIVE);
+  test_timespec_get (TIME_THREAD_ACTIVE);
 
   return 0;
 }
diff --git a/time/tst-timespec_getres.c b/time/tst-timespec_getres.c
index e9d6308149..5d43174804 100644
--- a/time/tst-timespec_getres.c
+++ b/time/tst-timespec_getres.c
@@ -19,31 +19,39 @@
 #include <time.h>
 #include <support/check.h>
 
+static void
+test_timespec_getres (int clockid, int timebase)
+{
+  struct timespec ts;
+  TEST_COMPARE (timespec_getres (&ts, TIME_UTC), TIME_UTC);
+  /* Expect all supported systems to support 'timebase' with
+     resolution better than one second.  */
+  TEST_VERIFY (ts.tv_sec == 0);
+  TEST_VERIFY (ts.tv_nsec > 0);
+  TEST_VERIFY (ts.tv_nsec < 1000000000);
+  /* Expect the resolution to be the same as that reported for
+     'clockid' with clock_getres.  */
+  struct timespec cts;
+  TEST_COMPARE (clock_getres (CLOCK_REALTIME, &cts), 0);
+  TEST_COMPARE (ts.tv_sec, cts.tv_sec);
+  TEST_COMPARE (ts.tv_nsec, cts.tv_nsec);
+}
+
 static int
 do_test (void)
 {
   {
     struct timespec ts;
+    /* Invalid timebase.  */
     TEST_COMPARE (timespec_getres (&ts, 0), 0);
+    /* Invalid timespec.  */
     TEST_COMPARE (timespec_getres (NULL, 0), 0);
   }
 
-  {
-    struct timespec ts;
-    TEST_COMPARE (timespec_getres (&ts, TIME_UTC), TIME_UTC);
-    /* Expect all supported systems to support TIME_UTC with
-       resolution better than one second.  */
-    TEST_VERIFY (ts.tv_sec == 0);
-    TEST_VERIFY (ts.tv_nsec > 0);
-    TEST_VERIFY (ts.tv_nsec < 1000000000);
-    TEST_COMPARE (timespec_getres (NULL, TIME_UTC), TIME_UTC);
-    /* Expect the resolution to be the same as that reported for
-       CLOCK_REALTIME with clock_getres.  */
-    struct timespec cts;
-    TEST_COMPARE (clock_getres (CLOCK_REALTIME, &cts), 0);
-    TEST_COMPARE (ts.tv_sec, cts.tv_sec);
-    TEST_COMPARE (ts.tv_nsec, cts.tv_nsec);
-  }
+  test_timespec_getres (CLOCK_REALTIME, TIME_UTC);
+  test_timespec_getres (CLOCK_MONOTONIC, TIME_MONOTONIC);
+  test_timespec_getres (CLOCK_PROCESS_CPUTIME_ID, TIME_ACTIVE);
+  test_timespec_getres (CLOCK_THREAD_CPUTIME_ID, TIME_THREAD_ACTIVE);
 
   return 0;
 }
-- 
2.43.0



More information about the Libc-alpha mailing list