mirror of https://gerrit.osmocom.org/libosmocore
timer: Introduce osmo_clock_gettime to override clock_gettime
Change-Id: I5bebc6e01fc9d238065bc2517058f0ba85620349
This commit is contained in:
parent
721aa6ded9
commit
87fade88bd
|
@ -40,6 +40,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
|
@ -87,6 +88,7 @@ int osmo_timers_update(void);
|
||||||
int osmo_timers_check(void);
|
int osmo_timers_check(void);
|
||||||
|
|
||||||
int osmo_gettimeofday(struct timeval *tv, struct timezone *tz);
|
int osmo_gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||||
|
int osmo_clock_gettime(clockid_t clk_id, struct timespec *tp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timer override
|
* timer override
|
||||||
|
@ -96,4 +98,8 @@ extern bool osmo_gettimeofday_override;
|
||||||
extern struct timeval osmo_gettimeofday_override_time;
|
extern struct timeval osmo_gettimeofday_override_time;
|
||||||
void osmo_gettimeofday_override_add(time_t secs, suseconds_t usecs);
|
void osmo_gettimeofday_override_add(time_t secs, suseconds_t usecs);
|
||||||
|
|
||||||
|
void osmo_clock_override_enable(clockid_t clk_id, bool enable);
|
||||||
|
void osmo_clock_override_add(clockid_t clk_id, time_t secs, long nsecs);
|
||||||
|
struct timespec *osmo_clock_override_gettimespec(clockid_t clk_id);
|
||||||
|
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
|
@ -13,7 +13,8 @@ endif
|
||||||
lib_LTLIBRARIES = libosmocore.la
|
lib_LTLIBRARIES = libosmocore.la
|
||||||
|
|
||||||
libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS)
|
libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS)
|
||||||
libosmocore_la_SOURCES = timer.c timer_gettimeofday.c select.c signal.c msgb.c bits.c \
|
libosmocore_la_SOURCES = timer.c timer_gettimeofday.c timer_clockgettime.c \
|
||||||
|
select.c signal.c msgb.c bits.c \
|
||||||
bitvec.c bitcomp.c counter.c fsm.c \
|
bitvec.c bitcomp.c counter.c fsm.c \
|
||||||
write_queue.c utils.c socket.c \
|
write_queue.c utils.c socket.c \
|
||||||
logging.c logging_syslog.c logging_gsmtap.c rate_ctr.c \
|
logging.c logging_syslog.c logging_gsmtap.c rate_ctr.c \
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Authors: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \addtogroup timer
|
||||||
|
* @{
|
||||||
|
* \file timer_clockgettime.c
|
||||||
|
* Overriding Time: osmo_clock_gettime()
|
||||||
|
* - Useful to write and reproduce tests that depend on specific time
|
||||||
|
* factors. This API allows to fake the timespec provided by `clock_gettime()`
|
||||||
|
* by using a small shim osmo_clock_gettime().
|
||||||
|
* - Choose the clock you want to override, for instance CLOCK_MONOTONIC.
|
||||||
|
* - If the clock override is disabled (default) for a given clock,
|
||||||
|
* osmo_clock_gettime() will do the same as regular `clock_gettime()`.
|
||||||
|
* - If you want osmo_clock_gettime() to provide a specific time, you must
|
||||||
|
* enable time override with osmo_clock_override_enable(),
|
||||||
|
* then set a pointer to the timespec storing the fake time for that
|
||||||
|
* specific clock (`struct timespec *ts =
|
||||||
|
* osmo_clock_override_gettimespec()`) and set it as
|
||||||
|
* desired. Next time osmo_clock_gettime() is called, it will return the
|
||||||
|
* values previously set through the ts pointer.
|
||||||
|
* - A helper osmo_clock_override_add() is provided to increment a given
|
||||||
|
* overriden clock with a specific amount of time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \file timer_clockgettime.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/timer_compat.h>
|
||||||
|
|
||||||
|
/*! An internal structure to handle overriden time for each clock type. */
|
||||||
|
struct fakeclock {
|
||||||
|
bool override;
|
||||||
|
struct timespec time;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fakeclock realtime;
|
||||||
|
static struct fakeclock realtime_coarse;
|
||||||
|
static struct fakeclock mono;
|
||||||
|
static struct fakeclock mono_coarse;
|
||||||
|
static struct fakeclock mono_raw;
|
||||||
|
static struct fakeclock boottime;
|
||||||
|
static struct fakeclock boottime;
|
||||||
|
static struct fakeclock proc_cputime_id;
|
||||||
|
static struct fakeclock th_cputime_id;
|
||||||
|
|
||||||
|
static struct fakeclock* clkid_to_fakeclock(clockid_t clk_id)
|
||||||
|
{
|
||||||
|
switch(clk_id) {
|
||||||
|
case CLOCK_REALTIME:
|
||||||
|
return &realtime;
|
||||||
|
case CLOCK_REALTIME_COARSE:
|
||||||
|
return &realtime_coarse;
|
||||||
|
case CLOCK_MONOTONIC:
|
||||||
|
return &mono;
|
||||||
|
case CLOCK_MONOTONIC_COARSE:
|
||||||
|
return &mono_coarse;
|
||||||
|
case CLOCK_MONOTONIC_RAW:
|
||||||
|
return &mono_raw;
|
||||||
|
case CLOCK_BOOTTIME:
|
||||||
|
return &boottime;
|
||||||
|
case CLOCK_PROCESS_CPUTIME_ID:
|
||||||
|
return &proc_cputime_id;
|
||||||
|
case CLOCK_THREAD_CPUTIME_ID:
|
||||||
|
return &th_cputime_id;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Shim around clock_gettime to be able to set the time manually.
|
||||||
|
*
|
||||||
|
* To override, use osmo_clock_override_enable and set the desired
|
||||||
|
* current time with osmo_clock_gettimespec. */
|
||||||
|
int osmo_clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||||
|
{
|
||||||
|
struct fakeclock* c = clkid_to_fakeclock(clk_id);
|
||||||
|
if (!c || !c->override)
|
||||||
|
return clock_gettime(clk_id, tp);
|
||||||
|
|
||||||
|
*tp = c->time;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convenience function to enable or disable a specific clock fake time.
|
||||||
|
*/
|
||||||
|
void osmo_clock_override_enable(clockid_t clk_id, bool enable)
|
||||||
|
{
|
||||||
|
struct fakeclock* c = clkid_to_fakeclock(clk_id);
|
||||||
|
if (c)
|
||||||
|
c->override = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convenience function to return a pointer to the timespec handling the
|
||||||
|
* fake time for clock clk_id. */
|
||||||
|
struct timespec *osmo_clock_override_gettimespec(clockid_t clk_id)
|
||||||
|
{
|
||||||
|
struct fakeclock* c = clkid_to_fakeclock(clk_id);
|
||||||
|
if (c)
|
||||||
|
return &c->time;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convenience function to advance the fake time.
|
||||||
|
*
|
||||||
|
* Adds the given values to the clock time. */
|
||||||
|
void osmo_clock_override_add(clockid_t clk_id, time_t secs, long nsecs)
|
||||||
|
{
|
||||||
|
struct timespec val = { secs, nsecs };
|
||||||
|
struct fakeclock* c = clkid_to_fakeclock(clk_id);
|
||||||
|
if (c)
|
||||||
|
timespecadd(&c->time, &val, &c->time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @} */
|
|
@ -39,7 +39,7 @@ struct timeval osmo_gettimeofday_override_time = { 23, 424242 };
|
||||||
* N. B: gettimeofday() is affected by discontinuous jumps in the system time
|
* N. B: gettimeofday() is affected by discontinuous jumps in the system time
|
||||||
* (e.g., if the system administrator manually changes the system time).
|
* (e.g., if the system administrator manually changes the system time).
|
||||||
* Hence this should NEVER be used for elapsed time computation.
|
* Hence this should NEVER be used for elapsed time computation.
|
||||||
* Instead, clock_gettime(CLOCK_MONOTONIC, ..) should be used for that (with similar shim if necessary).
|
* Instead, osmo_clock_gettime() with CLOCK_MONOTONIC should be used for that.
|
||||||
*/
|
*/
|
||||||
int osmo_gettimeofday(struct timeval *tv, struct timezone *tz)
|
int osmo_gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
|
||||||
coding/coding_test conv/conv_gsm0503_test \
|
coding/coding_test conv/conv_gsm0503_test \
|
||||||
abis/abis_test endian/endian_test sercomm/sercomm_test \
|
abis/abis_test endian/endian_test sercomm/sercomm_test \
|
||||||
prbs/prbs_test gsm23003/gsm23003_test \
|
prbs/prbs_test gsm23003/gsm23003_test \
|
||||||
codec/codec_ecu_fr_test
|
codec/codec_ecu_fr_test timer/clk_override_test
|
||||||
|
|
||||||
if ENABLE_MSGFILE
|
if ENABLE_MSGFILE
|
||||||
check_PROGRAMS += msgfile/msgfile_test
|
check_PROGRAMS += msgfile/msgfile_test
|
||||||
|
@ -122,6 +122,8 @@ sms_sms_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
|
||||||
|
|
||||||
timer_timer_test_SOURCES = timer/timer_test.c
|
timer_timer_test_SOURCES = timer/timer_test.c
|
||||||
|
|
||||||
|
timer_clk_override_test_SOURCES = timer/clk_override_test.c
|
||||||
|
|
||||||
ussd_ussd_test_SOURCES = ussd/ussd_test.c
|
ussd_ussd_test_SOURCES = ussd/ussd_test.c
|
||||||
ussd_ussd_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
|
ussd_ussd_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
|
||||||
|
|
||||||
|
@ -250,7 +252,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
|
||||||
osmo-auc-gen/osmo-auc-gen_test.err \
|
osmo-auc-gen/osmo-auc-gen_test.err \
|
||||||
conv/conv_gsm0503_test.ok endian/endian_test.ok \
|
conv/conv_gsm0503_test.ok endian/endian_test.ok \
|
||||||
sercomm/sercomm_test.ok prbs/prbs_test.ok \
|
sercomm/sercomm_test.ok prbs/prbs_test.ok \
|
||||||
gsm23003/gsm23003_test.ok
|
gsm23003/gsm23003_test.ok \
|
||||||
|
timer/clk_override_test.ok
|
||||||
|
|
||||||
DISTCLEANFILES = atconfig atlocal conv/gsm0503_test_vectors.c
|
DISTCLEANFILES = atconfig atlocal conv/gsm0503_test_vectors.c
|
||||||
BUILT_SOURCES = conv/gsm0503_test_vectors.c
|
BUILT_SOURCES = conv/gsm0503_test_vectors.c
|
||||||
|
|
|
@ -240,6 +240,12 @@ cat $abs_srcdir/timer/timer_test.ok > expout
|
||||||
AT_CHECK([$abs_top_builddir/tests/timer/timer_test], [0], [expout], [ignore])
|
AT_CHECK([$abs_top_builddir/tests/timer/timer_test], [0], [expout], [ignore])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
|
AT_SETUP([clk_override])
|
||||||
|
AT_KEYWORDS([clk_override])
|
||||||
|
cat $abs_srcdir/timer/clk_override_test.ok > expout
|
||||||
|
AT_CHECK([$abs_top_builddir/tests/timer/clk_override_test], [0], [expout], [ignore])
|
||||||
|
AT_CLEANUP
|
||||||
|
|
||||||
AT_SETUP([tlv])
|
AT_SETUP([tlv])
|
||||||
AT_KEYWORDS([tlv])
|
AT_KEYWORDS([tlv])
|
||||||
cat $abs_srcdir/tlv/tlv_test.ok > expout
|
cat $abs_srcdir/tlv/tlv_test.ok > expout
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Authors: Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* Pablo Neira Ayuso <pablo@gnumonks.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/timer.h>
|
||||||
|
#include <osmocom/core/select.h>
|
||||||
|
#include <osmocom/core/linuxlist.h>
|
||||||
|
#include <osmocom/core/timer_compat.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
struct timespec ts1 = { 123, 456 }, ts2 = {1, 200};
|
||||||
|
struct timespec read1, read2, res;
|
||||||
|
struct timespec *mono;
|
||||||
|
|
||||||
|
osmo_clock_gettime(CLOCK_BOOTTIME, &read1);
|
||||||
|
usleep(500);
|
||||||
|
osmo_clock_gettime(CLOCK_BOOTTIME, &read2);
|
||||||
|
if (!timespeccmp(&read2, &read1, >))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("Non implemented clocks work fine\n");
|
||||||
|
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read1);
|
||||||
|
usleep(500);
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read2);
|
||||||
|
if (!timespeccmp(&read2, &read1, >))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("Monotonic clock is working fine by default\n");
|
||||||
|
|
||||||
|
osmo_clock_override_enable(CLOCK_MONOTONIC, true);
|
||||||
|
printf("Monotonic clock override enabled\n");
|
||||||
|
|
||||||
|
mono = osmo_clock_override_gettimespec(CLOCK_MONOTONIC);
|
||||||
|
if (timespecisset(mono))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("Monotonic override is cleared by default\n");
|
||||||
|
|
||||||
|
memcpy(mono, &ts1, sizeof(struct timespec));
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read1);
|
||||||
|
if (!timespeccmp(&ts1, &read1, ==))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("Monotonic clock can be overriden\n");
|
||||||
|
|
||||||
|
osmo_clock_override_add(CLOCK_MONOTONIC, ts2.tv_sec, ts2.tv_nsec);
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read1);
|
||||||
|
timespecadd(&ts2, &ts1, &res);
|
||||||
|
if (!timespeccmp(&res, &read1, ==))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("osmo_clock_override_add works fine.\n");
|
||||||
|
|
||||||
|
osmo_clock_override_enable(CLOCK_MONOTONIC, false);
|
||||||
|
printf("Monotonic clock override disabled\n");
|
||||||
|
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read1);
|
||||||
|
usleep(500);
|
||||||
|
osmo_clock_gettime(CLOCK_MONOTONIC, &read2);
|
||||||
|
if (!timespeccmp(&read2, &read1, >))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
printf("Monotonic clock is working fine after enable+disable.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
Non implemented clocks work fine
|
||||||
|
Monotonic clock is working fine by default
|
||||||
|
Monotonic clock override enabled
|
||||||
|
Monotonic override is cleared by default
|
||||||
|
Monotonic clock can be overriden
|
||||||
|
osmo_clock_override_add works fine.
|
||||||
|
Monotonic clock override disabled
|
||||||
|
Monotonic clock is working fine after enable+disable.
|
Loading…
Reference in New Issue