Refactor time_* into nstime_*.

Use a single uint64_t in nstime_t to store nanoseconds rather than using
struct timespec.  This reduces fragility around conversions between long
and uint64_t, especially missing casts that only cause problems on
32-bit platforms.
This commit is contained in:
Jason Evans 2016-02-21 11:25:02 -08:00
parent 788d29d397
commit 9bad079039
17 changed files with 526 additions and 557 deletions

View File

@ -78,15 +78,31 @@ LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix)
# Lists of files. # Lists of files.
BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof
C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h
C_SRCS := $(srcroot)src/jemalloc.c $(srcroot)src/arena.c \ C_SRCS := $(srcroot)src/jemalloc.c \
$(srcroot)src/atomic.c $(srcroot)src/base.c $(srcroot)src/bitmap.c \ $(srcroot)src/arena.c \
$(srcroot)src/chunk.c $(srcroot)src/chunk_dss.c \ $(srcroot)src/atomic.c \
$(srcroot)src/chunk_mmap.c $(srcroot)src/ckh.c $(srcroot)src/ctl.c \ $(srcroot)src/base.c \
$(srcroot)src/extent.c $(srcroot)src/hash.c $(srcroot)src/huge.c \ $(srcroot)src/bitmap.c \
$(srcroot)src/mb.c $(srcroot)src/mutex.c $(srcroot)src/pages.c \ $(srcroot)src/chunk.c \
$(srcroot)src/prng.c $(srcroot)src/prof.c $(srcroot)src/quarantine.c \ $(srcroot)src/chunk_dss.c \
$(srcroot)src/rtree.c $(srcroot)src/stats.c $(srcroot)src/tcache.c \ $(srcroot)src/chunk_mmap.c \
$(srcroot)src/ticker.c $(srcroot)src/time.c $(srcroot)src/tsd.c \ $(srcroot)src/ckh.c \
$(srcroot)src/ctl.c \
$(srcroot)src/extent.c \
$(srcroot)src/hash.c \
$(srcroot)src/huge.c \
$(srcroot)src/mb.c \
$(srcroot)src/mutex.c \
$(srcroot)src/nstime.c \
$(srcroot)src/pages.c \
$(srcroot)src/prng.c \
$(srcroot)src/prof.c \
$(srcroot)src/quarantine.c \
$(srcroot)src/rtree.c \
$(srcroot)src/stats.c \
$(srcroot)src/tcache.c \
$(srcroot)src/ticker.c \
$(srcroot)src/tsd.c \
$(srcroot)src/util.c $(srcroot)src/util.c
ifeq ($(enable_valgrind), 1) ifeq ($(enable_valgrind), 1)
C_SRCS += $(srcroot)src/valgrind.c C_SRCS += $(srcroot)src/valgrind.c
@ -117,7 +133,7 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \
$(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
$(srcroot)test/src/thd.c $(srcroot)test/src/timer.c $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/time.c $(srcroot)src/util.c C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c
TESTS_UNIT := $(srcroot)test/unit/atomic.c \ TESTS_UNIT := $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/bitmap.c \
$(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/ckh.c \
@ -148,7 +164,7 @@ TESTS_UNIT := $(srcroot)test/unit/atomic.c \
$(srcroot)test/unit/smoothstep.c \ $(srcroot)test/unit/smoothstep.c \
$(srcroot)test/unit/stats.c \ $(srcroot)test/unit/stats.c \
$(srcroot)test/unit/ticker.c \ $(srcroot)test/unit/ticker.c \
$(srcroot)test/unit/time.c \ $(srcroot)test/unit/nstime.c \
$(srcroot)test/unit/tsd.c \ $(srcroot)test/unit/tsd.c \
$(srcroot)test/unit/util.c \ $(srcroot)test/unit/util.c \
$(srcroot)test/unit/zero.c $(srcroot)test/unit/zero.c

View File

@ -395,7 +395,7 @@ struct arena_s {
*/ */
ssize_t decay_time; ssize_t decay_time;
/* decay_time / SMOOTHSTEP_NSTEPS. */ /* decay_time / SMOOTHSTEP_NSTEPS. */
struct timespec decay_interval; nstime_t decay_interval;
/* /*
* Time at which the current decay interval logically started. We do * Time at which the current decay interval logically started. We do
* not actually advance to a new epoch until sometime after it starts * not actually advance to a new epoch until sometime after it starts
@ -403,7 +403,7 @@ struct arena_s {
* to completely skip epochs. In all cases, during epoch advancement we * to completely skip epochs. In all cases, during epoch advancement we
* merge all relevant activity into the most recently recorded epoch. * merge all relevant activity into the most recently recorded epoch.
*/ */
struct timespec decay_epoch; nstime_t decay_epoch;
/* decay_deadline randomness generator. */ /* decay_deadline randomness generator. */
uint64_t decay_jitter_state; uint64_t decay_jitter_state;
/* /*
@ -413,7 +413,7 @@ struct arena_s {
* decay_interval, but we randomize the deadline to reduce the * decay_interval, but we randomize the deadline to reduce the
* likelihood of arenas purging in lockstep. * likelihood of arenas purging in lockstep.
*/ */
struct timespec decay_deadline; nstime_t decay_deadline;
/* /*
* Number of dirty pages at beginning of current epoch. During epoch * Number of dirty pages at beginning of current epoch. During epoch
* advancement we use the delta between decay_ndirty and ndirty to * advancement we use the delta between decay_ndirty and ndirty to

View File

@ -356,7 +356,7 @@ typedef unsigned szind_t;
# define VARIABLE_ARRAY(type, name, count) type name[(count)] # define VARIABLE_ARRAY(type, name, count) type name[(count)]
#endif #endif
#include "jemalloc/internal/time.h" #include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
@ -387,7 +387,7 @@ typedef unsigned szind_t;
/******************************************************************************/ /******************************************************************************/
#define JEMALLOC_H_STRUCTS #define JEMALLOC_H_STRUCTS
#include "jemalloc/internal/time.h" #include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
@ -477,7 +477,7 @@ void jemalloc_prefork(void);
void jemalloc_postfork_parent(void); void jemalloc_postfork_parent(void);
void jemalloc_postfork_child(void); void jemalloc_postfork_child(void);
#include "jemalloc/internal/time.h" #include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"
@ -508,7 +508,7 @@ void jemalloc_postfork_child(void);
/******************************************************************************/ /******************************************************************************/
#define JEMALLOC_H_INLINES #define JEMALLOC_H_INLINES
#include "jemalloc/internal/time.h" #include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/valgrind.h"
#include "jemalloc/internal/util.h" #include "jemalloc/internal/util.h"
#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/atomic.h"

View File

@ -0,0 +1,48 @@
/******************************************************************************/
#ifdef JEMALLOC_H_TYPES
#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
&& _POSIX_MONOTONIC_CLOCK >= 0
typedef struct nstime_s nstime_t;
/* Maximum supported number of seconds (~584 years). */
#define NSTIME_SEC_MAX 18446744072
#endif /* JEMALLOC_H_TYPES */
/******************************************************************************/
#ifdef JEMALLOC_H_STRUCTS
struct nstime_s {
uint64_t ns;
};
#endif /* JEMALLOC_H_STRUCTS */
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
void nstime_init(nstime_t *time, uint64_t ns);
void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec);
uint64_t nstime_ns(const nstime_t *time);
uint64_t nstime_sec(const nstime_t *time);
uint64_t nstime_nsec(const nstime_t *time);
void nstime_copy(nstime_t *time, const nstime_t *source);
int nstime_compare(const nstime_t *a, const nstime_t *b);
void nstime_add(nstime_t *time, const nstime_t *addend);
void nstime_subtract(nstime_t *time, const nstime_t *subtrahend);
void nstime_imultiply(nstime_t *time, uint64_t multiplier);
void nstime_idivide(nstime_t *time, uint64_t divisor);
uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor);
#ifdef JEMALLOC_JET
typedef bool (nstime_update_t)(nstime_t *);
extern nstime_update_t *nstime_update;
#else
bool nstime_update(nstime_t *time);
#endif
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
#ifdef JEMALLOC_H_INLINES
#endif /* JEMALLOC_H_INLINES */
/******************************************************************************/

View File

@ -327,6 +327,19 @@ narenas_tdata_cleanup
narenas_total_get narenas_total_get
ncpus ncpus
nhbins nhbins
nstime_add
nstime_compare
nstime_copy
nstime_divide
nstime_idivide
nstime_imultiply
nstime_init
nstime_init2
nstime_ns
nstime_nsec
nstime_sec
nstime_subtract
nstime_update
opt_abort opt_abort
opt_decay_time opt_decay_time
opt_dss opt_dss
@ -484,17 +497,6 @@ ticker_init
ticker_read ticker_read
ticker_tick ticker_tick
ticker_ticks ticker_ticks
time_add
time_compare
time_copy
time_divide
time_idivide
time_imultiply
time_init
time_nsec
time_sec
time_subtract
time_update
tsd_arena_get tsd_arena_get
tsd_arena_set tsd_arena_set
tsd_boot tsd_boot

View File

@ -1,41 +0,0 @@
/******************************************************************************/
#ifdef JEMALLOC_H_TYPES
#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
&& _POSIX_MONOTONIC_CLOCK >= 0
/* Maximum supported number of seconds (~584 years). */
#define TIME_SEC_MAX 18446744072
#endif /* JEMALLOC_H_TYPES */
/******************************************************************************/
#ifdef JEMALLOC_H_STRUCTS
#endif /* JEMALLOC_H_STRUCTS */
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
void time_init(struct timespec *time, time_t sec, long nsec);
time_t time_sec(const struct timespec *time);
long time_nsec(const struct timespec *time);
void time_copy(struct timespec *time, const struct timespec *source);
int time_compare(const struct timespec *a, const struct timespec *b);
void time_add(struct timespec *time, const struct timespec *addend);
void time_subtract(struct timespec *time, const struct timespec *subtrahend);
void time_imultiply(struct timespec *time, uint64_t multiplier);
void time_idivide(struct timespec *time, uint64_t divisor);
uint64_t time_divide(const struct timespec *time,
const struct timespec *divisor);
#ifdef JEMALLOC_JET
typedef bool (time_update_t)(struct timespec *);
extern time_update_t *time_update;
#else
bool time_update(struct timespec *time);
#endif
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
#ifdef JEMALLOC_H_INLINES
#endif /* JEMALLOC_H_INLINES */
/******************************************************************************/

View File

@ -1224,27 +1224,24 @@ arena_decay_deadline_init(arena_t *arena)
* Generate a new deadline that is uniformly random within the next * Generate a new deadline that is uniformly random within the next
* epoch after the current one. * epoch after the current one.
*/ */
time_copy(&arena->decay_deadline, &arena->decay_epoch); nstime_copy(&arena->decay_deadline, &arena->decay_epoch);
time_add(&arena->decay_deadline, &arena->decay_interval); nstime_add(&arena->decay_deadline, &arena->decay_interval);
if (arena->decay_time > 0) { if (arena->decay_time > 0) {
uint64_t decay_interval_ns, r; nstime_t jitter;
struct timespec jitter;
decay_interval_ns = time_sec(&arena->decay_interval) * nstime_init(&jitter, prng_range(&arena->decay_jitter_state,
1000000000 + time_nsec(&arena->decay_interval); nstime_ns(&arena->decay_interval)));
r = prng_range(&arena->decay_jitter_state, decay_interval_ns); nstime_add(&arena->decay_deadline, &jitter);
time_init(&jitter, r / 1000000000, r % 1000000000);
time_add(&arena->decay_deadline, &jitter);
} }
} }
static bool static bool
arena_decay_deadline_reached(const arena_t *arena, const struct timespec *time) arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time)
{ {
assert(opt_purge == purge_mode_decay); assert(opt_purge == purge_mode_decay);
return (time_compare(&arena->decay_deadline, time) <= 0); return (nstime_compare(&arena->decay_deadline, time) <= 0);
} }
static size_t static size_t
@ -1276,24 +1273,24 @@ arena_decay_backlog_npages_limit(const arena_t *arena)
} }
static void static void
arena_decay_epoch_advance(arena_t *arena, const struct timespec *time) arena_decay_epoch_advance(arena_t *arena, const nstime_t *time)
{ {
uint64_t nadvance; uint64_t nadvance;
struct timespec delta; nstime_t delta;
size_t ndirty_delta; size_t ndirty_delta;
assert(opt_purge == purge_mode_decay); assert(opt_purge == purge_mode_decay);
assert(arena_decay_deadline_reached(arena, time)); assert(arena_decay_deadline_reached(arena, time));
time_copy(&delta, time); nstime_copy(&delta, time);
time_subtract(&delta, &arena->decay_epoch); nstime_subtract(&delta, &arena->decay_epoch);
nadvance = time_divide(&delta, &arena->decay_interval); nadvance = nstime_divide(&delta, &arena->decay_interval);
assert(nadvance > 0); assert(nadvance > 0);
/* Add nadvance decay intervals to epoch. */ /* Add nadvance decay intervals to epoch. */
time_copy(&delta, &arena->decay_interval); nstime_copy(&delta, &arena->decay_interval);
time_imultiply(&delta, nadvance); nstime_imultiply(&delta, nadvance);
time_add(&arena->decay_epoch, &delta); nstime_add(&arena->decay_epoch, &delta);
/* Set a new deadline. */ /* Set a new deadline. */
arena_decay_deadline_init(arena); arena_decay_deadline_init(arena);
@ -1340,12 +1337,12 @@ arena_decay_init(arena_t *arena, ssize_t decay_time)
arena->decay_time = decay_time; arena->decay_time = decay_time;
if (decay_time > 0) { if (decay_time > 0) {
time_init(&arena->decay_interval, decay_time, 0); nstime_init2(&arena->decay_interval, decay_time, 0);
time_idivide(&arena->decay_interval, SMOOTHSTEP_NSTEPS); nstime_idivide(&arena->decay_interval, SMOOTHSTEP_NSTEPS);
} }
time_init(&arena->decay_epoch, 0, 0); nstime_init(&arena->decay_epoch, 0);
time_update(&arena->decay_epoch); nstime_update(&arena->decay_epoch);
arena->decay_jitter_state = (uint64_t)(uintptr_t)arena; arena->decay_jitter_state = (uint64_t)(uintptr_t)arena;
arena_decay_deadline_init(arena); arena_decay_deadline_init(arena);
arena->decay_ndirty = arena->ndirty; arena->decay_ndirty = arena->ndirty;
@ -1357,7 +1354,7 @@ static bool
arena_decay_time_valid(ssize_t decay_time) arena_decay_time_valid(ssize_t decay_time)
{ {
return (decay_time >= -1 && decay_time <= TIME_SEC_MAX); return (decay_time >= -1 && decay_time <= NSTIME_SEC_MAX);
} }
ssize_t ssize_t
@ -1426,7 +1423,7 @@ arena_maybe_purge_ratio(arena_t *arena)
static void static void
arena_maybe_purge_decay(arena_t *arena) arena_maybe_purge_decay(arena_t *arena)
{ {
struct timespec time; nstime_t time;
size_t ndirty_limit; size_t ndirty_limit;
assert(opt_purge == purge_mode_decay); assert(opt_purge == purge_mode_decay);
@ -1438,10 +1435,10 @@ arena_maybe_purge_decay(arena_t *arena)
return; return;
} }
time_copy(&time, &arena->decay_epoch); nstime_copy(&time, &arena->decay_epoch);
if (unlikely(time_update(&time))) { if (unlikely(nstime_update(&time))) {
/* Time went backwards. Force an epoch advance. */ /* Time went backwards. Force an epoch advance. */
time_copy(&time, &arena->decay_deadline); nstime_copy(&time, &arena->decay_deadline);
} }
if (arena_decay_deadline_reached(arena, &time)) if (arena_decay_deadline_reached(arena, &time))

View File

@ -1151,7 +1151,7 @@ malloc_conf_init(void)
CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult", CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult",
-1, (sizeof(size_t) << 3) - 1) -1, (sizeof(size_t) << 3) - 1)
CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1, CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1,
TIME_SEC_MAX); NSTIME_SEC_MAX);
CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true)
if (config_fill) { if (config_fill) {
if (CONF_MATCH("junk")) { if (CONF_MATCH("junk")) {

148
src/nstime.c Normal file
View File

@ -0,0 +1,148 @@
#include "jemalloc/internal/jemalloc_internal.h"
#define BILLION UINT64_C(1000000000)
void
nstime_init(nstime_t *time, uint64_t ns)
{
time->ns = ns;
}
void
nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec)
{
time->ns = sec * BILLION + nsec;
}
uint64_t
nstime_ns(const nstime_t *time)
{
return (time->ns);
}
uint64_t
nstime_sec(const nstime_t *time)
{
return (time->ns / BILLION);
}
uint64_t
nstime_nsec(const nstime_t *time)
{
return (time->ns % BILLION);
}
void
nstime_copy(nstime_t *time, const nstime_t *source)
{
*time = *source;
}
int
nstime_compare(const nstime_t *a, const nstime_t *b)
{
return ((a->ns > b->ns) - (a->ns < b->ns));
}
void
nstime_add(nstime_t *time, const nstime_t *addend)
{
assert(UINT64_MAX - time->ns >= addend->ns);
time->ns += addend->ns;
}
void
nstime_subtract(nstime_t *time, const nstime_t *subtrahend)
{
assert(nstime_compare(time, subtrahend) >= 0);
time->ns -= subtrahend->ns;
}
void
nstime_imultiply(nstime_t *time, uint64_t multiplier)
{
assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) <<
2))) == 0) || ((time->ns * multiplier) / multiplier == time->ns));
time->ns *= multiplier;
}
void
nstime_idivide(nstime_t *time, uint64_t divisor)
{
assert(divisor != 0);
time->ns /= divisor;
}
uint64_t
nstime_divide(const nstime_t *time, const nstime_t *divisor)
{
assert(divisor->ns != 0);
return (time->ns / divisor->ns);
}
#ifdef JEMALLOC_JET
#undef nstime_update
#define nstime_update JEMALLOC_N(nstime_update_impl)
#endif
bool
nstime_update(nstime_t *time)
{
nstime_t old_time;
nstime_copy(&old_time, time);
#ifdef _WIN32
{
FILETIME ft;
uint64_t ticks;
GetSystemTimeAsFileTime(&ft);
ticks = (((uint64_t)ft.dwHighDateTime) << 32) |
ft.dwLowDateTime;
time->ns = ticks * 100;
}
#elif JEMALLOC_CLOCK_GETTIME
{
struct timespec ts;
if (sysconf(_SC_MONOTONIC_CLOCK) > 0)
clock_gettime(CLOCK_MONOTONIC, &ts);
else
clock_gettime(CLOCK_REALTIME, &ts);
time->ns = ts.tv_sec * BILLION + ts.tv_nsec;
}
#else
struct timeval tv;
gettimeofday(&tv, NULL);
time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000;
#endif
/* Handle non-monotonic clocks. */
if (unlikely(nstime_compare(&old_time, time) > 0)) {
nstime_copy(time, &old_time);
return (true);
}
return (false);
}
#ifdef JEMALLOC_JET
#undef nstime_update
#define nstime_update JEMALLOC_N(nstime_update)
nstime_update_t *nstime_update = JEMALLOC_N(nstime_update_impl);
#endif

