clock abstraction
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
#ifndef UCORE_CLOCK_H_
|
||||
#define UCORE_CLOCK_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <ucore/ucore_clock.h>
|
||||
#include <ucore/ucore_utils.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user