Skip to content

Commit 4b786e2

Browse files
jmberg-intelrichardweinberger
authored andcommitted
um: time-travel: Rewrite as an event scheduler
Instead of tracking all the various timer configurations, modify the time-travel mode to have an event scheduler and use a timer event on the scheduler to handle the different timer configurations. This doesn't change the function right now, but it prepares the code for having different kinds of events in the future (i.e. interrupts coming from other devices that are part of co-simulation.) While at it, also move time_travel_sleep() to time.c to reduce the externally visible API surface. Also, we really should mark time-travel as incompatible with SMP, even if UML doesn't support SMP yet. Finally, I noticed a bug while developing this - if we move time forward due to consuming time while reading the clock, we might move across the next event and that would cause us to go backward in time when we then handle that event. Fix that by invoking the whole event machine in this case, but in order to simplify this, make reading the clock only cost something when interrupts are not disabled. Otherwise, we'd have to hook into the interrupt delivery machinery etc. and that's somewhat intrusive. Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent f185063 commit 4b786e2

File tree

4 files changed

+229
-95
lines changed

4 files changed

+229
-95
lines changed

arch/um/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ config UML_TIME_TRAVEL_SUPPORT
191191
prompt "Support time-travel mode (e.g. for test execution)"
192192
# inf-cpu mode is incompatible with the benchmarking
193193
depends on !RAID6_PQ_BENCHMARK
194+
depends on !SMP
194195
help
195196
Enable this option to support time travel inside the UML instance.
196197

arch/um/include/linux/time-internal.h

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#ifndef __TIMER_INTERNAL_H__
88
#define __TIMER_INTERNAL_H__
9+
#include <linux/list.h>
910

1011
#define TIMER_MULTIPLIER 256
1112
#define TIMER_MIN_DELTA 500
@@ -16,61 +17,35 @@ enum time_travel_mode {
1617
TT_MODE_INFCPU,
1718
};
1819

19-
enum time_travel_timer_mode {
20-
TT_TMR_DISABLED,
21-
TT_TMR_ONESHOT,
22-
TT_TMR_PERIODIC,
20+
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
21+
struct time_travel_event {
22+
unsigned long long time;
23+
void (*fn)(struct time_travel_event *d);
24+
struct list_head list;
25+
bool pending, onstack;
2326
};
2427

25-
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
2628
extern enum time_travel_mode time_travel_mode;
27-
extern unsigned long long time_travel_time;
28-
extern enum time_travel_timer_mode time_travel_timer_mode;
29-
extern unsigned long long time_travel_timer_expiry;
30-
extern unsigned long long time_travel_timer_interval;
3129

32-
static inline void time_travel_set_time(unsigned long long ns)
33-
{
34-
time_travel_time = ns;
35-
}
30+
void time_travel_sleep(unsigned long long duration);
3631

37-
static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
32+
static inline void
33+
time_travel_set_event_fn(struct time_travel_event *e,
34+
void (*fn)(struct time_travel_event *d))
3835
{
39-
time_travel_timer_mode = mode;
40-
}
41-
42-
static inline void time_travel_set_timer_expiry(unsigned long long expiry)
43-
{
44-
time_travel_timer_expiry = expiry;
45-
}
46-
47-
static inline void time_travel_set_timer_interval(unsigned long long interval)
48-
{
49-
time_travel_timer_interval = interval;
36+
e->fn = fn;
5037
}
5138
#else
52-
#define time_travel_mode TT_MODE_OFF
53-
#define time_travel_time 0
54-
#define time_travel_timer_expiry 0
55-
#define time_travel_timer_interval 0
56-
57-
static inline void time_travel_set_time(unsigned long long ns)
58-
{
59-
}
60-
61-
static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
62-
{
63-
}
39+
struct time_travel_event {
40+
};
6441

65-
static inline void time_travel_set_timer_expiry(unsigned long long expiry)
66-
{
67-
}
42+
#define time_travel_mode TT_MODE_OFF
6843

69-
static inline void time_travel_set_timer_interval(unsigned long long interval)
44+
static inline void time_travel_sleep(unsigned long long duration)
7045
{
7146
}
7247

73-
#define time_travel_timer_mode TT_TMR_DISABLED
74-
#endif
75-
76-
#endif
48+
/* this is a macro so the event/function need not exist */
49+
#define time_travel_set_event_fn(e, fn) do {} while (0)
50+
#endif /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
51+
#endif /* __TIMER_INTERNAL_H__ */

arch/um/kernel/process.c

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -203,43 +203,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
203203
kmalloc_ok = save_kmalloc_ok;
204204
}
205205

206-
static void time_travel_sleep(unsigned long long duration)
207-
{
208-
unsigned long long next = time_travel_time + duration;
209-
210-
if (time_travel_mode != TT_MODE_INFCPU)
211-
os_timer_disable();
212-
213-
while (time_travel_timer_mode == TT_TMR_PERIODIC &&
214-
time_travel_timer_expiry < time_travel_time)
215-
time_travel_set_timer_expiry(time_travel_timer_expiry +
216-
time_travel_timer_interval);
217-
218-
if (time_travel_timer_mode != TT_TMR_DISABLED &&
219-
time_travel_timer_expiry < next) {
220-
if (time_travel_timer_mode == TT_TMR_ONESHOT)
221-
time_travel_set_timer_mode(TT_TMR_DISABLED);
222-
/*
223-
* In basic mode, time_travel_time will be adjusted in
224-
* the timer IRQ handler so it works even when the signal
225-
* comes from the OS timer, see there.
226-
*/
227-
if (time_travel_mode != TT_MODE_BASIC)
228-
time_travel_set_time(time_travel_timer_expiry);
229-
230-
deliver_alarm();
231-
} else {
232-
time_travel_set_time(next);
233-
}
234-
235-
if (time_travel_mode != TT_MODE_INFCPU) {
236-
if (time_travel_timer_mode == TT_TMR_PERIODIC)
237-
os_timer_set_interval(time_travel_timer_interval);
238-
else if (time_travel_timer_mode == TT_TMR_ONESHOT)
239-
os_timer_one_shot(time_travel_timer_expiry - next);
240-
}
241-
}
242-
243206
static void um_idle_sleep(void)
244207
{
245208
unsigned long long duration = UM_NSEC_PER_SEC;

0 commit comments

Comments
 (0)