View File

@ -1,198 +0,0 @@
#include "jemalloc/internal/jemalloc_internal.h"
#define BILLION 1000000000
UNUSED static bool
time_valid(const struct timespec *time)
{
if (time->tv_sec > TIME_SEC_MAX)
return (false);
if (time->tv_nsec >= BILLION)
return (false);
return (true);
}
void
time_init(struct timespec *time, time_t sec, long nsec)
{
time->tv_sec = sec;
time->tv_nsec = nsec;
assert(time_valid(time));
}
time_t
time_sec(const struct timespec *time)
{
assert(time_valid(time));
return (time->tv_sec);
}
long
time_nsec(const struct timespec *time)
{
assert(time_valid(time));
return (time->tv_nsec);
}
void
time_copy(struct timespec *time, const struct timespec *source)
{
assert(time_valid(source));
*time = *source;
}
int
time_compare(const struct timespec *a, const struct timespec *b)
{
int ret;
assert(time_valid(a));
assert(time_valid(b));
ret = (a->tv_sec > b->tv_sec) - (a->tv_sec < b->tv_sec);
if (ret == 0)
ret = (a->tv_nsec > b->tv_nsec) - (a->tv_nsec < b->tv_nsec);
return (ret);
}
void
time_add(struct timespec *time, const struct timespec *addend)
{
assert(time_valid(time));
assert(time_valid(addend));
time->tv_sec += addend->tv_sec;
time->tv_nsec += addend->tv_nsec;
if (time->tv_nsec >= BILLION) {
time->tv_sec++;
time->tv_nsec -= BILLION;
}
assert(time_valid(time));
}
void
time_subtract(struct timespec *time, const struct timespec *subtrahend)
{
assert(time_valid(time));
assert(time_valid(subtrahend));
assert(time_compare(time, subtrahend) >= 0);
time->tv_sec -= subtrahend->tv_sec;
if (time->tv_nsec < subtrahend->tv_nsec) {
time->tv_sec--;
time->tv_nsec += BILLION;
}
time->tv_nsec -= subtrahend->tv_nsec;
}
void
time_imultiply(struct timespec *time, uint64_t multiplier)
{
time_t sec;
uint64_t nsec;
assert(time_valid(time));
sec = time->tv_sec * multiplier;
nsec = time->tv_nsec * multiplier;
sec += nsec / BILLION;
nsec %= BILLION;
time_init(time, sec, (long)nsec);
assert(time_valid(time));
}
void
time_idivide(struct timespec *time, uint64_t divisor)
{
time_t sec;
uint64_t nsec;
assert(time_valid(time));
sec = time->tv_sec / divisor;
nsec = ((time->tv_sec % divisor) * BILLION + time->tv_nsec) / divisor;
sec += nsec / BILLION;
nsec %= BILLION;
time_init(time, sec, (long)nsec);
assert(time_valid(time));
}
uint64_t
time_divide(const struct timespec *time, const struct timespec *divisor)
{
uint64_t t, d;
assert(time_valid(time));
assert(time_valid(divisor));
t = time_sec(time) * BILLION + time_nsec(time);
d = time_sec(divisor) * BILLION + time_nsec(divisor);
assert(d != 0);
return (t / d);
}
#ifdef JEMALLOC_JET
#undef time_update
#define time_update JEMALLOC_N(time_update_impl)
#endif
bool
time_update(struct timespec *time)
{
struct timespec old_time;
assert(time_valid(time));
time_copy(&old_time, time);
#ifdef _WIN32
{
FILETIME ft;
uint64_t ticks;
GetSystemTimeAsFileTime(&ft);
ticks = (((uint64_t)ft.dwHighDateTime) << 32) |
ft.dwLowDateTime;
time->tv_sec = ticks / 10000000;
time->tv_nsec = ((ticks % 10000000) * 100);
}
#elif JEMALLOC_CLOCK_GETTIME
if (sysconf(_SC_MONOTONIC_CLOCK) > 0)
clock_gettime(CLOCK_MONOTONIC, time);
else
clock_gettime(CLOCK_REALTIME, time);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
time->tv_sec = tv.tv_sec;
time->tv_nsec = tv.tv_usec * 1000;
#endif
/* Handle non-monotonic clocks. */
if (unlikely(time_compare(&old_time, time) > 0)) {
time_copy(time, &old_time);
return (true);
}
assert(time_valid(time));
return (false);
}
#ifdef JEMALLOC_JET
#undef time_update
#define time_update JEMALLOC_N(time_update)
time_update_t *time_update = JEMALLOC_N(time_update_impl);
#endif

