Rusty Russell
9 years ago
8 changed files with 1253 additions and 1 deletions
@ -0,0 +1 @@ |
|||
../../licenses/BSD-MIT |
@ -0,0 +1,57 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* time - routines for dealing with time |
|||
* |
|||
* This code provides convenient functions for working with time, in the |
|||
* form of 'struct timerel' for durations and 'struct timeabs' for timestamps |
|||
* which are light wrappers around struct timespec. |
|||
* |
|||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|||
* License: BSD-MIT |
|||
* |
|||
* Example: |
|||
* #include <ccan/time/time.h> |
|||
* #include <stdlib.h> |
|||
* #include <stdio.h> |
|||
* #include <err.h> |
|||
* |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* struct timeabs t; |
|||
* |
|||
* if (argc != 2) |
|||
* errx(1, "Usage: %s <diff in millisec>", argv[0]); |
|||
* |
|||
* t = time_now(); |
|||
* if (argv[1][0] == '-') |
|||
* t = timeabs_sub(t, time_from_msec(atol(argv[1]+1))); |
|||
* else |
|||
* t = timeabs_add(t, time_from_msec(atol(argv[1]))); |
|||
* |
|||
* printf("%lu.%09u\n", |
|||
* (unsigned long)t.ts.tv_sec, (unsigned)t.ts.tv_nsec); |
|||
* return 0; |
|||
* } |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Expect exactly one argument */ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
return 0; |
|||
} |
|||
|
|||
#if HAVE_CLOCK_GETTIME_IN_LIBRT |
|||
if (strcmp(argv[1], "libs") == 0) { |
|||
printf("rt\n"); |
|||
return 0; |
|||
} |
|||
#endif |
|||
|
|||
return 1; |
|||
} |
@ -0,0 +1,204 @@ |
|||
#define DEBUG |
|||
#include <ccan/time/time.h> |
|||
#include <ccan/time/time.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <unistd.h> |
|||
#include <stdlib.h> |
|||
#include <signal.h> |
|||
#include <sys/types.h> |
|||
#include <sys/wait.h> |
|||
|
|||
/* If we really abort, we don't get coverage info! */ |
|||
void abort(void) |
|||
{ |
|||
exit(7); |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
struct timeabs t1, t2, epoch = { { 0, 0 } }; |
|||
struct timerel t3, t4, zero = { { 0, 0 } }; |
|||
int fds[2]; |
|||
|
|||
plan_tests(64); |
|||
|
|||
/* Test time_now */ |
|||
t1 = time_now(); |
|||
t2 = time_now(); |
|||
|
|||
/* Test time_between. */ |
|||
t3 = time_between(t2, t1); |
|||
ok1(t3.ts.tv_sec > 0 || t3.ts.tv_nsec >= 0); |
|||
t3 = time_between(t2, t2); |
|||
ok1(t3.ts.tv_sec == 0 && t3.ts.tv_nsec == 0); |
|||
t3 = time_between(t1, t1); |
|||
ok1(t3.ts.tv_sec == 0 && t3.ts.tv_nsec == 0); |
|||
|
|||
/* Test timeabs_eq / timerel_eq */ |
|||
ok1(timeabs_eq(t1, t1)); |
|||
ok1(timeabs_eq(t2, t2)); |
|||
ok1(!timeabs_eq(t1, epoch)); |
|||
ok1(!timeabs_eq(t2, epoch)); |
|||
t3.ts.tv_sec = 1; |
|||
ok1(timerel_eq(t3, t3)); |
|||
ok1(!timerel_eq(t3, zero)); |
|||
|
|||
/* Make sure t2 > t1. */ |
|||
t3.ts.tv_sec = 0; |
|||
t3.ts.tv_nsec = 1; |
|||
t2 = timeabs_add(t2, t3); |
|||
|
|||
/* Test time_before and time_after. */ |
|||
ok1(!timeabs_eq(t1, t2)); |
|||
ok1(!time_after(t1, t2)); |
|||
ok1(time_before(t1, t2)); |
|||
ok1(time_after(t2, t1)); |
|||
ok1(!time_before(t2, t1)); |
|||
t3.ts.tv_sec = 0; |
|||
t3.ts.tv_nsec = 999999999; |
|||
t2 = timeabs_add(t2, t3); |
|||
ok1(!timeabs_eq(t1, t2)); |
|||
ok1(!time_after(t1, t2)); |
|||
ok1(time_before(t1, t2)); |
|||
ok1(time_after(t2, t1)); |
|||
ok1(!time_before(t2, t1)); |
|||
|
|||
t3 = time_between(t2, epoch); |
|||
ok1(t2.ts.tv_sec == t3.ts.tv_sec && t2.ts.tv_nsec == t3.ts.tv_nsec); |
|||
t3 = time_between(t2, t2); |
|||
ok1(timerel_eq(t3, zero)); |
|||
|
|||
/* time_from_msec / time_to_msec */ |
|||
t3 = time_from_msec(500); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_msec(t3) == 500); |
|||
|
|||
t3 = time_from_msec(1000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_msec(t3) == 1000); |
|||
|
|||
t3 = time_from_msec(1500); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_msec(t3) == 1500); |
|||
|
|||
/* time_from_usec */ |
|||
t3 = time_from_usec(500000); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_usec(t3) == 500000); |
|||
|
|||
t3 = time_from_usec(1000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_usec(t3) == 1000000); |
|||
|
|||
t3 = time_from_usec(1500000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_usec(t3) == 1500000); |
|||
|
|||
/* time_from_nsec */ |
|||
t3 = time_from_nsec(500000000); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_nsec(t3) == 500000000); |
|||
|
|||
t3 = time_from_nsec(1000000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_nsec(t3) == 1000000000); |
|||
|
|||
t3 = time_from_nsec(1500000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_nsec(t3) == 1500000000); |
|||
|
|||
/* Test wrapunder */ |
|||
t1 = timeabs_sub(timeabs_sub(t2, time_from_msec(500)), |
|||
time_from_msec(500)); |
|||
ok1(t1.ts.tv_sec == t2.ts.tv_sec - 1); |
|||
ok1(t1.ts.tv_nsec == t2.ts.tv_nsec); |
|||
|
|||
/* time_divide and time_multiply */ |
|||
t4.ts.tv_nsec = 100; |
|||
t4.ts.tv_sec = 100; |
|||
|
|||
t3 = time_divide(t4, 2); |
|||
ok1(t3.ts.tv_sec == 50); |
|||
ok1(t3.ts.tv_nsec == 50); |
|||
|
|||
t3 = time_divide(t4, 100); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 1); |
|||
|
|||
t3 = time_multiply(t3, 100); |
|||
ok1(timerel_eq(t3, t4)); |
|||
|
|||
t3 = time_divide(t4, 200); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
|
|||
/* Divide by huge number. */ |
|||
t4.ts.tv_sec = (1U << 31) - 1; |
|||
t4.ts.tv_nsec = 999999999; |
|||
t3 = time_divide(t4, 1 << 30); |
|||
/* Allow us to round either way. */ |
|||
ok1((t3.ts.tv_sec == 2 && t3.ts.tv_nsec == 0) |
|||
|| (t3.ts.tv_sec == 1 && t3.ts.tv_nsec == 999999999)); |
|||
|
|||
/* Multiply by huge number. */ |
|||
t4.ts.tv_sec = 0; |
|||
t4.ts.tv_nsec = 1; |
|||
t3 = time_multiply(t4, 1UL << 31); |
|||
ok1(t3.ts.tv_sec == 2); |
|||
ok1(t3.ts.tv_nsec == 147483648); |
|||
|
|||
pipe(fds); |
|||
|
|||
fflush(stdout); |
|||
switch (fork()) { |
|||
case 0: |
|||
close(fds[0]); |
|||
dup2(fds[1], 1); |
|||
dup2(fds[1], 2); |
|||
t1.ts.tv_sec = 7; |
|||
t1.ts.tv_nsec = 1000000001; |
|||
t2 = timeabs_check(t1, NULL); |
|||
if (t2.ts.tv_sec != 8 || t2.ts.tv_nsec != 1) |
|||
exit(1); |
|||
t1.ts.tv_sec = -1; |
|||
t1.ts.tv_nsec = 5; |
|||
t2 = timeabs_check(t1, NULL); |
|||
if (t2.ts.tv_sec != 0 || t2.ts.tv_nsec != 5) |
|||
exit(1); |
|||
t1.ts.tv_sec = 8; |
|||
t1.ts.tv_nsec = 1000000002; |
|||
/* We expect this to abort! */ |
|||
t2 = timeabs_check(t1, "abortstr"); |
|||
exit(1); |
|||
|
|||
default: { |
|||
char readbuf[1024]; |
|||
int r, len = 0; |
|||
|
|||
close(fds[1]); |
|||
while ((r = read(fds[0], readbuf + len, 1023 - len)) > 0) |
|||
len += r; |
|||
readbuf[len] = '\0'; |
|||
ok1(strcmp(readbuf, |
|||
"WARNING: malformed time" |
|||
" 7 seconds 1000000001 ns converted to 8.000000001.\n" |
|||
"WARNING: malformed time" |
|||
" -1 seconds 5 ns converted to 0.000000005.\n" |
|||
"abortstr: malformed time 8.1000000002\n") == 0); |
|||
ok1(wait(&r) != -1); |
|||
ok1(WIFEXITED(r)); |
|||
ok1(WEXITSTATUS(r) == 7); |
|||
} |
|||
} |
|||
|
|||
return exit_status(); |
|||
} |
@ -0,0 +1,24 @@ |
|||
#include <ccan/time/time.h> |
|||
#include <ccan/time/time.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
struct timemono t1, t2; |
|||
struct timerel t3; |
|||
|
|||
plan_tests(2); |
|||
|
|||
/* Test time_mono */ |
|||
t1 = time_mono(); |
|||
t2 = time_mono(); |
|||
|
|||
ok1(!time_less_(t2.ts, t1.ts)); |
|||
|
|||
t3.ts.tv_sec = 1; |
|||
t3.ts.tv_nsec = 0; |
|||
|
|||
ok1(time_less(timemono_between(t1, t2), t3)); |
|||
|
|||
return exit_status(); |
|||
} |
@ -0,0 +1,163 @@ |
|||
#include <ccan/time/time.h> |
|||
#include <ccan/time/time.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
struct timeabs t1, t2; |
|||
struct timerel t3, t4, zero = { { 0, 0 } }; |
|||
|
|||
plan_tests(66); |
|||
|
|||
/* Test time_now */ |
|||
t1 = time_now(); |
|||
t2 = time_now(); |
|||
|
|||
/* Test time_between. */ |
|||
t3 = time_between(t2, t1); |
|||
ok1(t3.ts.tv_sec > 0 || t3.ts.tv_nsec >= 0); |
|||
t3 = time_between(t2, t2); |
|||
ok1(t3.ts.tv_sec == 0 && t3.ts.tv_nsec == 0); |
|||
t3 = time_between(t1, t1); |
|||
ok1(t3.ts.tv_sec == 0 && t3.ts.tv_nsec == 0); |
|||
|
|||
/* Test timeabs_eq / timerel_eq */ |
|||
ok1(timeabs_eq(t1, t1)); |
|||
ok1(timeabs_eq(t2, t2)); |
|||
t3.ts.tv_sec = 0; |
|||
t3.ts.tv_nsec = 1; |
|||
ok1(!timerel_eq(t3, zero)); |
|||
ok1(!timerel_eq(t3, zero)); |
|||
|
|||
/* Make sure t2 > t1. */ |
|||
t2 = timeabs_add(t2, t3); |
|||
|
|||
/* Test time_after and time_before. */ |
|||
ok1(!timeabs_eq(t1, t2)); |
|||
ok1(!time_after(t1, t2)); |
|||
ok1(time_before(t1, t2)); |
|||
ok1(time_after(t2, t1)); |
|||
ok1(!time_before(t2, t1)); |
|||
t3.ts.tv_sec = 0; |
|||
t3.ts.tv_nsec = 999999999; |
|||
t2 = timeabs_add(t2, t3); |
|||
ok1(!timeabs_eq(t1, t2)); |
|||
ok1(!time_after(t1, t2)); |
|||
ok1(time_before(t1, t2)); |
|||
ok1(time_after(t2, t1)); |
|||
ok1(!time_before(t2, t1)); |
|||
|
|||
/* Test time_less and time_greater. */ |
|||
ok1(time_less(zero, t3)); |
|||
ok1(!time_greater(zero, t3)); |
|||
ok1(!time_less(t3, zero)); |
|||
ok1(time_greater(t3, zero)); |
|||
|
|||
/* Test time_sub */ |
|||
t3 = time_sub(t3, t3); |
|||
ok1(timerel_eq(t3, zero)); |
|||
|
|||
/* Test time_between */ |
|||
t3 = time_between(t2, t2); |
|||
ok1(timerel_eq(t3, zero)); |
|||
t3.ts.tv_sec = 0; |
|||
t3.ts.tv_nsec = 999999999; |
|||
t1 = timeabs_add(t2, t3); |
|||
t3 = time_between(t1, t2); |
|||
ok1(t3.ts.tv_sec == 0 && t3.ts.tv_nsec == 999999999); |
|||
|
|||
/* time_from_sec / time_to_sec */ |
|||
t3 = time_from_sec(500); |
|||
ok1(t3.ts.tv_sec == 500); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_sec(t3) == 500); |
|||
|
|||
/* time_from_msec / time_to_msec */ |
|||
t3 = time_from_msec(500); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_msec(t3) == 500); |
|||
|
|||
t3 = time_from_msec(1000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_msec(t3) == 1000); |
|||
|
|||
t3 = time_from_msec(1500); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_msec(t3) == 1500); |
|||
|
|||
/* time_from_usec */ |
|||
t3 = time_from_usec(500000); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_usec(t3) == 500000); |
|||
|
|||
t3 = time_from_usec(1000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_usec(t3) == 1000000); |
|||
|
|||
t3 = time_from_usec(1500000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_usec(t3) == 1500000); |
|||
|
|||
/* time_from_nsec */ |
|||
t3 = time_from_nsec(500000000); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_nsec(t3) == 500000000); |
|||
|
|||
t3 = time_from_nsec(1000000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 0); |
|||
ok1(time_to_nsec(t3) == 1000000000); |
|||
|
|||
t3 = time_from_nsec(1500000000); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
ok1(time_to_nsec(t3) == 1500000000); |
|||
|
|||
/* Test wrapunder */ |
|||
t1 = timeabs_sub(timeabs_sub(t2, time_from_msec(500)), time_from_msec(500)); |
|||
ok1(t1.ts.tv_sec == t2.ts.tv_sec - 1); |
|||
ok1(t1.ts.tv_nsec == t2.ts.tv_nsec); |
|||
|
|||
/* time_divide and time_multiply */ |
|||
t4.ts.tv_nsec = 100; |
|||
t4.ts.tv_sec = 100; |
|||
|
|||
t3 = time_divide(t4, 2); |
|||
ok1(t3.ts.tv_sec == 50); |
|||
ok1(t3.ts.tv_nsec == 50); |
|||
|
|||
t3 = time_divide(t4, 100); |
|||
ok1(t3.ts.tv_sec == 1); |
|||
ok1(t3.ts.tv_nsec == 1); |
|||
|
|||
t3 = time_multiply(t3, 100); |
|||
ok1(timerel_eq(t3, t4)); |
|||
|
|||
t3 = time_divide(t4, 200); |
|||
ok1(t3.ts.tv_sec == 0); |
|||
ok1(t3.ts.tv_nsec == 500000000); |
|||
|
|||
/* Divide by huge number. */ |
|||
t4.ts.tv_sec = (1U << 31) - 1; |
|||
t4.ts.tv_nsec = 999999999; |
|||
t3 = time_divide(t4, 1 << 30); |
|||
/* Allow us to round either way. */ |
|||
ok1((t3.ts.tv_sec == 2 && t3.ts.tv_nsec == 0) |
|||
|| (t3.ts.tv_sec == 1 && t3.ts.tv_nsec == 999999999)); |
|||
|
|||
/* Multiply by huge number. */ |
|||
t4.ts.tv_sec = 0; |
|||
t4.ts.tv_nsec = 1; |
|||
t3 = time_multiply(t4, 1UL << 31); |
|||
ok1(t3.ts.tv_sec == 2); |
|||
ok1(t3.ts.tv_nsec == 147483648); |
|||
|
|||
return exit_status(); |
|||
} |
@ -0,0 +1,130 @@ |
|||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|||
#include <ccan/time/time.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#if !HAVE_CLOCK_GETTIME |
|||
#include <sys/time.h> |
|||
|
|||
struct timeabs time_now(void) |
|||
{ |
|||
struct timeval now; |
|||
struct timeabs ret; |
|||
gettimeofday(&now, NULL); |
|||
ret.ts.tv_sec = now.tv_sec; |
|||
ret.ts.tv_nsec = now.tv_usec * 1000; |
|||
return TIMEABS_CHECK(ret); |
|||
} |
|||
#else |
|||
#include <time.h> |
|||
struct timeabs time_now(void) |
|||
{ |
|||
struct timeabs ret; |
|||
clock_gettime(CLOCK_REALTIME, &ret.ts); |
|||
return TIMEABS_CHECK(ret); |
|||
} |
|||
#endif /* HAVE_CLOCK_GETTIME */ |
|||
|
|||
struct timemono time_mono(void) |
|||
{ |
|||
struct timemono ret; |
|||
#ifdef TIME_HAVE_MONOTONIC |
|||
clock_gettime(CLOCK_MONOTONIC, &ret.ts); |
|||
#else /* Best we can do */ |
|||
ret.ts = time_now().ts; |
|||
#endif /* !HAVE_TIME_MONOTONIC */ |
|||
return ret; |
|||
} |
|||
|
|||
struct timerel time_divide(struct timerel t, unsigned long div) |
|||
{ |
|||
struct timerel res; |
|||
uint64_t rem, ns; |
|||
|
|||
/* Dividing seconds is simple. */ |
|||
res.ts.tv_sec = TIMEREL_CHECK(t).ts.tv_sec / div; |
|||
rem = t.ts.tv_sec % div; |
|||
|
|||
/* If we can't fit remainder * 1,000,000,000 in 64 bits? */ |
|||
#if 0 /* ilog is great, but we use fp for multiply anyway. */
|
|||
bits = ilog64(rem); |
|||
if (bits + 30 >= 64) { |
|||
/* Reduce accuracy slightly */ |
|||
rem >>= (bits - (64 - 30)); |
|||
div >>= (bits - (64 - 30)); |
|||
} |
|||
#endif |
|||
if (rem & ~(((uint64_t)1 << 30) - 1)) { |
|||
/* FIXME: fp is cheating! */ |
|||
double nsec = rem * 1000000000.0 + t.ts.tv_nsec; |
|||
res.ts.tv_nsec = nsec / div; |
|||
} else { |
|||
ns = rem * 1000000000 + t.ts.tv_nsec; |
|||
res.ts.tv_nsec = ns / div; |
|||
} |
|||
return TIMEREL_CHECK(res); |
|||
} |
|||
|
|||
struct timerel time_multiply(struct timerel t, unsigned long mult) |
|||
{ |
|||
struct timerel res; |
|||
|
|||
/* Are we going to overflow if we multiply nsec? */ |
|||
if (mult & ~((1UL << 30) - 1)) { |
|||
/* FIXME: fp is cheating! */ |
|||
double nsec = (double)t.ts.tv_nsec * mult; |
|||
|
|||
res.ts.tv_sec = nsec / 1000000000.0; |
|||
res.ts.tv_nsec = nsec - (res.ts.tv_sec * 1000000000.0); |
|||
} else { |
|||
uint64_t nsec = t.ts.tv_nsec * mult; |
|||
|
|||
res.ts.tv_nsec = nsec % 1000000000; |
|||
res.ts.tv_sec = nsec / 1000000000; |
|||
} |
|||
res.ts.tv_sec += TIMEREL_CHECK(t).ts.tv_sec * mult; |
|||
return TIMEREL_CHECK(res); |
|||
} |
|||
|
|||
struct timespec time_check_(struct timespec t, const char *abortstr) |
|||
{ |
|||
if (t.tv_sec < 0 || t.tv_nsec >= 1000000000) { |
|||
if (abortstr) { |
|||
fprintf(stderr, "%s: malformed time %li.%09li\n", |
|||
abortstr, |
|||
(long)t.tv_sec, (long)t.tv_nsec); |
|||
abort(); |
|||
} else { |
|||
struct timespec old = t; |
|||
|
|||
if (t.tv_nsec >= 1000000000) { |
|||
t.tv_sec += t.tv_nsec / 1000000000; |
|||
t.tv_nsec %= 1000000000; |
|||
} |
|||
if (t.tv_sec < 0) |
|||
t.tv_sec = 0; |
|||
|
|||
fprintf(stderr, "WARNING: malformed time" |
|||
" %li seconds %li ns converted to %li.%09li.\n", |
|||
(long)old.tv_sec, (long)old.tv_nsec, |
|||
(long)t.tv_sec, (long)t.tv_nsec); |
|||
} |
|||
} |
|||
return t; |
|||
} |
|||
|
|||
struct timerel timerel_check(struct timerel t, const char *abortstr) |
|||
{ |
|||
struct timerel ret; |
|||
|
|||
ret.ts = time_check_(t.ts, abortstr); |
|||
return ret; |
|||
} |
|||
|
|||
struct timeabs timeabs_check(struct timeabs t, const char *abortstr) |
|||
{ |
|||
struct timeabs ret; |
|||
|
|||
ret.ts = time_check_(t.ts, abortstr); |
|||
return ret; |
|||
} |
@ -0,0 +1,669 @@ |
|||
/* Licensed under BSD-MIT - see LICENSE file for details */ |
|||
#ifndef CCAN_TIME_H |
|||
#define CCAN_TIME_H |
|||
#include "config.h" |
|||
#include <sys/time.h> |
|||
#if HAVE_STRUCT_TIMESPEC |
|||
#include <time.h> |
|||
#else |
|||
struct timespec { |
|||
time_t tv_sec; /* seconds */ |
|||
long tv_nsec; /* nanoseconds */ |
|||
}; |
|||
#endif |
|||
#include <stdint.h> |
|||
#include <stdbool.h> |
|||
|
|||
#ifdef DEBUG |
|||
#include <ccan/str/str.h> |
|||
#define TIME_CHECK(t) \ |
|||
time_check_((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ") |
|||
#define TIMEREL_CHECK(t) \ |
|||
timerel_check((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ") |
|||
#define TIMEABS_CHECK(t) \ |
|||
timeabs_check((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ") |
|||
#else |
|||
#define TIME_CHECK(t) (t) |
|||
#define TIMEREL_CHECK(t) (t) |
|||
#define TIMEABS_CHECK(t) (t) |
|||
#endif |
|||
|
|||
/**
|
|||
* struct timerel - a relative time. |
|||
* @ts: the actual timespec value. |
|||
* |
|||
* For example, 1 second: ts.tv_sec = 1, ts.tv_nsec = 0 |
|||
*/ |
|||
struct timerel { |
|||
struct timespec ts; |
|||
}; |
|||
|
|||
/**
|
|||
* struct timeabs - an absolue time. |
|||
* @ts: the actual timespec value. |
|||
* |
|||
* For example, Midnight UTC January 1st, 1970: ts.tv_sec = 0, ts.tv_nsec = 0 |
|||
*/ |
|||
struct timeabs { |
|||
struct timespec ts; |
|||
}; |
|||
|
|||
/**
|
|||
* struct timemono - a monotonic time. |
|||
* @ts: the actual timespec value. |
|||
* |
|||
* This comes from the monotonic clock (if available), so it's useful |
|||
* for measuring intervals as it won't change even if the system clock |
|||
* is moved for some reason. |
|||
*/ |
|||
struct timemono { |
|||
struct timespec ts; |
|||
}; |
|||
|
|||
/**
|
|||
* TIME_HAVE_MONOTONIC - defined if we really have a monotonic clock. |
|||
* |
|||
* Otherwise time_mono() just refers to time_now(). Your code might |
|||
* test this if you really need a monotonic clock. |
|||
*/ |
|||
#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) |
|||
#define TIME_HAVE_MONOTONIC 1 |
|||
#endif |
|||
|
|||
struct timespec time_check_(struct timespec in, const char *abortstr); |
|||
|
|||
/**
|
|||
* timerel_check - check if a relative time is malformed. |
|||
* @in: the relative time to check (returned) |
|||
* @abortstr: the string to print to stderr before aborting (if set). |
|||
* |
|||
* This can be used to make sure a time isn't negative and doesn't |
|||
* have a tv_nsec >= 1000000000. If it is, and @abortstr is non-NULL, |
|||
* that will be printed and abort() is called. Otherwise, if |
|||
* @abortstr is NULL then the returned timerel will be normalized and |
|||
* tv_sec set to 0 if it was negative. |
|||
* |
|||
* Note that if ccan/time is compiled with DEBUG, then it will call this |
|||
* for all passed and returned times. |
|||
* |
|||
* Example: |
|||
* printf("Time to calc this was %lu nanoseconds\n", |
|||
* (long)timerel_check(time_between(time_now(), time_now()), |
|||
* "time_now() failed?").ts.tv_nsec); |
|||
*/ |
|||
struct timerel timerel_check(struct timerel in, const char *abortstr); |
|||
|
|||
/**
|
|||
* timeabs_check - check if an absolute time is malformed. |
|||
* @in: the relative time to check (returned) |
|||
* @abortstr: the string to print to stderr before aborting (if set). |
|||
* |
|||
* This can be used to make sure a time isn't negative and doesn't |
|||
* have a tv_nsec >= 1000000000. If it is, and @abortstr is non-NULL, |
|||
* that will be printed and abort() is called. Otherwise, if |
|||
* @abortstr is NULL then the returned timeabs will be normalized and |
|||
* tv_sec set to 0 if it was negative. |
|||
* |
|||
* Note that if ccan/time is compiled with DEBUG, then it will call this |
|||
* for all passed and returned times. |
|||
* |
|||
* Example: |
|||
* printf("Now is %lu seconds since epoch\n", |
|||
* (long)timeabs_check(time_now(), "time_now failed?").ts.tv_sec); |
|||
*/ |
|||
struct timeabs timeabs_check(struct timeabs in, const char *abortstr); |
|||
|
|||
/**
|
|||
* time_now - return the current time |
|||
* |
|||
* Example: |
|||
* printf("Now is %lu seconds since epoch\n", (long)time_now().ts.tv_sec); |
|||
*/ |
|||
struct timeabs time_now(void); |
|||
|
|||
/**
|
|||
* time_mono - return the current monotonic time |
|||
* |
|||
* This value is only really useful for measuring time intervals. |
|||
* |
|||
* See also: |
|||
* time_since() |
|||
*/ |
|||
struct timemono time_mono(void); |
|||
|
|||
static inline bool time_greater_(struct timespec a, struct timespec b) |
|||
{ |
|||
if (TIME_CHECK(a).tv_sec > TIME_CHECK(b).tv_sec) |
|||
return true; |
|||
else if (a.tv_sec < b.tv_sec) |
|||
return false; |
|||
|
|||
return a.tv_nsec > b.tv_nsec; |
|||
} |
|||
|
|||
/**
|
|||
* time_after - is a after b? |
|||
* @a: one abstime. |
|||
* @b: another abstime. |
|||
* |
|||
* Example: |
|||
* static bool timed_out(const struct timeabs *start) |
|||
* { |
|||
* #define TIMEOUT time_from_msec(1000) |
|||
* return time_after(time_now(), timeabs_add(*start, TIMEOUT)); |
|||
* } |
|||
*/ |
|||
static inline bool time_after(struct timeabs a, struct timeabs b) |
|||
{ |
|||
return time_greater_(a.ts, b.ts); |
|||
} |
|||
|
|||
/**
|
|||
* time_greater - is a greater than b? |
|||
* @a: one reltime. |
|||
* @b: another reltime. |
|||
*/ |
|||
static inline bool time_greater(struct timerel a, struct timerel b) |
|||
{ |
|||
return time_greater_(a.ts, b.ts); |
|||
} |
|||
|
|||
static inline bool time_less_(struct timespec a, struct timespec b) |
|||
{ |
|||
if (TIME_CHECK(a).tv_sec < TIME_CHECK(b).tv_sec) |
|||
return true; |
|||
else if (a.tv_sec > b.tv_sec) |
|||
return false; |
|||
|
|||
return a.tv_nsec < b.tv_nsec; |
|||
} |
|||
|
|||
/**
|
|||
* time_before - is a before b? |
|||
* @a: one absolute time. |
|||
* @b: another absolute time. |
|||
* |
|||
* Example: |
|||
* static bool still_valid(const struct timeabs *start) |
|||
* { |
|||
* #define TIMEOUT time_from_msec(1000) |
|||
* return time_before(time_now(), timeabs_add(*start, TIMEOUT)); |
|||
* } |
|||
*/ |
|||
static inline bool time_before(struct timeabs a, struct timeabs b) |
|||
{ |
|||
return time_less_(a.ts, b.ts); |
|||
} |
|||
|
|||
/**
|
|||
* time_less - is a before b? |
|||
* @a: one relative time. |
|||
* @b: another relative time. |
|||
*/ |
|||
static inline bool time_less(struct timerel a, struct timerel b) |
|||
{ |
|||
return time_less_(a.ts, b.ts); |
|||
} |
|||
|
|||
/**
|
|||
* timeabs_eq - is a equal to b? |
|||
* @a: one absolute time. |
|||
* @b: another absolute time. |
|||
* |
|||
* Example: |
|||
* #include <sys/types.h> |
|||
* #include <sys/wait.h> |
|||
* |
|||
* // Can we fork in under a nanosecond?
|
|||
* static bool fast_fork(void) |
|||
* { |
|||
* struct timeabs start = time_now(); |
|||
* if (fork() != 0) { |
|||
* exit(0); |
|||
* } |
|||
* wait(NULL); |
|||
* return timeabs_eq(start, time_now()); |
|||
* } |
|||
*/ |
|||
static inline bool timeabs_eq(struct timeabs a, struct timeabs b) |
|||
{ |
|||
return TIMEABS_CHECK(a).ts.tv_sec == TIMEABS_CHECK(b).ts.tv_sec |
|||
&& a.ts.tv_nsec == b.ts.tv_nsec; |
|||
} |
|||
|
|||
/**
|
|||
* timerel_eq - is a equal to b? |
|||
* @a: one relative time. |
|||
* @b: another relative time. |
|||
* |
|||
* Example: |
|||
* #include <sys/types.h> |
|||
* #include <sys/wait.h> |
|||
* |
|||
* // Can we fork in under a nanosecond?
|
|||
* static bool fast_fork(void) |
|||
* { |
|||
* struct timeabs start = time_now(); |
|||
* struct timerel diff, zero = { .ts = { 0, 0 } }; |
|||
* if (fork() != 0) { |
|||
* exit(0); |
|||
* } |
|||
* wait(NULL); |
|||
* diff = time_between(time_now(), start); |
|||
* return timerel_eq(diff, zero); |
|||
* } |
|||
*/ |
|||
static inline bool timerel_eq(struct timerel a, struct timerel b) |
|||
{ |
|||
return TIMEREL_CHECK(a).ts.tv_sec == TIMEREL_CHECK(b).ts.tv_sec |
|||
&& a.ts.tv_nsec == b.ts.tv_nsec; |
|||
} |
|||
|
|||
static inline struct timespec time_sub_(struct timespec recent, |
|||
struct timespec old) |
|||
{ |
|||
struct timespec diff; |
|||
|
|||
diff.tv_sec = TIME_CHECK(recent).tv_sec - TIME_CHECK(old).tv_sec; |
|||
if (old.tv_nsec > recent.tv_nsec) { |
|||
diff.tv_sec--; |
|||
diff.tv_nsec = 1000000000 + recent.tv_nsec - old.tv_nsec; |
|||
} else |
|||
diff.tv_nsec = recent.tv_nsec - old.tv_nsec; |
|||
|
|||
return TIME_CHECK(diff); |
|||
} |
|||
|
|||
/**
|
|||
* time_sub - subtract two relative times |
|||
* @a: the larger time. |
|||
* @b: the smaller time. |
|||
* |
|||
* This returns a well formed struct timerel of @a - @b. |
|||
*/ |
|||
static inline struct timerel time_sub(struct timerel a, struct timerel b) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts = time_sub_(a.ts, b.ts); |
|||
return t; |
|||
} |
|||
|
|||
/**
|
|||
* time_between - time between two absolute times |
|||
* @recent: the larger time. |
|||
* @old: the smaller time. |
|||
* |
|||
* This returns a well formed struct timerel of @a - @b. |
|||
*/ |
|||
static inline struct timerel time_between(struct timeabs recent, struct timeabs old) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts = time_sub_(recent.ts, old.ts); |
|||
return t; |
|||
} |
|||
|
|||
/**
|
|||
* timemono_between - time between two monotonic times |
|||
* @recent: the larger time. |
|||
* @old: the smaller time. |
|||
* |
|||
* This returns a well formed struct timerel of @recent - @old. |
|||
*/ |
|||
static inline struct timerel timemono_between(struct timemono recent, |
|||
struct timemono old) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts = time_sub_(recent.ts, old.ts); |
|||
return t; |
|||
} |
|||
|
|||
/**
|
|||
* timeabs_sub - subtract a relative time from an absolute time |
|||
* @abs: the absolute time. |
|||
* @rel: the relative time. |
|||
* |
|||
* This returns a well formed struct timeabs of @a - @b. |
|||
* |
|||
* Example: |
|||
* // We do one every second.
|
|||
* static struct timeabs previous_time(void) |
|||
* { |
|||
* return timeabs_sub(time_now(), time_from_msec(1000)); |
|||
* } |
|||
*/ |
|||
static inline struct timeabs timeabs_sub(struct timeabs abs, struct timerel rel) |
|||
{ |
|||
struct timeabs t; |
|||
|
|||
t.ts = time_sub_(abs.ts, rel.ts); |
|||
return t; |
|||
} |
|||
|
|||
static inline struct timespec time_add_(struct timespec a, struct timespec b) |
|||
{ |
|||
struct timespec sum; |
|||
|
|||
sum.tv_sec = TIME_CHECK(a).tv_sec + TIME_CHECK(b).tv_sec; |
|||
sum.tv_nsec = a.tv_nsec + b.tv_nsec; |
|||
if (sum.tv_nsec >= 1000000000) { |
|||
sum.tv_sec++; |
|||
sum.tv_nsec -= 1000000000; |
|||
} |
|||
return TIME_CHECK(sum); |
|||
} |
|||
|
|||
/**
|
|||
* timeabs_add - add a relative to an absolute time |
|||
* @a: the absolute time. |
|||
* @b: a relative time. |
|||
* |
|||
* The times must not overflow, or the results are undefined. |
|||
* |
|||
* Example: |
|||
* // We do one every second.
|
|||
* static struct timeabs next_time(void) |
|||
* { |
|||
* return timeabs_add(time_now(), time_from_msec(1000)); |
|||
* } |
|||
*/ |
|||
static inline struct timeabs timeabs_add(struct timeabs a, struct timerel b) |
|||
{ |
|||
struct timeabs t; |
|||
|
|||
t.ts = time_add_(a.ts, b.ts); |
|||
return t; |
|||
} |
|||
|
|||
/**
|
|||
* timerel_add - add two relative times |
|||
* @a: one relative time. |
|||
* @b: another relative time. |
|||
* |
|||
* The times must not overflow, or the results are undefined. |
|||
* |
|||
* Example: |
|||
* static struct timerel double_time(struct timerel a) |
|||
* { |
|||
* return timerel_add(a, a); |
|||
* } |
|||
*/ |
|||
static inline struct timerel timerel_add(struct timerel a, struct timerel b) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts = time_add_(a.ts, b.ts); |
|||
return t; |
|||
} |
|||
|
|||
/**
|
|||
* time_divide - divide a time by a value. |
|||
* @t: a time. |
|||
* @div: number to divide it by. |
|||
* |
|||
* Example: |
|||
* // How long does it take to do a fork?
|
|||
* static struct timerel forking_time(void) |
|||
* { |
|||
* struct timeabs start = time_now(); |
|||
* unsigned int i; |
|||
* |
|||
* for (i = 0; i < 1000; i++) { |
|||
* if (fork() != 0) { |
|||
* exit(0); |
|||
* } |
|||
* wait(NULL); |
|||
* } |
|||
* return time_divide(time_between(time_now(), start), i); |
|||
* } |
|||
*/ |
|||
struct timerel time_divide(struct timerel t, unsigned long div); |
|||
|
|||
/**
|
|||
* time_multiply - multiply a time by a value. |
|||
* @t: a relative time. |
|||
* @mult: number to multiply it by. |
|||
* |
|||
* Example: |
|||
* ... |
|||
* printf("Time to do 100000 forks would be %u sec\n", |
|||
* (unsigned)time_multiply(forking_time(), 1000000).ts.tv_sec); |
|||
*/ |
|||
struct timerel time_multiply(struct timerel t, unsigned long mult); |
|||
|
|||
/**
|
|||
* time_to_sec - return number of seconds |
|||
* @t: a time |
|||
* |
|||
* It's often more convenient to deal with time values as seconds. |
|||
* Note that this will fit into an unsigned 32-bit variable if it's a |
|||
* time of less than about 136 years. |
|||
* |
|||
* Example: |
|||
* ... |
|||
* printf("Forking time is %u sec\n", |
|||
* (unsigned)time_to_sec(forking_time())); |
|||
*/ |
|||
static inline uint64_t time_to_sec(struct timerel t) |
|||
{ |
|||
return t.ts.tv_sec; |
|||
} |
|||
|
|||
/**
|
|||
* time_to_msec - return number of milliseconds |
|||
* @t: a relative time |
|||
* |
|||
* It's often more convenient to deal with time values as |
|||
* milliseconds. Note that this will fit into a 32-bit variable if |
|||
* it's a time difference of less than ~7 weeks. |
|||
* |
|||
* Example: |
|||
* ... |
|||
* printf("Forking time is %u msec\n", |
|||
* (unsigned)time_to_msec(forking_time())); |
|||
*/ |
|||
static inline uint64_t time_to_msec(struct timerel t) |
|||
{ |
|||
uint64_t msec; |
|||
|
|||
msec = TIMEREL_CHECK(t).ts.tv_nsec/1000000 + (uint64_t)t.ts.tv_sec*1000; |
|||
return msec; |
|||
} |
|||
|
|||
/**
|
|||
* time_to_usec - return number of microseconds |
|||
* @t: a relative time |
|||
* |
|||
* It's often more convenient to deal with time values as |
|||
* microseconds. Note that this will fit into a 32-bit variable if |
|||
* it's a time difference of less than ~1 hour. |
|||
* |
|||
* Example: |
|||
* ... |
|||
* printf("Forking time is %u usec\n", |
|||
* (unsigned)time_to_usec(forking_time())); |
|||
* |
|||
*/ |
|||
static inline uint64_t time_to_usec(struct timerel t) |
|||
{ |
|||
uint64_t usec; |
|||
|
|||
usec = TIMEREL_CHECK(t).ts.tv_nsec/1000 + (uint64_t)t.ts.tv_sec*1000000; |
|||
return usec; |
|||
} |
|||
|
|||
/**
|
|||
* time_to_nsec - return number of nanoseconds |
|||
* @t: a relative time |
|||
* |
|||
* It's sometimes more convenient to deal with time values as |
|||
* nanoseconds. Note that this will fit into a 32-bit variable if |
|||
* it's a time difference of less than ~4 seconds. |
|||
* |
|||
* Example: |
|||
* ... |
|||
* printf("Forking time is %u nsec\n", |
|||
* (unsigned)time_to_nsec(forking_time())); |
|||
* |
|||
*/ |
|||
static inline uint64_t time_to_nsec(struct timerel t) |
|||
{ |
|||
uint64_t nsec; |
|||
|
|||
nsec = TIMEREL_CHECK(t).ts.tv_nsec + (uint64_t)t.ts.tv_sec * 1000000000; |
|||
return nsec; |
|||
} |
|||
|
|||
/**
|
|||
* time_from_sec - convert seconds to a relative time |
|||
* @msec: time in seconds |
|||
* |
|||
* Example: |
|||
* // 1 minute timeout
|
|||
* #define TIMEOUT time_from_sec(60) |
|||
*/ |
|||
static inline struct timerel time_from_sec(uint64_t sec) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts.tv_nsec = 0; |
|||
t.ts.tv_sec = sec; |
|||
return TIMEREL_CHECK(t); |
|||
} |
|||
|
|||
/**
|
|||
* time_from_msec - convert milliseconds to a relative time |
|||
* @msec: time in milliseconds |
|||
* |
|||
* Example: |
|||
* // 1/2 second timeout
|
|||
* #define TIMEOUT time_from_msec(500) |
|||
*/ |
|||
static inline struct timerel time_from_msec(uint64_t msec) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts.tv_nsec = (msec % 1000) * 1000000; |
|||
t.ts.tv_sec = msec / 1000; |
|||
return TIMEREL_CHECK(t); |
|||
} |
|||
|
|||
/**
|
|||
* time_from_usec - convert microseconds to a relative time |
|||
* @usec: time in microseconds |
|||
* |
|||
* Example: |
|||
* // 1/2 second timeout
|
|||
* #define TIMEOUT time_from_usec(500000) |
|||
*/ |
|||
static inline struct timerel time_from_usec(uint64_t usec) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts.tv_nsec = (usec % 1000000) * 1000; |
|||
t.ts.tv_sec = usec / 1000000; |
|||
return TIMEREL_CHECK(t); |
|||
} |
|||
|
|||
/**
|
|||
* time_from_nsec - convert nanoseconds to a relative time |
|||
* @nsec: time in nanoseconds |
|||
* |
|||
* Example: |
|||
* // 1/2 second timeout
|
|||
* #define TIMEOUT time_from_nsec(500000000) |
|||
*/ |
|||
static inline struct timerel time_from_nsec(uint64_t nsec) |
|||
{ |
|||
struct timerel t; |
|||
|
|||
t.ts.tv_nsec = nsec % 1000000000; |
|||
t.ts.tv_sec = nsec / 1000000000; |
|||
return TIMEREL_CHECK(t); |
|||
} |
|||
|
|||
static inline struct timeval timespec_to_timeval(struct timespec ts) |
|||
{ |
|||
struct timeval tv; |
|||
tv.tv_sec = ts.tv_sec; |
|||
tv.tv_usec = ts.tv_nsec / 1000; |
|||
return tv; |
|||
} |
|||
|
|||
/**
|
|||
* timerel_to_timeval - convert a relative time to a timeval. |
|||
* @t: a relative time. |
|||
* |
|||
* Example: |
|||
* struct timerel t = { { 100, 0 } }; // 100 seconds
|
|||
* struct timeval tv; |
|||
* |
|||
* tv = timerel_to_timeval(t); |
|||
* printf("time = %lu.%06u\n", (long)tv.tv_sec, (int)tv.tv_usec); |
|||
*/ |
|||
static inline struct timeval timerel_to_timeval(struct timerel t) |
|||
{ |
|||
return timespec_to_timeval(t.ts); |
|||
} |
|||
|
|||
/**
|
|||
* timeabs_to_timeval - convert an absolute time to a timeval. |
|||
* @t: an absolute time. |
|||
* |
|||
* Example: |
|||
* struct timeval tv; |
|||
* |
|||
* tv = timeabs_to_timeval(time_now()); |
|||
* printf("time = %lu.%06u\n", (long)tv.tv_sec, (int)tv.tv_usec); |
|||
*/ |
|||
static inline struct timeval timeabs_to_timeval(struct timeabs t) |
|||
{ |
|||
return timespec_to_timeval(t.ts); |
|||
} |
|||
|
|||
static inline struct timespec timeval_to_timespec(struct timeval tv) |
|||
{ |
|||
struct timespec ts; |
|||
ts.tv_sec = tv.tv_sec; |
|||
ts.tv_nsec = tv.tv_usec * 1000; |
|||
return ts; |
|||
} |
|||
|
|||
/**
|
|||
* timeval_to_timerel - convert a timeval to a relative time. |
|||
* @tv: a timeval. |
|||
* |
|||
* Example: |
|||
* struct timeval tv = { 0, 500 }; |
|||
* struct timerel t; |
|||
* |
|||
* t = timeval_to_timerel(tv); |
|||
* printf("timerel = %lu.%09lu\n", (long)t.ts.tv_sec, (long)t.ts.tv_nsec); |
|||
*/ |
|||
static inline struct timerel timeval_to_timerel(struct timeval tv) |
|||
{ |
|||
struct timerel t; |
|||
t.ts = timeval_to_timespec(tv); |
|||
return TIMEREL_CHECK(t); |
|||
} |
|||
|
|||
/**
|
|||
* timeval_to_timeabs - convert a timeval to an absolute time. |
|||
* @tv: a timeval. |
|||
* |
|||
* Example: |
|||
* struct timeval tv = { 1401762008, 500 }; |
|||
* struct timeabs t; |
|||
* |
|||
* t = timeval_to_timeabs(tv); |
|||
* printf("timeabs = %lu.%09lu\n", (long)t.ts.tv_sec, (long)t.ts.tv_nsec); |
|||
*/ |
|||
static inline struct timeabs timeval_to_timeabs(struct timeval tv) |
|||
{ |
|||
struct timeabs t; |
|||
t.ts = timeval_to_timespec(tv); |
|||
return TIMEABS_CHECK(t); |
|||
} |
|||
#endif /* CCAN_TIME_H */ |
Loading…
Reference in new issue