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