View File

@ -94,7 +94,7 @@
# define JEMALLOC_H_STRUCTS # define JEMALLOC_H_STRUCTS
# define JEMALLOC_H_EXTERNS # define JEMALLOC_H_EXTERNS
# define JEMALLOC_H_INLINES # define JEMALLOC_H_INLINES
# include "jemalloc/internal/time.h" # include "jemalloc/internal/nstime.h"
# include "jemalloc/internal/util.h" # include "jemalloc/internal/util.h"
# include "jemalloc/internal/qr.h" # include "jemalloc/internal/qr.h"
# include "jemalloc/internal/ql.h" # include "jemalloc/internal/ql.h"

View File

@ -4,8 +4,8 @@
#include <sys/time.h> #include <sys/time.h>
typedef struct { typedef struct {
struct timespec t0; nstime_t t0;
struct timespec t1; nstime_t t1;
} timedelta_t; } timedelta_t;
void timer_start(timedelta_t *timer); void timer_start(timedelta_t *timer);

View File

@ -4,26 +4,26 @@ void
timer_start(timedelta_t *timer) timer_start(timedelta_t *timer)
{ {
time_init(&timer->t0, 0, 0); nstime_init(&timer->t0, 0);
time_update(&timer->t0); nstime_update(&timer->t0);
} }
void void
timer_stop(timedelta_t *timer) timer_stop(timedelta_t *timer)
{ {
time_copy(&timer->t1, &timer->t0); nstime_copy(&timer->t1, &timer->t0);
time_update(&timer->t1); nstime_update(&timer->t1);
} }
uint64_t uint64_t
timer_usec(const timedelta_t *timer) timer_usec(const timedelta_t *timer)
{ {
struct timespec delta; nstime_t delta;
time_copy(&delta, &timer->t1); nstime_copy(&delta, &timer->t1);
time_subtract(&delta, &timer->t0); nstime_subtract(&delta, &timer->t0);
return (time_sec(&delta) * 1000000 + time_nsec(&delta) / 1000); return (nstime_ns(&delta) / 1000);
} }
void void

