| /* |
| * (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 "config.h" |
| #ifdef HAVE_CLOCK_GETTIME |
| |
| #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); |
| } |
| |
| #endif /* HAVE_CLOCK_GETTIME */ |
| |
| /*! @} */ |