xref: /llvm-project/libc/src/__support/time/linux/clock_gettime.cpp (revision e6cf5d2863b77895ae7183952514bedd9e8dde16)
1 //===--- clock_gettime linux implementation ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/__support/time/clock_gettime.h"
10 #include "hdr/types/clockid_t.h"
11 #include "hdr/types/struct_timespec.h"
12 #include "src/__support/OSUtil/linux/vdso.h"
13 #include "src/__support/OSUtil/syscall.h"
14 #include "src/__support/common.h"
15 #include "src/__support/error_or.h"
16 #include "src/__support/macros/config.h"
17 #include <sys/syscall.h>
18 
19 #if defined(SYS_clock_gettime64)
20 #include <linux/time_types.h>
21 #endif
22 
23 namespace LIBC_NAMESPACE_DECL {
24 namespace internal {
25 ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) {
26   using namespace vdso;
27   int ret;
28 #if defined(SYS_clock_gettime)
29   TypedSymbol<VDSOSym::ClockGetTime> clock_gettime;
30   if (LIBC_LIKELY(clock_gettime != nullptr))
31     ret = clock_gettime(clockid, ts);
32   else
33     ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_gettime,
34                                             static_cast<long>(clockid),
35                                             reinterpret_cast<long>(ts));
36 #elif defined(SYS_clock_gettime64)
37   static_assert(
38       sizeof(time_t) == sizeof(int64_t),
39       "SYS_clock_gettime64 requires struct timespec with 64-bit members.");
40 
41   TypedSymbol<VDSOSym::ClockGetTime64> clock_gettime64;
42   __kernel_timespec ts64{};
43   if (LIBC_LIKELY(clock_gettime64 != nullptr))
44     ret = clock_gettime64(clockid, &ts64);
45   else
46     ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_gettime64,
47                                             static_cast<long>(clockid),
48                                             reinterpret_cast<long>(&ts64));
49   if (ret == 0) {
50     ts->tv_sec = static_cast<decltype(ts->tv_sec)>(ts64.tv_sec);
51     ts->tv_nsec = static_cast<decltype(ts->tv_nsec)>(ts64.tv_nsec);
52   }
53 #else
54 #error "SYS_clock_gettime and SYS_clock_gettime64 syscalls not available."
55 #endif
56   if (ret < 0)
57     return Error(-ret);
58   return ret;
59 }
60 
61 } // namespace internal
62 } // namespace LIBC_NAMESPACE_DECL
63