]>
Commit | Line | Data |
---|---|---|
320054e8 DG |
1 | // Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ |
2 | // | |
3 | // SPDX-License-Identifier: BSD-2-Clause | |
4 | ||
5 | #ifndef COMMON_TIME_H | |
6 | #define COMMON_TIME_H | |
7 | ||
8 | #include <common/limits.h> | |
320054e8 DG |
9 | |
10 | #include <sys/time.h> | |
11 | ||
446cb3f1 | 12 | #include <wasi/api.h> |
320054e8 DG |
13 | #include <stdbool.h> |
14 | #include <time.h> | |
15 | ||
16 | #define NSEC_PER_SEC 1000000000 | |
17 | ||
320054e8 DG |
18 | static inline bool timespec_to_timestamp_exact( |
19 | const struct timespec *timespec, __wasi_timestamp_t *timestamp) { | |
20 | // Invalid nanoseconds field. | |
21 | if (timespec->tv_nsec < 0 || timespec->tv_nsec >= NSEC_PER_SEC) | |
22 | return false; | |
23 | ||
24 | // Timestamps before the Epoch are not supported. | |
25 | if (timespec->tv_sec < 0) | |
26 | return false; | |
27 | ||
28 | // Make sure our timestamp does not overflow. | |
60f221a4 DG |
29 | return !__builtin_mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) && |
30 | !__builtin_add_overflow(*timestamp, timespec->tv_nsec, timestamp); | |
320054e8 DG |
31 | } |
32 | ||
33 | static inline bool timespec_to_timestamp_clamp( | |
34 | const struct timespec *timespec, __wasi_timestamp_t *timestamp) { | |
35 | // Invalid nanoseconds field. | |
36 | if (timespec->tv_nsec < 0 || timespec->tv_nsec >= NSEC_PER_SEC) | |
37 | return false; | |
38 | ||
39 | if (timespec->tv_sec < 0) { | |
40 | // Timestamps before the Epoch are not supported. | |
41 | *timestamp = 0; | |
60f221a4 DG |
42 | } else if (__builtin_mul_overflow(timespec->tv_sec, NSEC_PER_SEC, timestamp) || |
43 | __builtin_add_overflow(*timestamp, timespec->tv_nsec, timestamp)) { | |
320054e8 DG |
44 | // Make sure our timestamp does not overflow. |
45 | *timestamp = NUMERIC_MAX(__wasi_timestamp_t); | |
46 | } | |
47 | return true; | |
48 | } | |
49 | ||
50 | static inline struct timespec timestamp_to_timespec( | |
51 | __wasi_timestamp_t timestamp) { | |
52 | // Decompose timestamp into seconds and nanoseconds. | |
53 | return (struct timespec){.tv_sec = timestamp / NSEC_PER_SEC, | |
54 | .tv_nsec = timestamp % NSEC_PER_SEC}; | |
55 | } | |
56 | ||
57 | static inline struct timeval timestamp_to_timeval( | |
58 | __wasi_timestamp_t timestamp) { | |
59 | struct timespec ts = timestamp_to_timespec(timestamp); | |
60 | return (struct timeval){.tv_sec = ts.tv_sec, ts.tv_nsec / 1000}; | |
61 | } | |
62 | ||
63 | #endif |