diff --git a/include/ucore/ucore_clock.h b/include/ucore/ucore_clock.h new file mode 100644 index 0000000..67d2c24 --- /dev/null +++ b/include/ucore/ucore_clock.h @@ -0,0 +1,99 @@ +#ifndef UCORE_CLOCK_H_ +#define UCORE_CLOCK_H_ + +#include +#include + + +/** + * An abstract clock. + * Instead of hardcoding calls to time()/gettimeofday() and similar, + * it is useful tp have a level of indirection to better facilitate + * testing and simulation of code that's dependent on time. + */ +struct ucore_clock { + /** + * Name of this clock + */ + const char *name; + /** + * Wrapper for getting the current time. + * @param tv timeval that will be filled in + */ + void (*now)(struct ucore_clock *clock, struct timeval *tv); +}; + + +/** A cached clock where clock.now() returns + * the cached value. The cache is updated + * from the real_clock whenever ucore_cached_clock_update() + * is called. + */ +struct ucore_cached_clock { + /** The clock*/ + struct ucore_clock clock; + /** The underlying real clock*/ + struct ucore_clock *real_clock; + /** cached value */ + struct timeval cache; +}; + +/** A settable clock where clock.now() returns + * the user settable value. The user updates the clock + * with ucore_settable_clock_set(). + */ +struct ucore_settable_clock { + /** The clock*/ + struct ucore_clock clock; + /** The underlying real clock*/ + /** Current value */ + struct timeval now; +}; + + +/** A clock where now() calls gettimeofday() + */ +extern struct ucore_clock ucore_timeofday_clock; + +/** + * A clock where now() calls time(). + * This clock will this just have seconds resolution. + */ +extern struct ucore_clock ucore_time_clock; + +/** + * Initialize a cached clock where now() calls time(). + * This clock will this just have seconds resolution. + * @param clock clock to initialize + */ +void ucore_cached_clock_init(struct ucore_cached_clock *clock, + struct ucore_clock *real_clock); + +/** Update the cached clock from the real_clock + */ +void ucore_cached_clock_update(struct ucore_cached_clock *clock); + + +/** + * Initialize a user settable where now() calls time(). + * This clock will this just have seconds resolution. + * @param clock clock to initialize + */ +void ucore_settable_clock_init(struct ucore_settable_clock *clock); + +/** + * Set the new timeval this clock will return + **/ +void ucore_cached_clock_set_tv(struct ucore_settable_clock *clock, + const struct timeval *tv); + +/** + * Set the new timeval this clock will return + * Convenience function that takes seconds/microseconds as arguments + * instead of a struct timeval. + **/ +void ucore_cached_clock_set(struct ucore_settable_clock *clock, + time_t secs, suseconds_t usecs); + +#endif + diff --git a/src/ucore_clock.c b/src/ucore_clock.c new file mode 100644 index 0000000..c2a49bd --- /dev/null +++ b/src/ucore_clock.c @@ -0,0 +1,81 @@ +#include +#include + +#ifdef __GNUC__ +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif + +static void ucore_timeofday_now(struct ucore_clock *clock UNUSED, struct timeval *tv) +{ + gettimeofday(tv, NULL); +} + +static void ucore_time_now(struct ucore_clock *clock UNUSED, struct timeval *tv) +{ + tv->tv_sec = time(NULL); + tv->tv_usec = 0; +} + +struct ucore_clock ucore_timeofday_clock = { + .name = "gettimeofday", + .now = ucore_timeofday_now, +}; + +struct ucore_clock ucore_time_clock = { + .name = "time", + .now = ucore_time_now, +}; + +static void ucore_cached_clock_now(struct ucore_clock *clock UNUSED, + struct timeval *tv) +{ + struct ucore_cached_clock *cached_clock; + cached_clock = CONTAINER_OF(clock, struct ucore_cached_clock, clock), + + *tv = cached_clock->cache; +} + +void ucore_cached_clock_init(struct ucore_cached_clock *clock, struct ucore_clock *real_clock) +{ + clock->clock.name = "cached clock"; + clock->clock.now = ucore_cached_clock_now; + + clock->real_clock = real_clock; + + ucore_cached_clock_update(clock); +} + +void ucore_cached_clock_update(struct ucore_cached_clock *clock) +{ + clock->real_clock->now(&clock->clock, &clock->cache); +} + +static void ucore_settable_clock_now(struct ucore_clock *clock, struct timeval *tv) +{ + struct ucore_settable_clock *cached_clock; + cached_clock = CONTAINER_OF(clock, struct ucore_settable_clock, clock), + + *tv = cached_clock->now; +} + +void ucore_settable_clock_init(struct ucore_settable_clock *clock) +{ + clock->clock.name = "settable clock"; + clock->clock.now = ucore_settable_clock_now; + + clock->now.tv_sec = 0; + clock->now.tv_usec = 0; +} + +void ucore_settable_clock_set_tv(struct ucore_settable_clock *clock, const struct timeval *tv) +{ + clock->now = *tv; +} + +void ucore_settable_clock_set(struct ucore_settable_clock *clock, time_t secs, suseconds_t usecs) +{ + clock->now.tv_sec = secs; + clock->now.tv_usec = usecs; +}