xref: /third_party/node/deps/uvwasi/src/clocks.c (revision 1cb0ef41)
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
110uvwasi_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
123uvwasi_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
136uvwasi_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
155uvwasi_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
168uvwasi_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