View File

@ -2,19 +2,19 @@
const char *malloc_conf = "purge:decay,decay_time:1"; const char *malloc_conf = "purge:decay,decay_time:1";
static time_update_t *time_update_orig; static nstime_update_t *nstime_update_orig;
static unsigned nupdates_mock; static unsigned nupdates_mock;
static struct timespec time_mock; static nstime_t time_mock;
static bool nonmonotonic_mock; static bool nonmonotonic_mock;
static bool static bool
time_update_mock(struct timespec *time) nstime_update_mock(nstime_t *time)
{ {
nupdates_mock++; nupdates_mock++;
if (!nonmonotonic_mock) if (!nonmonotonic_mock)
time_copy(time, &time_mock); nstime_copy(time, &time_mock);
return (nonmonotonic_mock); return (nonmonotonic_mock);
} }
@ -204,7 +204,7 @@ TEST_BEGIN(test_decay_ticker)
uint64_t epoch, npurge0, npurge1; uint64_t epoch, npurge0, npurge1;
size_t sz, tcache_max, large; size_t sz, tcache_max, large;
unsigned i, nupdates0; unsigned i, nupdates0;
struct timespec time, decay_time, deadline; nstime_t time, decay_time, deadline;
test_skip_if(opt_purge != purge_mode_decay); test_skip_if(opt_purge != purge_mode_decay);
@ -233,12 +233,12 @@ TEST_BEGIN(test_decay_ticker)
} }
nupdates_mock = 0; nupdates_mock = 0;
time_init(&time_mock, 0, 0); nstime_init(&time_mock, 0);
time_update(&time_mock); nstime_update(&time_mock);
nonmonotonic_mock = false; nonmonotonic_mock = false;
time_update_orig = time_update; nstime_update_orig = nstime_update;
time_update = time_update_mock; nstime_update = nstime_update_mock;
for (i = 0; i < NPS; i++) { for (i = 0; i < NPS; i++) {
dallocx(ps[i], flags); dallocx(ps[i], flags);
@ -246,16 +246,16 @@ TEST_BEGIN(test_decay_ticker)
assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.decay failure"); "Unexpected arena.0.decay failure");
assert_u_gt(nupdates_mock, nupdates0, assert_u_gt(nupdates_mock, nupdates0,
"Expected time_update() to be called"); "Expected nstime_update() to be called");
} }
time_update = time_update_orig; nstime_update = nstime_update_orig;
time_init(&time, 0, 0); nstime_init(&time, 0);
time_update(&time); nstime_update(&time);
time_init(&decay_time, opt_decay_time, 0); nstime_init2(&decay_time, opt_decay_time, 0);
time_copy(&deadline, &time); nstime_copy(&deadline, &time);
time_add(&deadline, &decay_time); nstime_add(&deadline, &decay_time);
do { do {
for (i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) { for (i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) {
void *p = mallocx(1, flags); void *p = mallocx(1, flags);
@ -268,8 +268,8 @@ TEST_BEGIN(test_decay_ticker)
assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz,
NULL, 0), 0, "Unexpected mallctl failure"); NULL, 0), 0, "Unexpected mallctl failure");
time_update(&time); nstime_update(&time);
} while (time_compare(&time, &deadline) <= 0 && npurge1 == npurge0); } while (nstime_compare(&time, &deadline) <= 0 && npurge1 == npurge0);
assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); assert_u64_gt(npurge1, npurge0, "Expected purging to occur");
#undef NPS #undef NPS
@ -300,12 +300,12 @@ TEST_BEGIN(test_decay_nonmonotonic)
"Unexpected mallctl failure"); "Unexpected mallctl failure");
nupdates_mock = 0; nupdates_mock = 0;
time_init(&time_mock, 0, 0); nstime_init(&time_mock, 0);
time_update(&time_mock); nstime_update(&time_mock);
nonmonotonic_mock = true; nonmonotonic_mock = true;
time_update_orig = time_update; nstime_update_orig = nstime_update;
time_update = time_update_mock; nstime_update = nstime_update_mock;
for (i = 0; i < NPS; i++) { for (i = 0; i < NPS; i++) {
ps[i] = mallocx(large0, flags); ps[i] = mallocx(large0, flags);
@ -318,7 +318,7 @@ TEST_BEGIN(test_decay_nonmonotonic)
assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.decay failure"); "Unexpected arena.0.decay failure");
assert_u_gt(nupdates_mock, nupdates0, assert_u_gt(nupdates_mock, nupdates0,
"Expected time_update() to be called"); "Expected nstime_update() to be called");
} }
assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0,
@ -329,7 +329,7 @@ TEST_BEGIN(test_decay_nonmonotonic)
assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); assert_u64_gt(npurge1, npurge0, "Expected purging to occur");
time_update = time_update_orig; nstime_update = nstime_update_orig;
#undef NPS #undef NPS
} }
TEST_END TEST_END

