C23: add timespec_getres() and the new TIME_* constants.

Nothing to see here --- you'll want to keep using POSIX clock_gettime()
and clock_getres() instead. But portable code might use this eventually,
and it's trivial, so let's add it anyway.

(The whole "zero as an error return" precluding the direct use of
Linux's CLOCK_ constants is what really makes this a terrible API ---
we're going to have to add explicit translation any time they add a
new base.)

Test: treehugger
Change-Id: Iddb6cbe67b67b2b10fdd8b5ee654896d23deee47
diff --git a/docs/status.md b/docs/status.md
index c2ed944..411b140 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -55,6 +55,9 @@
 
 Current libc symbols: https://android.googlesource.com/platform/bionic/+/master/libc/libc.map.txt
 
+New libc functions in V (API level 35):
+  * `timespec_getres` (C23 addition).
+
 New libc functions in U (API level 34):
   * `close_range` and `copy_file_range` (Linux-specific GNU extensions).
   * `memset_explicit` in <string.h> (C23 addition).
diff --git a/libc/Android.bp b/libc/Android.bp
index f5f5f7c..ecabb06 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1205,8 +1205,8 @@
         "bionic/termios.cpp",
         "bionic/thread_private.cpp",
         "bionic/threads.cpp",
+        "bionic/time.cpp",
         "bionic/time_l.cpp",
-        "bionic/timespec_get.cpp",
         "bionic/tmpfile.cpp",
         "bionic/umount.cpp",
         "bionic/unlink.cpp",
diff --git a/libc/bionic/timespec_get.cpp b/libc/bionic/time.cpp
similarity index 70%
rename from libc/bionic/timespec_get.cpp
rename to libc/bionic/time.cpp
index 7fc2182..3a41027 100644
--- a/libc/bionic/timespec_get.cpp
+++ b/libc/bionic/time.cpp
@@ -28,6 +28,27 @@
 
 #include <time.h>
 
+static clockid_t __base_to_clock(int base) {
+  switch (base) {
+    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;
+  }
+}
+
 int timespec_get(timespec* ts, int base) {
-  return (base == TIME_UTC && clock_gettime(CLOCK_REALTIME, ts) != -1) ? base : 0;
+  clockid_t clock = __base_to_clock(base);
+  return (clock != -1 && clock_gettime(clock, ts) != -1) ? base : 0;
+}
+
+int timespec_getres(timespec* ts, int base) {
+  clockid_t clock = __base_to_clock(base);
+  return (clock != -1 && clock_getres(clock, ts) != -1) ? base : 0;
 }
diff --git a/libc/include/time.h b/libc/include/time.h
index 5339540..2d2de9f 100644
--- a/libc/include/time.h
+++ b/libc/include/time.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _TIME_H_
-#define _TIME_H_
+#pragma once
 
 #include <sys/cdefs.h>
 #include <sys/time.h>
@@ -105,9 +104,52 @@
 time_t timelocal(struct tm* _Nonnull __tm);
 time_t timegm(struct tm* _Nonnull __tm);
 
+/**
+ * The timebase for timespec_get() and timespec_getres() corresponding to CLOCK_REALTIME.
+ *
+ * Available since API level 29.
+ */
 #define TIME_UTC 1
+
+/**
+ * The timebase for timespec_get() and timespec_getres() corresponding to CLOCK_MONOTONIC.
+ *
+ * Available since API level 35.
+ */
+#define TIME_MONOTONIC 2
+
+/**
+ * The timebase for timespec_get() and timespec_getres() corresponding to CLOCK_PROCESS_CPUTIME_ID.
+ *
+ * Available since API level 35.
+ */
+#define TIME_ACTIVE 3
+
+/**
+ * The timebase for timespec_get() and timespec_getres() corresponding to CLOCK_THREAD_CPUTIME_ID.
+ *
+ * Available since API level 35.
+ */
+#define TIME_THREAD_ACTIVE 4
+
+/**
+ * timespec_get(3) is equivalent to clock_gettime() for the clock corresponding to the given base.
+ *
+ * Returns the base on success and returns 0 on failure.
+ *
+ * Available since API level 29 for TIME_UTC; other bases arrived later.
+ * Code for Android should prefer clock_gettime().
+ */
 int timespec_get(struct timespec* _Nonnull __ts, int __base) __INTRODUCED_IN(29);
 
-__END_DECLS
+/**
+ * timespec_getres(3) is equivalent to clock_getres() for the clock corresponding to the given base.
+ *
+ * Returns the base on success and returns 0 on failure.
+ *
+ * Available since API level 35.
+ * Code for Android should prefer clock_gettime().
+ */
+int timespec_getres(struct timespec* _Nonnull __ts, int __base) __INTRODUCED_IN(35);
 
-#endif
+__END_DECLS
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index c75b13a..0102b30 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1584,6 +1584,11 @@
     posix_spawn_file_actions_addfchdir_np;
 } LIBC_T;
 
+LIBC_V { # introduced=VanillaIceCream
+  global:
+    timespec_getres;
+} LIBC_U;
+
 LIBC_PRIVATE {
   global:
     __accept4; # arm x86
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index f0ad937..0fb9bc0 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -1254,8 +1254,39 @@
 TEST(time, timespec_get) {
 #if __BIONIC__
   timespec ts = {};
-  ASSERT_EQ(0, timespec_get(&ts, 123));
   ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC));
+  ASSERT_EQ(TIME_MONOTONIC, timespec_get(&ts, TIME_MONOTONIC));
+  ASSERT_EQ(TIME_ACTIVE, timespec_get(&ts, TIME_ACTIVE));
+  ASSERT_EQ(TIME_THREAD_ACTIVE, timespec_get(&ts, TIME_THREAD_ACTIVE));
+#else
+  GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
+#endif
+}
+
+TEST(time, timespec_get_invalid) {
+#if __BIONIC__
+  timespec ts = {};
+  ASSERT_EQ(0, timespec_get(&ts, -1));
+#else
+  GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
+#endif
+}
+
+TEST(time, timespec_getres) {
+#if __BIONIC__
+  timespec ts = {};
+  ASSERT_EQ(TIME_UTC, timespec_getres(&ts, TIME_UTC));
+  ASSERT_EQ(1, ts.tv_nsec);
+  ASSERT_EQ(0, ts.tv_sec);
+#else
+  GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
+#endif
+}
+
+TEST(time, timespec_getres_invalid) {
+#if __BIONIC__
+  timespec ts = {};
+  ASSERT_EQ(0, timespec_getres(&ts, 123));
 #else
   GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21";
 #endif