blob: 7b17fd11d601d851977d037fb6d016755fd1cc3d [file] [log] [blame]
Pau Espin Pedrol87fade82018-02-26 19:42:22 +01001/*
2 * (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * All Rights Reserved
4 *
5 * Authors: Pau Espin Pedrol <pespin@sysmocom.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23/*! \addtogroup timer
24 * @{
25 * \file timer_clockgettime.c
26 * Overriding Time: osmo_clock_gettime()
27 * - Useful to write and reproduce tests that depend on specific time
28 * factors. This API allows to fake the timespec provided by `clock_gettime()`
29 * by using a small shim osmo_clock_gettime().
30 * - Choose the clock you want to override, for instance CLOCK_MONOTONIC.
31 * - If the clock override is disabled (default) for a given clock,
32 * osmo_clock_gettime() will do the same as regular `clock_gettime()`.
33 * - If you want osmo_clock_gettime() to provide a specific time, you must
34 * enable time override with osmo_clock_override_enable(),
35 * then set a pointer to the timespec storing the fake time for that
36 * specific clock (`struct timespec *ts =
37 * osmo_clock_override_gettimespec()`) and set it as
38 * desired. Next time osmo_clock_gettime() is called, it will return the
39 * values previously set through the ts pointer.
40 * - A helper osmo_clock_override_add() is provided to increment a given
41 * overriden clock with a specific amount of time.
42 */
43
44/*! \file timer_clockgettime.c
45 */
46
Harald Welte14c4c492018-06-28 08:28:52 +020047#include "config.h"
48#ifdef HAVE_CLOCK_GETTIME
49
Pau Espin Pedrol87fade82018-02-26 19:42:22 +010050#include <stdlib.h>
51#include <stdbool.h>
52#include <sys/time.h>
53#include <time.h>
54
55#include <osmocom/core/timer_compat.h>
56
57/*! An internal structure to handle overriden time for each clock type. */
58struct fakeclock {
59 bool override;
60 struct timespec time;
61};
62
63static struct fakeclock realtime;
64static struct fakeclock realtime_coarse;
65static struct fakeclock mono;
66static struct fakeclock mono_coarse;
67static struct fakeclock mono_raw;
68static struct fakeclock boottime;
69static struct fakeclock boottime;
70static struct fakeclock proc_cputime_id;
71static struct fakeclock th_cputime_id;
72
73static struct fakeclock* clkid_to_fakeclock(clockid_t clk_id)
74{
75 switch(clk_id) {
76 case CLOCK_REALTIME:
77 return &realtime;
78 case CLOCK_REALTIME_COARSE:
79 return &realtime_coarse;
80 case CLOCK_MONOTONIC:
81 return &mono;
82 case CLOCK_MONOTONIC_COARSE:
83 return &mono_coarse;
84 case CLOCK_MONOTONIC_RAW:
85 return &mono_raw;
86 case CLOCK_BOOTTIME:
87 return &boottime;
88 case CLOCK_PROCESS_CPUTIME_ID:
89 return &proc_cputime_id;
90 case CLOCK_THREAD_CPUTIME_ID:
91 return &th_cputime_id;
92 default:
93 return NULL;
94 }
95}
96
97/*! Shim around clock_gettime to be able to set the time manually.
98 *
99 * To override, use osmo_clock_override_enable and set the desired
100 * current time with osmo_clock_gettimespec. */
101int osmo_clock_gettime(clockid_t clk_id, struct timespec *tp)
102{
103 struct fakeclock* c = clkid_to_fakeclock(clk_id);
104 if (!c || !c->override)
105 return clock_gettime(clk_id, tp);
106
107 *tp = c->time;
108 return 0;
109}
110
111/*! Convenience function to enable or disable a specific clock fake time.
112 */
113void osmo_clock_override_enable(clockid_t clk_id, bool enable)
114{
115 struct fakeclock* c = clkid_to_fakeclock(clk_id);
116 if (c)
117 c->override = enable;
118}
119
120/*! Convenience function to return a pointer to the timespec handling the
121 * fake time for clock clk_id. */
122struct timespec *osmo_clock_override_gettimespec(clockid_t clk_id)
123{
124 struct fakeclock* c = clkid_to_fakeclock(clk_id);
125 if (c)
126 return &c->time;
127 return NULL;
128}
129
130/*! Convenience function to advance the fake time.
131 *
132 * Adds the given values to the clock time. */
133void osmo_clock_override_add(clockid_t clk_id, time_t secs, long nsecs)
134{
135 struct timespec val = { secs, nsecs };
136 struct fakeclock* c = clkid_to_fakeclock(clk_id);
137 if (c)
138 timespecadd(&c->time, &val, &c->time);
139}
140
Harald Welte14c4c492018-06-28 08:28:52 +0200141#endif /* HAVE_CLOCK_GETTIME */
142
Pau Espin Pedrol87fade82018-02-26 19:42:22 +0100143/*! @} */