1 #ifndef _WIN32
2 # include <errno.h>
3 # include <sys/time.h>
4 # include <sys/resource.h>
5 # include <time.h>
6 #endif /* _WIN32 */
7
8 #include "uv.h"
9 #include "clocks.h"
10 #include "wasi_types.h"
11 #include "uv_mapping.h"
12
13
14 #define UVWASI__WIN_TIME_AND_RETURN(handle, time) \
15 do { \
16 FILETIME create; \
17 FILETIME exit; \
18 FILETIME system; \
19 FILETIME user; \
20 SYSTEMTIME sys_system; \
21 SYSTEMTIME sys_user; \
22 if (0 == GetProcessTimes((handle), &create, &exit, &system, &user)) { \
23 return uvwasi__translate_uv_error( \
24 uv_translate_sys_error(GetLastError()) \
25 ); \
26 } \
27 \
28 if (0 == FileTimeToSystemTime(&system, &sys_system)) { \
29 return uvwasi__translate_uv_error( \
30 uv_translate_sys_error(GetLastError()) \
31 ); \
32 } \
33 \
34 if (0 == FileTimeToSystemTime(&user, &sys_user)) { \
35 return uvwasi__translate_uv_error( \
36 uv_translate_sys_error(GetLastError()) \
37 ); \
38 } \
39 \
40 (time) = (((sys_system.wHour * 3600) + (sys_system.wMinute * 60) + \
41 sys_system.wSecond) * NANOS_PER_SEC) + \
42 (sys_system.wMilliseconds * 1000000) + \
43 (((sys_user.wHour * 3600) + (sys_user.wMinute * 60) + \
44 sys_user.wSecond) * NANOS_PER_SEC) + \
45 (sys_user.wMilliseconds * 1000000); \
46 return UVWASI_ESUCCESS; \
47 } while (0)
48
49
50 #define UVWASI__CLOCK_GETTIME_AND_RETURN(clk, time) \
51 do { \
52 struct timespec ts; \
53 if (0 != clock_gettime((clk), &ts)) \
54 return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
55 (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
56 return UVWASI_ESUCCESS; \
57 } while (0)
58
59
60 #define UVWASI__GETRUSAGE_AND_RETURN(who, time) \
61 do { \
62 struct rusage ru; \
63 if (0 != getrusage((who), &ru)) \
64 return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
65 (time) = (ru.ru_utime.tv_sec * NANOS_PER_SEC) + \
66 (ru.ru_utime.tv_usec * 1000) + \
67 (ru.ru_stime.tv_sec * NANOS_PER_SEC) + \
68 (ru.ru_stime.tv_usec * 1000); \
69 return UVWASI_ESUCCESS; \
70 } while (0)
71
72
73 #define UVWASI__OSX_THREADTIME_AND_RETURN(time) \
74 do { \
75 mach_port_t thread; \
76 thread_basic_info_data_t info; \
77 mach_msg_type_number_t count; \
78 count = THREAD_BASIC_INFO_COUNT; \
79 thread = pthread_mach_thread_np(pthread_self()); \
80 if (KERN_SUCCESS != thread_info(thread, \
81 THREAD_BASIC_INFO, \
82 (thread_info_t) &info, \
83 &count)) { \
84 return UVWASI_ENOSYS; \
85 } \
86 (time) = (info.user_time.seconds * NANOS_PER_SEC) + \
87 (info.user_time.microseconds * 1000) + \
88 (info.system_time.seconds * NANOS_PER_SEC) + \
89 (info.system_time.microseconds * 1000); \
90 return UVWASI_ESUCCESS; \
91 } while (0)
92
93
94 #define UVWASI__WIN_GETRES_AND_RETURN(time) \
95 do { \
96 /* The GetProcessTimes() docs claim a resolution of 100 ns. */ \
97 (time) = 100; \
98 return UVWASI_ESUCCESS; \
99 } while (0)
100
101
102 #define UVWASI__CLOCK_GETRES_AND_RETURN(clk, time) \
103 do { \
104 struct timespec ts; \
105 /* Try calling clock_getres(). If it doesn't succeed, then default to \
106 1000000. We implement all of the clocks, and some platforms (such as \
107 SmartOS) don't support all of the clocks, even though they define \
108 the constants for them. */ \
109 if (0 != clock_getres((clk), &ts)) \
110 (time) = 1000000; \
111 else \
112 (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
113 return UVWASI_ESUCCESS; \
114 } while (0)
115
116
117 #define UVWASI__SLOW_GETRES_AND_RETURN(time) \
118 do { \
119 /* Assume a "worst case" of 1000000 ns resolution. */ \
120 (time) = 1000000; \
121 return UVWASI_ESUCCESS; \
122 } while (0)
123
124
uvwasi__clock_gettime_realtime(uvwasi_timestamp_t * time)125 uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time) {
126 uv_timeval64_t tv;
127 int r;
128
129 r = uv_gettimeofday(&tv);
130 if (r != 0)
131 return uvwasi__translate_uv_error(r);
132
133 *time = (tv.tv_sec * NANOS_PER_SEC) + (tv.tv_usec * 1000);
134 return UVWASI_ESUCCESS;
135 }
136
137
uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t * time)138 uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time) {
139 #if defined(_WIN32)
140 UVWASI__WIN_TIME_AND_RETURN(GetCurrentProcess(), *time);
141 #elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
142 !defined(__APPLE__) && \
143 !defined(__sun)
144 UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
145 #else
146 UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_SELF, *time);
147 #endif
148 }
149
150
uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t * time)151 uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time) {
152 #if defined(_WIN32)
153 UVWASI__WIN_TIME_AND_RETURN(GetCurrentThread(), *time);
154 #elif defined(__APPLE__)
155 UVWASI__OSX_THREADTIME_AND_RETURN(*time);
156 #elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun) && !defined(__PASE__)
157 UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
158 #else
159 # if defined(RUSAGE_LWP)
160 UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_LWP, *time);
161 # elif defined(RUSAGE_THREAD)
162 UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_THREAD, *time);
163 # else
164 return UVWASI_ENOSYS;
165 # endif /* RUSAGE_LWP */
166 #endif
167 }
168
169
uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t * time)170 uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time) {
171 #if defined(_WIN32)
172 UVWASI__WIN_GETRES_AND_RETURN(*time);
173 #elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
174 !defined(__APPLE__) && \
175 !defined(__sun)
176 UVWASI__CLOCK_GETRES_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
177 #else
178 UVWASI__SLOW_GETRES_AND_RETURN(*time);
179 #endif
180 }
181
182
uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t * time)183 uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time) {
184 #if defined(_WIN32)
185 UVWASI__WIN_GETRES_AND_RETURN(*time);
186 #elif defined(__APPLE__)
187 UVWASI__SLOW_GETRES_AND_RETURN(*time);
188 #elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun) && !defined(__PASE__)
189 UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
190 #elif defined(RUSAGE_THREAD) || defined(RUSAGE_LWP)
191 UVWASI__SLOW_GETRES_AND_RETURN(*time);
192 #else
193 return UVWASI_ENOSYS;
194 #endif
195 }
196