[libc-commits] [libc] [libc] Add clock_gettime for Darwin (PR #167160)
Shreeyash Pandey via libc-commits
libc-commits at lists.llvm.org
Fri Nov 28 06:14:50 PST 2025
https://github.com/bojle updated https://github.com/llvm/llvm-project/pull/167160
>From b03f12115e6912bd39ad388b486257d83a540ae1 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Sat, 8 Nov 2025 23:04:03 +0530
Subject: [PATCH 1/2] [libc] Add clock_gettime for Darwin
This patch adds support for clock_gettime for Darwin. Darwin syscall
'gettimeofday' is used to query the time from the system.
Many headers in llvm-libc-types, namely clockid_t, struct_timespec,
struct_timeval, suseconds_t, time_t_32, time_t_64, are modified to include
header guards as Darwin has its own implementation of primitive types.
---
.../llvm-libc-macros/darwin/CMakeLists.txt | 5 +++
.../llvm-libc-macros/darwin/time-macros.h | 14 ++++++
libc/include/llvm-libc-macros/time-macros.h | 2 +
libc/include/llvm-libc-types/clockid_t.h | 6 +++
.../include/llvm-libc-types/struct_timespec.h | 6 +++
libc/include/llvm-libc-types/struct_timeval.h | 6 +++
libc/include/llvm-libc-types/suseconds_t.h | 6 +++
libc/include/llvm-libc-types/time_t_32.h | 6 +++
libc/include/llvm-libc-types/time_t_64.h | 6 +++
libc/src/__support/time/darwin/CMakeLists.txt | 12 +++++
.../__support/time/darwin/clock_gettime.cpp | 44 +++++++++++++++++++
libc/src/time/darwin/CMakeLists.txt | 10 +++++
libc/src/time/darwin/clock_gettime.cpp | 29 ++++++++++++
.../src/__support/time/darwin/CMakeLists.txt | 8 ++++
.../__support/time/darwin/clock_gettime.cpp | 20 +++++++++
15 files changed, 180 insertions(+)
create mode 100644 libc/include/llvm-libc-macros/darwin/CMakeLists.txt
create mode 100644 libc/include/llvm-libc-macros/darwin/time-macros.h
create mode 100644 libc/src/__support/time/darwin/CMakeLists.txt
create mode 100644 libc/src/__support/time/darwin/clock_gettime.cpp
create mode 100644 libc/src/time/darwin/CMakeLists.txt
create mode 100644 libc/src/time/darwin/clock_gettime.cpp
create mode 100644 libc/test/src/__support/time/darwin/CMakeLists.txt
create mode 100644 libc/test/src/__support/time/darwin/clock_gettime.cpp
diff --git a/libc/include/llvm-libc-macros/darwin/CMakeLists.txt b/libc/include/llvm-libc-macros/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..ea08c63c00301
--- /dev/null
+++ b/libc/include/llvm-libc-macros/darwin/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_header(
+ time_macros
+ HDR
+ time-macros.h
+)
diff --git a/libc/include/llvm-libc-macros/darwin/time-macros.h b/libc/include/llvm-libc-macros/darwin/time-macros.h
new file mode 100644
index 0000000000000..477dfa8eda85f
--- /dev/null
+++ b/libc/include/llvm-libc-macros/darwin/time-macros.h
@@ -0,0 +1,14 @@
+//===-- Definition of macros from time.h ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
+#define LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
+
+#include <_time.h>
+
+#endif // LLVM_LIBC_MACROS_LINUX_TIME_MACROS_H
diff --git a/libc/include/llvm-libc-macros/time-macros.h b/libc/include/llvm-libc-macros/time-macros.h
index 30e0a310a5485..c026df29b1e7f 100644
--- a/libc/include/llvm-libc-macros/time-macros.h
+++ b/libc/include/llvm-libc-macros/time-macros.h
@@ -7,6 +7,8 @@
#include "linux/time-macros.h"
#elif defined(__ELF__)
#include "baremetal/time-macros.h"
+#elif defined(__APPLE__)
+#include "darwin/time-macros.h"
#else
#define CLOCKS_PER_SEC 1000000
#endif
diff --git a/libc/include/llvm-libc-types/clockid_t.h b/libc/include/llvm-libc-types/clockid_t.h
index 4b059599502c4..926948717c664 100644
--- a/libc/include/llvm-libc-types/clockid_t.h
+++ b/libc/include/llvm-libc-types/clockid_t.h
@@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_CLOCKID_T_H
#define LLVM_LIBC_TYPES_CLOCKID_T_H
+#if defined(__APPLE__)
+// Darwin provides its own defintion for clockid_t . Use that to prevent
+// redeclaration errors and correctness.
+#include <_time.h>
+#else
typedef int clockid_t;
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_CLOCKID_T_H
diff --git a/libc/include/llvm-libc-types/struct_timespec.h b/libc/include/llvm-libc-types/struct_timespec.h
index 28b5a571f6790..8993ecc7db8f0 100644
--- a/libc/include/llvm-libc-types/struct_timespec.h
+++ b/libc/include/llvm-libc-types/struct_timespec.h
@@ -9,6 +9,11 @@
#ifndef LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H
#define LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H
+#if defined(__APPLE__)
+// Darwin provides its own definition for struct timespec. Include it directly
+// to ensure type compatibility and avoid redefinition errors.
+#include <sys/_types/_timespec.h>
+#else
#include "time_t.h"
struct timespec {
@@ -16,5 +21,6 @@ struct timespec {
/* TODO: BIG_ENDIAN may require padding. */
long tv_nsec; /* Nanoseconds. */
};
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_STRUCT_TIMESPEC_H
diff --git a/libc/include/llvm-libc-types/struct_timeval.h b/libc/include/llvm-libc-types/struct_timeval.h
index 9595d85a46c8f..41f0b4e92932e 100644
--- a/libc/include/llvm-libc-types/struct_timeval.h
+++ b/libc/include/llvm-libc-types/struct_timeval.h
@@ -12,9 +12,15 @@
#include "suseconds_t.h"
#include "time_t.h"
+#if defined(__APPLE__)
+// Darwin provides its own definition for struct timeval. Include it directly
+// to ensure type compatibility and avoid redefinition errors.
+#include <sys/_types/_timeval.h>
+#else
struct timeval {
time_t tv_sec; // Seconds
suseconds_t tv_usec; // Micro seconds
};
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_STRUCT_TIMEVAL_H
diff --git a/libc/include/llvm-libc-types/suseconds_t.h b/libc/include/llvm-libc-types/suseconds_t.h
index 8e926e8401f5c..acc1822cb59e1 100644
--- a/libc/include/llvm-libc-types/suseconds_t.h
+++ b/libc/include/llvm-libc-types/suseconds_t.h
@@ -14,6 +14,12 @@
// types...] and suseconds_t are no greater than the width of type long.
// The kernel expects 64 bit suseconds_t at least on x86_64.
+#if defined(__APPLE__)
+// Darwin provides its own definition for suseconds_t. Include it directly
+// to ensure type compatibility and avoid redefinition errors.
+#include <sys/_types/_suseconds_t.h>
+#else
typedef long suseconds_t;
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_SUSECONDS_T_H
diff --git a/libc/include/llvm-libc-types/time_t_32.h b/libc/include/llvm-libc-types/time_t_32.h
index 2c415f6fa9dca..8d7a81e5ce7f7 100644
--- a/libc/include/llvm-libc-types/time_t_32.h
+++ b/libc/include/llvm-libc-types/time_t_32.h
@@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_TIME_T_32_H
#define LLVM_LIBC_TYPES_TIME_T_32_H
+#if defined(__APPLE__)
+// Darwin provides its own definition for time_t. Include it directly
+// to ensure type compatibility and avoid redefinition errors.
+#include <sys/_types/_time_t.h>
+#else
typedef __INT32_TYPE__ time_t;
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_TIME_T_32_H
diff --git a/libc/include/llvm-libc-types/time_t_64.h b/libc/include/llvm-libc-types/time_t_64.h
index 8f7fd3233646e..c8267abe31289 100644
--- a/libc/include/llvm-libc-types/time_t_64.h
+++ b/libc/include/llvm-libc-types/time_t_64.h
@@ -9,6 +9,12 @@
#ifndef LLVM_LIBC_TYPES_TIME_T_64_H
#define LLVM_LIBC_TYPES_TIME_T_64_H
+#if defined(__APPLE__)
+// Darwin provides its own definition for time_t. Include it directly
+// to ensure type compatibility and avoid redefinition errors.
+#include <sys/_types/_time_t.h>
+#else
typedef __INT64_TYPE__ time_t;
+#endif // __APPLE__
#endif // LLVM_LIBC_TYPES_TIME_T_64_H
diff --git a/libc/src/__support/time/darwin/CMakeLists.txt b/libc/src/__support/time/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..a06a41289a41c
--- /dev/null
+++ b/libc/src/__support/time/darwin/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_object_library(
+ clock_gettime
+ SRCS
+ clock_gettime.cpp
+ HDRS
+ ../clock_gettime.h
+ DEPENDS
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.hdr.types.struct_timeval
+ libc.hdr.types.struct_timespec
+)
diff --git a/libc/src/__support/time/darwin/clock_gettime.cpp b/libc/src/__support/time/darwin/clock_gettime.cpp
new file mode 100644
index 0000000000000..158737a6251a0
--- /dev/null
+++ b/libc/src/__support/time/darwin/clock_gettime.cpp
@@ -0,0 +1,44 @@
+//===-- Darwin implementation of internal clock_gettime -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/time/clock_gettime.h"
+#include "hdr/errno_macros.h" // For EINVAL
+#include "hdr/time_macros.h"
+#include "hdr/types/struct_timespec.h"
+#include "hdr/types/struct_timeval.h"
+#include "src/__support/OSUtil/syscall.h" // For syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include <sys/syscall.h> // For SYS_gettimeofday
+#include <sys/time.h> // For struct timezone
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+ErrorOr<int> clock_gettime(clockid_t clockid, struct timespec *ts) {
+ if (clockid != CLOCK_REALTIME) {
+ return Error(EINVAL);
+ }
+ struct timeval tv;
+ // The second argument to gettimeofday is a timezone pointer
+ // The third argument is mach_absolute_time
+ // Both of these, we don't need here, so they are 0
+ long ret = LIBC_NAMESPACE::syscall_impl<long>(
+ SYS_gettimeofday, reinterpret_cast<long>(&tv), 0, 0);
+ if (ret != 0) {
+ // The syscall returns -1 on error and sets errno.
+ return Error(EINVAL);
+ }
+
+ ts->tv_sec = tv.tv_sec;
+ ts->tv_nsec = tv.tv_usec * 1000;
+ return 0;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/darwin/CMakeLists.txt b/libc/src/time/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..6d68086c72584
--- /dev/null
+++ b/libc/src/time/darwin/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_entrypoint_object(
+ clock_gettime
+ SRCS
+ clock_gettime.cpp
+ HDRS
+ # The public header is part of the parent directory's library.
+ DEPENDS
+ libc.src.__support.time.clock_gettime
+ libc.src.errno.errno
+)
diff --git a/libc/src/time/darwin/clock_gettime.cpp b/libc/src/time/darwin/clock_gettime.cpp
new file mode 100644
index 0000000000000..f717d05451aca
--- /dev/null
+++ b/libc/src/time/darwin/clock_gettime.cpp
@@ -0,0 +1,29 @@
+//===---------- Darwin implementation of the POSIX clock_gettime function
+//--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/time/clock_gettime.h"
+
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/time/clock_gettime.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, clock_gettime,
+ (clockid_t clockid, struct timespec *ts)) {
+ auto result = internal::clock_gettime(clockid, ts);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/time/darwin/CMakeLists.txt b/libc/test/src/__support/time/darwin/CMakeLists.txt
new file mode 100644
index 0000000000000..ee1247b354173
--- /dev/null
+++ b/libc/test/src/__support/time/darwin/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_libc_test(
+ clock_gettime
+ SUITE libc-support-time-tests
+ SRCS clock_gettime.cpp
+ DEPENDS
+ libc.src.__support.CPP.expected
+ libc.src.__support.time.darwin.clock_gettime
+)
diff --git a/libc/test/src/__support/time/darwin/clock_gettime.cpp b/libc/test/src/__support/time/darwin/clock_gettime.cpp
new file mode 100644
index 0000000000000..d593c5d02744a
--- /dev/null
+++ b/libc/test/src/__support/time/darwin/clock_gettime.cpp
@@ -0,0 +1,20 @@
+//===-- unit tests for darwin's time utilities --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/time/clock_gettime.h"
+#include "src/__support/CPP/expected.h"
+#include "test/UnitTest/Test.h"
+
+template <class T, class E>
+using expected = LIBC_NAMESPACE::cpp::expected<T, E>;
+
+TEST(LlvmLibcSupportDarwinClockGetTime, BasicGetTime) {
+ struct timespec ts;
+ auto result = LIBC_NAMESPACE::internal::clock_gettime(CLOCK_REALTIME, &ts);
+ ASSERT_TRUE(result.has_value());
+}
>From 2d5ba2f69fd7a431d4b2fe45fc003c1d0b469c44 Mon Sep 17 00:00:00 2001
From: Shreeyash Pandey <shreeyash335 at gmail.com>
Date: Tue, 11 Nov 2025 19:56:55 +0530
Subject: [PATCH 2/2] [libc] fix minor nits
---
libc/src/__support/OSUtil/darwin/exit.cpp | 3 +--
libc/src/__support/time/darwin/clock_gettime.cpp | 6 ++----
libc/src/time/darwin/clock_gettime.cpp | 5 ++---
3 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/libc/src/__support/OSUtil/darwin/exit.cpp b/libc/src/__support/OSUtil/darwin/exit.cpp
index 7439db2ef38b0..a5fa4a7522189 100644
--- a/libc/src/__support/OSUtil/darwin/exit.cpp
+++ b/libc/src/__support/OSUtil/darwin/exit.cpp
@@ -15,9 +15,8 @@ namespace LIBC_NAMESPACE_DECL {
namespace internal {
[[noreturn]] void exit(int status) {
- for (;;) {
+ for (;;)
LIBC_NAMESPACE::syscall_impl<long>(SYS_exit, status);
- }
}
} // namespace internal
diff --git a/libc/src/__support/time/darwin/clock_gettime.cpp b/libc/src/__support/time/darwin/clock_gettime.cpp
index 158737a6251a0..aa483aa9a01d2 100644
--- a/libc/src/__support/time/darwin/clock_gettime.cpp
+++ b/libc/src/__support/time/darwin/clock_gettime.cpp
@@ -21,19 +21,17 @@ namespace LIBC_NAMESPACE_DECL {
namespace internal {
ErrorOr<int> clock_gettime(clockid_t clockid, struct timespec *ts) {
- if (clockid != CLOCK_REALTIME) {
+ if (clockid != CLOCK_REALTIME)
return Error(EINVAL);
- }
struct timeval tv;
// The second argument to gettimeofday is a timezone pointer
// The third argument is mach_absolute_time
// Both of these, we don't need here, so they are 0
long ret = LIBC_NAMESPACE::syscall_impl<long>(
SYS_gettimeofday, reinterpret_cast<long>(&tv), 0, 0);
- if (ret != 0) {
+ if (ret != 0)
// The syscall returns -1 on error and sets errno.
return Error(EINVAL);
- }
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec * 1000;
diff --git a/libc/src/time/darwin/clock_gettime.cpp b/libc/src/time/darwin/clock_gettime.cpp
index f717d05451aca..ecf116bbc5521 100644
--- a/libc/src/time/darwin/clock_gettime.cpp
+++ b/libc/src/time/darwin/clock_gettime.cpp
@@ -1,11 +1,10 @@
-//===---------- Darwin implementation of the POSIX clock_gettime function
-//--===//
+//===---- Darwin implementation of the POSIX clock_gettime function --===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
-//===----------------------------------------------------------------------===//
+//===-----------------------------------------------------------------===//
#include "src/time/clock_gettime.h"
More information about the libc-commits
mailing list