View File

@ -401,7 +401,7 @@ TEST_BEGIN(test_arena_i_decay_time)
&decay_time, sizeof(ssize_t)), EFAULT, &decay_time, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
decay_time = TIME_SEC_MAX; decay_time = 0x7fffffff;
assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), 0, &decay_time, sizeof(ssize_t)), 0,
"Unexpected mallctl() failure"); "Unexpected mallctl() failure");
@ -567,7 +567,7 @@ TEST_BEGIN(test_arenas_decay_time)
&decay_time, sizeof(ssize_t)), EFAULT, &decay_time, sizeof(ssize_t)), EFAULT,
"Unexpected mallctl() success"); "Unexpected mallctl() success");
decay_time = TIME_SEC_MAX; decay_time = 0x7fffffff;
assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
&decay_time, sizeof(ssize_t)), 0, &decay_time, sizeof(ssize_t)), 0,
"Expected mallctl() failure"); "Expected mallctl() failure");

220
test/unit/nstime.c Normal file
View File

@ -0,0 +1,220 @@
#include "test/jemalloc_test.h"
#define BILLION UINT64_C(1000000000)
TEST_BEGIN(test_nstime_init)
{
nstime_t nst;
nstime_init(&nst, 42000000043);
assert_u64_eq(nstime_ns(&nst), 42000000043, "ns incorrectly read");
assert_u64_eq(nstime_sec(&nst), 42, "sec incorrectly read");
assert_u64_eq(nstime_nsec(&nst), 43, "nsec incorrectly read");
}
TEST_END
TEST_BEGIN(test_nstime_init2)
{
nstime_t nst;
nstime_init2(&nst, 42, 43);
assert_u64_eq(nstime_sec(&nst), 42, "sec incorrectly read");
assert_u64_eq(nstime_nsec(&nst), 43, "nsec incorrectly read");
}
TEST_END
TEST_BEGIN(test_nstime_copy)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_init(&nstb, 0);
nstime_copy(&nstb, &nsta);
assert_u64_eq(nstime_sec(&nstb), 42, "sec incorrectly copied");
assert_u64_eq(nstime_nsec(&nstb), 43, "nsec incorrectly copied");
}
TEST_END
TEST_BEGIN(test_nstime_compare)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
assert_d_eq(nstime_compare(&nsta, &nstb), 0, "Times should be equal");
assert_d_eq(nstime_compare(&nstb, &nsta), 0, "Times should be equal");
nstime_init2(&nstb, 42, 42);
assert_d_eq(nstime_compare(&nsta, &nstb), 1,
"nsta should be greater than nstb");
assert_d_eq(nstime_compare(&nstb, &nsta), -1,
"nstb should be less than nsta");
nstime_init2(&nstb, 42, 44);
assert_d_eq(nstime_compare(&nsta, &nstb), -1,
"nsta should be less than nstb");
assert_d_eq(nstime_compare(&nstb, &nsta), 1,
"nstb should be greater than nsta");
nstime_init2(&nstb, 41, BILLION - 1);
assert_d_eq(nstime_compare(&nsta, &nstb), 1,
"nsta should be greater than nstb");
assert_d_eq(nstime_compare(&nstb, &nsta), -1,
"nstb should be less than nsta");
nstime_init2(&nstb, 43, 0);
assert_d_eq(nstime_compare(&nsta, &nstb), -1,
"nsta should be less than nstb");
assert_d_eq(nstime_compare(&nstb, &nsta), 1,
"nstb should be greater than nsta");
}
TEST_END
TEST_BEGIN(test_nstime_add)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_add(&nsta, &nstb);
nstime_init2(&nstb, 84, 86);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect addition result");
nstime_init2(&nsta, 42, BILLION - 1);
nstime_copy(&nstb, &nsta);
nstime_add(&nsta, &nstb);
nstime_init2(&nstb, 85, BILLION - 2);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect addition result");
}
TEST_END
TEST_BEGIN(test_nstime_subtract)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_subtract(&nsta, &nstb);
nstime_init(&nstb, 0);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect subtraction result");
nstime_init2(&nsta, 42, 43);
nstime_init2(&nstb, 41, 44);
nstime_subtract(&nsta, &nstb);
nstime_init2(&nstb, 0, BILLION - 1);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect subtraction result");
}
TEST_END
TEST_BEGIN(test_nstime_imultiply)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_imultiply(&nsta, 10);
nstime_init2(&nstb, 420, 430);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect multiplication result");
nstime_init2(&nsta, 42, 666666666);
nstime_imultiply(&nsta, 3);
nstime_init2(&nstb, 127, 999999998);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect multiplication result");
}
TEST_END
TEST_BEGIN(test_nstime_idivide)
{
nstime_t nsta, nstb;
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_imultiply(&nsta, 10);
nstime_idivide(&nsta, 10);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect division result");
nstime_init2(&nsta, 42, 666666666);
nstime_copy(&nstb, &nsta);
nstime_imultiply(&nsta, 3);
nstime_idivide(&nsta, 3);
assert_d_eq(nstime_compare(&nsta, &nstb), 0,
"Incorrect division result");
}
TEST_END
TEST_BEGIN(test_nstime_divide)
{
nstime_t nsta, nstb, nstc;
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_imultiply(&nsta, 10);
assert_u64_eq(nstime_divide(&nsta, &nstb), 10,
"Incorrect division result");
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_imultiply(&nsta, 10);
nstime_init(&nstc, 1);
nstime_add(&nsta, &nstc);
assert_u64_eq(nstime_divide(&nsta, &nstb), 10,
"Incorrect division result");
nstime_init2(&nsta, 42, 43);
nstime_copy(&nstb, &nsta);
nstime_imultiply(&nsta, 10);
nstime_init(&nstc, 1);
nstime_subtract(&nsta, &nstc);
assert_u64_eq(nstime_divide(&nsta, &nstb), 9,
"Incorrect division result");
}
TEST_END
TEST_BEGIN(test_nstime_update)
{
nstime_t nst;
nstime_init(&nst, 0);
assert_false(nstime_update(&nst), "Basic time update failed.");
/* Only Rip Van Winkle sleeps this long. */
{
nstime_t addend;
nstime_init2(&addend, 631152000, 0);
nstime_add(&nst, &addend);
}
{
nstime_t nst0;
nstime_copy(&nst0, &nst);
assert_true(nstime_update(&nst),
"Update should detect time roll-back.");
assert_d_eq(nstime_compare(&nst, &nst0), 0,
"Time should not have been modified");
}
}
TEST_END
int
main(void)
{
return (test(
test_nstime_init,
test_nstime_init2,
test_nstime_copy,
test_nstime_compare,
test_nstime_add,
test_nstime_subtract,
test_nstime_imultiply,
test_nstime_idivide,
test_nstime_divide,
test_nstime_update));
}

