• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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