time.c (6193B)
1 #include <inttypes.h> 2 #include <limits.h> 3 #include <stdbool.h> 4 #include <string.h> 5 #include <time.h> 6 7 #include <uv.h> 8 9 #include "auto/config.h" 10 #include "nvim/event/loop.h" 11 #include "nvim/event/multiqueue.h" 12 #include "nvim/gettext_defs.h" 13 #include "nvim/globals.h" 14 #include "nvim/log.h" 15 #include "nvim/main.h" 16 #include "nvim/memory.h" 17 #include "nvim/os/input.h" 18 #include "nvim/os/os.h" 19 #include "nvim/os/time.h" 20 21 #include "os/time.c.generated.h" 22 23 /// Gets a high-resolution (nanosecond), monotonically-increasing time relative 24 /// to an arbitrary time in the past. 25 /// 26 /// Not related to the time of day and therefore not subject to clock drift. 27 /// 28 /// @return Relative time value with nanosecond precision. 29 uint64_t os_hrtime(void) 30 FUNC_ATTR_WARN_UNUSED_RESULT 31 { 32 return uv_hrtime(); 33 } 34 35 /// Gets a millisecond-resolution, monotonically-increasing time relative to an 36 /// arbitrary time in the past. 37 /// 38 /// Not related to the time of day and therefore not subject to clock drift. 39 /// The value is cached by the loop, it will not change until the next 40 /// loop-tick (unless uv_update_time is called). 41 /// 42 /// @return Relative time value with millisecond precision. 43 uint64_t os_now(void) 44 FUNC_ATTR_WARN_UNUSED_RESULT 45 { 46 return uv_now(&main_loop.uv); 47 } 48 49 /// Sleeps for `ms` milliseconds. 50 /// 51 /// @see uv_sleep() (libuv v1.34.0) 52 /// 53 /// @param ms Number of milliseconds to sleep 54 /// @param ignoreinput If true, only SIGINT (CTRL-C) can interrupt. 55 void os_delay(uint64_t ms, bool ignoreinput) 56 { 57 DLOG("%" PRIu64 " ms", ms); 58 if (ms > INT_MAX) { 59 ms = INT_MAX; 60 } 61 LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)ms, 62 ignoreinput ? got_int : os_input_ready(NULL)); 63 } 64 65 /// Sleeps for `ms` milliseconds without checking for events or interrupts. 66 /// 67 /// This blocks even "fast" events which is quite disruptive. This should only 68 /// be used in debug code. Prefer os_delay() and decide if the delay should be 69 /// interrupted by input or only a CTRL-C. 70 /// 71 /// @see uv_sleep() (libuv v1.34.0) 72 /// 73 /// @param us Number of microseconds to sleep. 74 void os_sleep(uint64_t ms) 75 { 76 if (ms > UINT_MAX) { 77 ms = UINT_MAX; 78 } 79 uv_sleep((unsigned)ms); 80 } 81 82 // Cache of the current timezone name as retrieved from TZ, or an empty string 83 // where unset, up to 64 octets long including trailing null byte. 84 static char tz_cache[64]; 85 86 /// Portable version of POSIX localtime_r() 87 /// 88 /// @return NULL in case of error 89 struct tm *os_localtime_r(const time_t *restrict clock, 90 struct tm *restrict result) FUNC_ATTR_NONNULL_ALL 91 { 92 #ifdef UNIX 93 // POSIX provides localtime_r() as a thread-safe version of localtime(). 94 // 95 // Check to see if the environment variable TZ has changed since the last run. 96 // Call tzset(3) to update the global timezone variables if it has. 97 // POSIX standard doesn't require localtime_r() implementations to do that 98 // as it does with localtime(), and we don't want to call tzset() every time. 99 const char *tz = os_getenv_noalloc("TZ"); 100 if (!tz) { 101 tz = ""; 102 } 103 if (strncmp(tz_cache, tz, sizeof(tz_cache) - 1) != 0) { 104 tzset(); 105 xstrlcpy(tz_cache, tz, sizeof(tz_cache)); 106 } 107 return localtime_r(clock, result); // NOLINT(runtime/threadsafe_fn) 108 #else 109 // Windows version of localtime() is thread-safe. 110 // See http://msdn.microsoft.com/en-us/library/bf12f0hc%28VS.80%29.aspx 111 struct tm *local_time = localtime(clock); // NOLINT(runtime/threadsafe_fn) 112 if (!local_time) { 113 return NULL; 114 } 115 *result = *local_time; 116 return result; 117 #endif 118 } 119 120 /// Gets the current Unix timestamp and adjusts it to local time. 121 /// 122 /// @param result Pointer to a 'struct tm' where the result should be placed 123 /// @return A pointer to a 'struct tm' in the current time zone (the 'result' 124 /// argument) or NULL in case of error 125 struct tm *os_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL 126 { 127 time_t rawtime = time(NULL); 128 return os_localtime_r(&rawtime, result); 129 } 130 131 /// Portable version of POSIX ctime_r() 132 /// 133 /// @param clock[in] 134 /// @param result[out] Pointer to a 'char' where the result should be placed 135 /// @param result_len length of result buffer 136 /// @return human-readable string of current local time 137 char *os_ctime_r(const time_t *restrict clock, char *restrict result, size_t result_len, 138 bool add_newline) 139 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 140 { 141 struct tm clock_local; 142 struct tm *clock_local_ptr = os_localtime_r(clock, &clock_local); 143 // MSVC returns NULL for an invalid value of seconds. 144 if (clock_local_ptr == NULL) { 145 xstrlcpy(result, _("(Invalid)"), result_len - 1); 146 } else { 147 // xgettext:no-c-format 148 if (strftime(result, result_len - 1, _("%a %b %d %H:%M:%S %Y"), clock_local_ptr) == 0) { 149 // Quoting "man strftime": 150 // > If the length of the result string (including the terminating 151 // > null byte) would exceed max bytes, then strftime() returns 0, 152 // > and the contents of the array are undefined. 153 xstrlcpy(result, _("(Invalid)"), result_len - 1); 154 } 155 } 156 if (add_newline) { 157 xstrlcat(result, "\n", result_len); 158 } 159 return result; 160 } 161 162 /// Gets the current Unix timestamp and adjusts it to local time. 163 /// 164 /// @param result[out] Pointer to a 'char' where the result should be placed 165 /// @param result_len length of result buffer 166 /// @return human-readable string of current local time 167 char *os_ctime(char *result, size_t result_len, bool add_newline) 168 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET 169 { 170 time_t rawtime = time(NULL); 171 return os_ctime_r(&rawtime, result, result_len, add_newline); 172 } 173 174 /// Portable version of POSIX strptime() 175 /// 176 /// @param str[in] string to convert 177 /// @param format[in] format to parse "str" 178 /// @param tm[out] time representation of "str" 179 /// @return Pointer to first unprocessed character or NULL 180 char *os_strptime(const char *str, const char *format, struct tm *tm) 181 FUNC_ATTR_NONNULL_ALL 182 { 183 #ifdef HAVE_STRPTIME 184 return strptime(str, format, tm); 185 #else 186 return NULL; 187 #endif 188 } 189 190 /// Obtains the current Unix timestamp. 191 /// 192 /// @return Seconds since epoch. 193 Timestamp os_time(void) 194 FUNC_ATTR_WARN_UNUSED_RESULT 195 { 196 return (Timestamp)time(NULL); 197 }