blob: 6112b8a5499995977af206ce20460bbb11c970d5 [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 *
Pau Espin Pedrol87fade82018-02-26 19:42:22 +010017 */
18
19/*! \addtogroup timer
20 * @{
21 * \file timer_clockgettime.c
22 * Overriding Time: osmo_clock_gettime()
23 * - Useful to write and reproduce tests that depend on specific time
24 * factors. This API allows to fake the timespec provided by `clock_gettime()`
25 * by using a small shim osmo_clock_gettime().
26 * - Choose the clock you want to override, for instance CLOCK_MONOTONIC.
27 * - If the clock override is disabled (default) for a given clock,
28 * osmo_clock_gettime() will do the same as regular `clock_gettime()`.
29 * - If you want osmo_clock_gettime() to provide a specific time, you must
30 * enable time override with osmo_clock_override_enable(),
31 * then set a pointer to the timespec storing the fake time for that
32 * specific clock (`struct timespec *ts =
33 * osmo_clock_override_gettimespec()`) and set it as
34 * desired. Next time osmo_clock_gettime() is called, it will return the
35 * values previously set through the ts pointer.
36 * - A helper osmo_clock_override_add() is provided to increment a given
37 * overriden clock with a specific amount of time.
38 */
39
40/*! \file timer_clockgettime.c
41 */
42
Harald Welte14c4c492018-06-28 08:28:52 +020043#include "config.h"
44#ifdef HAVE_CLOCK_GETTIME
45
Pau Espin Pedrol87fade82018-02-26 19:42:22 +010046#include <stdlib.h>
47#include <stdbool.h>
48#include <sys/time.h>
49#include <time.h>
50
51#include <osmocom/core/timer_compat.h>
52
53/*! An internal structure to handle overriden time for each clock type. */
54struct fakeclock {
55 bool override;
56 struct timespec time;
57};
58
59static struct fakeclock realtime;
60static struct fakeclock realtime_coarse;
61static struct fakeclock mono;
62static struct fakeclock mono_coarse;
63static struct fakeclock mono_raw;
64static struct fakeclock boottime;
65static struct fakeclock boottime;
66static struct fakeclock proc_cputime_id;
67static struct fakeclock th_cputime_id;
68
69static struct fakeclock* clkid_to_fakeclock(clockid_t clk_id)
70{
71 switch(clk_id) {
72 case CLOCK_REALTIME:
73 return &realtime;
74 case CLOCK_REALTIME_COARSE:
75 return &realtime_coarse;
76 case CLOCK_MONOTONIC:
77 return &mono;
78 case CLOCK_MONOTONIC_COARSE:
79 return &mono_coarse;
80 case CLOCK_MONOTONIC_RAW:
81 return &mono_raw;
82 case CLOCK_BOOTTIME:
83 return &boottime;
84 case CLOCK_PROCESS_CPUTIME_ID:
85 return &proc_cputime_id;
86 case CLOCK_THREAD_CPUTIME_ID:
87 return &th_cputime_id;
88 default:
89 return NULL;
90 }
91}
92
93/*! Shim around clock_gettime to be able to set the time manually.
94 *
95 * To override, use osmo_clock_override_enable and set the desired
96 * current time with osmo_clock_gettimespec. */
97int osmo_clock_gettime(clockid_t clk_id, struct timespec *tp)
98{
99 struct fakeclock* c = clkid_to_fakeclock(clk_id);
100 if (!c || !c->override)
101 return clock_gettime(clk_id, tp);
102
103 *tp = c->time;
104 return 0;
105}
106
107/*! Convenience function to enable or disable a specific clock fake time.
108 */
109void osmo_clock_override_enable(clockid_t clk_id, bool enable)
110{
111 struct fakeclock* c = clkid_to_fakeclock(clk_id);
112 if (c)
113 c->override = enable;
114}
115
116/*! Convenience function to return a pointer to the timespec handling the
117 * fake time for clock clk_id. */
118struct timespec *osmo_clock_override_gettimespec(clockid_t clk_id)
119{
120 struct fakeclock* c = clkid_to_fakeclock(clk_id);
121 if (c)
122 return &c->time;
123 return NULL;
124}
125
126/*! Convenience function to advance the fake time.
127 *
128 * Adds the given values to the clock time. */
129void osmo_clock_override_add(clockid_t clk_id, time_t secs, long nsecs)
130{
131 struct timespec val = { secs, nsecs };
132 struct fakeclock* c = clkid_to_fakeclock(clk_id);
133 if (c)
134 timespecadd(&c->time, &val, &c->time);
135}
136
Harald Welte14c4c492018-06-28 08:28:52 +0200137#endif /* HAVE_CLOCK_GETTIME */
138
Pau Espin Pedrol87fade82018-02-26 19:42:22 +0100139/*! @} */