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) = (((uvwasi_timestamp_t)(sys_system.wHour * 3600) +                \
41               (sys_system.wMinute * 60) + sys_system.wSecond) * NANOS_PER_SEC) + \
42              ((uvwasi_timestamp_t)(sys_system.wMilliseconds) * 1000000) +     \
43              (((uvwasi_timestamp_t)(sys_user.wHour * 3600) +                  \
44               (sys_user.wMinute * 60) + sys_user.wSecond) * NANOS_PER_SEC) +  \
45              ((uvwasi_timestamp_t)(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) = ((uvwasi_timestamp_t)(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) = ((uvwasi_timestamp_t)(ru.ru_utime.tv_sec) * NANOS_PER_SEC) +     \
66              (ru.ru_utime.tv_usec * 1000) +                                   \
67              ((uvwasi_timestamp_t)(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) = ((uvwasi_timestamp_t)(info.user_time.seconds) * NANOS_PER_SEC) + \
87              (info.user_time.microseconds * 1000) +                           \
88              ((uvwasi_timestamp_t)(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) = ((uvwasi_timestamp_t)(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