View File

@ -1,223 +0,0 @@
#include "test/jemalloc_test.h"
#define BILLION 1000000000
TEST_BEGIN(test_time_init)
{
struct timespec ts;
time_init(&ts, 42, 43);
assert_ld_eq(ts.tv_sec, 42, "tv_sec incorrectly initialized");
assert_ld_eq(ts.tv_nsec, 43, "tv_nsec incorrectly initialized");
}
TEST_END
TEST_BEGIN(test_time_sec)
{
struct timespec ts;
time_init(&ts, 42, 43);
assert_ld_eq(time_sec(&ts), 42, "tv_sec incorrectly read");
}
TEST_END
TEST_BEGIN(test_time_nsec)
{
struct timespec ts;
time_init(&ts, 42, 43);
assert_ld_eq(time_nsec(&ts), 43, "tv_nsec incorrectly read");
}
TEST_END
TEST_BEGIN(test_time_copy)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_init(&tsb, 0, 0);
time_copy(&tsb, &tsa);
assert_ld_eq(time_sec(&tsb), 42, "tv_sec incorrectly copied");
assert_ld_eq(time_nsec(&tsb), 43, "tv_nsec incorrectly copied");
}
TEST_END
TEST_BEGIN(test_time_compare)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
assert_d_eq(time_compare(&tsa, &tsb), 0, "Times should be equal");
assert_d_eq(time_compare(&tsb, &tsa), 0, "Times should be equal");
time_init(&tsb, 42, 42);
assert_d_eq(time_compare(&tsa, &tsb), 1,
"tsa should be greater than tsb");
assert_d_eq(time_compare(&tsb, &tsa), -1,
"tsb should be less than tsa");
time_init(&tsb, 42, 44);
assert_d_eq(time_compare(&tsa, &tsb), -1,
"tsa should be less than tsb");
assert_d_eq(time_compare(&tsb, &tsa), 1,
"tsb should be greater than tsa");
time_init(&tsb, 41, BILLION - 1);
assert_d_eq(time_compare(&tsa, &tsb), 1,
"tsa should be greater than tsb");
assert_d_eq(time_compare(&tsb, &tsa), -1,
"tsb should be less than tsa");
time_init(&tsb, 43, 0);
assert_d_eq(time_compare(&tsa, &tsb), -1,
"tsa should be less than tsb");
assert_d_eq(time_compare(&tsb, &tsa), 1,
"tsb should be greater than tsa");
}
TEST_END
TEST_BEGIN(test_time_add)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_add(&tsa, &tsb);
time_init(&tsb, 84, 86);
assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect addition result");
time_init(&tsa, 42, BILLION - 1);
time_copy(&tsb, &tsa);
time_add(&tsa, &tsb);
time_init(&tsb, 85, BILLION - 2);
assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect addition result");
}
TEST_END
TEST_BEGIN(test_time_subtract)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_subtract(&tsa, &tsb);
time_init(&tsb, 0, 0);
assert_d_eq(time_compare(&tsa, &tsb), 0,
"Incorrect subtraction result");
time_init(&tsa, 42, 43);
time_init(&tsb, 41, 44);
time_subtract(&tsa, &tsb);
time_init(&tsb, 0, BILLION - 1);
assert_d_eq(time_compare(&tsa, &tsb), 0,
"Incorrect subtraction result");
}
TEST_END
TEST_BEGIN(test_time_imultiply)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_imultiply(&tsa, 10);
time_init(&tsb, 420, 430);
assert_d_eq(time_compare(&tsa, &tsb), 0,
"Incorrect multiplication result");
time_init(&tsa, 42, 666666666);
time_imultiply(&tsa, 3);
time_init(&tsb, 127, 999999998);
assert_d_eq(time_compare(&tsa, &tsb), 0,
"Incorrect multiplication result");
}
TEST_END
TEST_BEGIN(test_time_idivide)
{
struct timespec tsa, tsb;
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_imultiply(&tsa, 10);
time_idivide(&tsa, 10);
assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect division result");
time_init(&tsa, 42, 666666666);
time_copy(&tsb, &tsa);
time_imultiply(&tsa, 3);
time_idivide(&tsa, 3);
assert_d_eq(time_compare(&tsa, &tsb), 0, "Incorrect division result");
}
TEST_END
TEST_BEGIN(test_time_divide)
{
struct timespec tsa, tsb, tsc;
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_imultiply(&tsa, 10);
assert_u64_eq(time_divide(&tsa, &tsb), 10,
"Incorrect division result");
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_imultiply(&tsa, 10);
time_init(&tsc, 0, 1);
time_add(&tsa, &tsc);
assert_u64_eq(time_divide(&tsa, &tsb), 10,
"Incorrect division result");
time_init(&tsa, 42, 43);
time_copy(&tsb, &tsa);
time_imultiply(&tsa, 10);
time_init(&tsc, 0, 1);
time_subtract(&tsa, &tsc);
assert_u64_eq(time_divide(&tsa, &tsb), 9, "Incorrect division result");
}
TEST_END
TEST_BEGIN(test_time_update)
{
struct timespec ts;
time_init(&ts, 0, 0);
assert_false(time_update(&ts), "Basic time update failed.");
/* Only Rip Van Winkle sleeps this long. */
{
struct timespec addend;
time_init(&addend, 631152000, 0);
time_add(&ts, &addend);
}
{
struct timespec ts0;
time_copy(&ts0, &ts);
assert_true(time_update(&ts),
"Update should detect time roll-back.");
assert_d_eq(time_compare(&ts, &ts0), 0,
"Time should not have been modified");
}
}
TEST_END
int
main(void)
{
return (test(
test_time_init,
test_time_sec,
test_time_nsec,
test_time_copy,
test_time_compare,
test_time_add,
test_time_subtract,
test_time_imultiply,
test_time_idivide,
test_time_divide,
test_time_update));
}