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