1 
2 // Copyright (C) 2023 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 #include <Windows.h>
16 #include <sys/time.h>
17 #include <time.h>
18 
19 #include <cassert>
20 #include <chrono>
21 #include <ctime>
22 #include <iostream>
23 #include <thread>
24 
25 #include "compat_compiler.h"
26 
27 ANDROID_BEGIN_HEADER
28 
29 typedef int clockid_t;
30 
clock_gettime(clockid_t clk_id,struct timespec * tp)31 int clock_gettime(clockid_t clk_id, struct timespec* tp) {
32     assert(clk_id == CLOCK_MONOTONIC);
33     auto now = std::chrono::steady_clock::now();
34     auto duration = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
35 
36     tp->tv_sec = static_cast<time_t>(duration.count());
37     tp->tv_nsec = static_cast<long>(
38         std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch() - duration)
39             .count());
40 
41     return 0;  // Success
42 }
43 
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)44 int nanosleep(const struct timespec* rqtp, struct timespec* rmtp) {
45     // Validate input
46     if (rqtp == NULL || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1'000'000'000) {
47         SetLastError(ERROR_INVALID_PARAMETER);
48         return -1;
49     }
50 
51     // Create a persistent thread local timer object
52     struct ThreadLocalTimerState {
53         ThreadLocalTimerState() {
54             timerHandle = CreateWaitableTimerEx(
55                 nullptr /* no security attributes */, nullptr /* no timer name */,
56                 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
57 
58             if (!timerHandle) {
59                 // Use an older version of waitable timer as backup.
60                 timerHandle = CreateWaitableTimer(nullptr, FALSE, nullptr);
61             }
62         }
63 
64         ~ThreadLocalTimerState() {
65             if (timerHandle) {
66                 CloseHandle(timerHandle);
67             }
68         }
69 
70         HANDLE timerHandle = 0;
71     };
72 
73     static thread_local ThreadLocalTimerState tl_timerInfo;
74 
75     // Convert timespec to FILETIME
76     ULARGE_INTEGER fileTime;
77     fileTime.QuadPart = static_cast<ULONGLONG>(rqtp->tv_sec) * 10'000'000 + rqtp->tv_nsec / 100;
78 
79     if (!tl_timerInfo.timerHandle) {
80         // Oh oh, for some reason we do not have a handle..
81         return -1;
82     }
83 
84     LARGE_INTEGER dueTime;
85     // Note: Negative values indicate relative time.
86     // (https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer)
87     dueTime.QuadPart = -static_cast<LONGLONG>(fileTime.QuadPart);
88 
89     if (!SetWaitableTimer(tl_timerInfo.timerHandle, &dueTime, 0, NULL, NULL, FALSE)) {
90         return -1;
91     }
92 
93     if (WaitForSingleObject(tl_timerInfo.timerHandle, INFINITE) != WAIT_OBJECT_0) {
94         return -1;  // Sleep interrupted or error
95     }
96 
97     // Calculate remaining time if needed
98     if (rmtp != NULL) {
99         // Get current time
100         FILETIME currentTime;
101         GetSystemTimeAsFileTime(&currentTime);
102 
103         // Calculate remaining time
104         ULARGE_INTEGER currentFileTime;
105         currentFileTime.LowPart = currentTime.dwLowDateTime;
106         currentFileTime.HighPart = currentTime.dwHighDateTime;
107 
108         ULONGLONG remainingTime = fileTime.QuadPart + currentFileTime.QuadPart;
109         rmtp->tv_sec = static_cast<time_t>(remainingTime / 10'000'000);
110         rmtp->tv_nsec = static_cast<long>((remainingTime % 10'000'000) * 100);
111     }
112 
113     return 0;
114 }
115 
gettimeofday(struct timeval * tp,void *)116 int gettimeofday(struct timeval* tp, void* /* tzp */) {
117     if (tp == nullptr) {
118         return -1;
119     }
120 
121     // Get the current time using std::chrono::system_clock
122     auto now = std::chrono::system_clock::now();
123     auto duration = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch());
124 
125     // Extract seconds and microseconds
126     tp->tv_sec = static_cast<long>(duration.count() / 1'000'000);
127     tp->tv_usec = static_cast<long>(duration.count() % 1'000'000);
128 
129     // Return success
130     return 0;
131 }
132 
usleep(int64_t usec)133 void usleep(int64_t usec) {
134     struct timespec req;
135     req.tv_sec = static_cast<time_t>(usec / 1'000'000);
136     req.tv_nsec = static_cast<long>((usec % 1'000'000) * 1000);
137 
138     nanosleep(&req, nullptr);
139 }
140 
sleep(unsigned int seconds)141 unsigned int sleep(unsigned int seconds) {
142     Sleep(seconds * 1000);
143     return 0;
144 }
145 
146 ANDROID_END_HEADER