aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/time.c
diff options
context:
space:
mode:
authorAnton Ivanov <aivanov@brocade.com>2015-11-02 11:16:37 -0500
committerRichard Weinberger <richard@nod.at>2015-11-06 16:54:49 -0500
commit2eb5f31bc4ea24bb293e82934cfa1cce9573304b (patch)
tree69c2d1f775babd528d0873660c97d78f52318641 /arch/um/kernel/time.c
parente17c6d77b28c6feab446ad6eaec865e8031ed616 (diff)
um: Switch clocksource to hrtimers
UML is using an obsolete itimer call for all timers and "polls" for kernel space timer firing in its userspace portion resulting in a long list of bugs and incorrect behaviour(s). It also uses ITIMER_VIRTUAL for its timer which results in the timer being dependent on it running and the cpu load. This patch fixes this by moving to posix high resolution timers firing off CLOCK_MONOTONIC and relaying the timer correctly to the UML userspace. Fixes: - crashes when hosts suspends/resumes - broken userspace timers - effecive ~40Hz instead of what they should be. Note - this modifies skas behavior by no longer setting an itimer per clone(). Timer events are relayed instead. - kernel network packet scheduling disciplines - tcp behaviour especially under load - various timer related corner cases Finally, overall responsiveness of userspace is better. Signed-off-by: Thomas Meyer <thomas@m3y3r.de> Signed-off-by: Anton Ivanov <aivanov@brocade.com> [rw: massaged commit message] Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel/time.c')
-rw-r--r--arch/um/kernel/time.c73
1 files changed, 48 insertions, 25 deletions
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 5af441efb377..25c23666d592 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -1,4 +1,7 @@
1/* 1/*
2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
4 * Copyright (C) 2012-2014 Cisco Systems
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 6 * Licensed under the GPL
4 */ 7 */
@@ -7,11 +10,15 @@
7#include <linux/init.h> 10#include <linux/init.h>
8#include <linux/interrupt.h> 11#include <linux/interrupt.h>
9#include <linux/jiffies.h> 12#include <linux/jiffies.h>
13#include <linux/mm.h>
14#include <linux/sched.h>
15#include <linux/spinlock.h>
10#include <linux/threads.h> 16#include <linux/threads.h>
11#include <asm/irq.h> 17#include <asm/irq.h>
12#include <asm/param.h> 18#include <asm/param.h>
13#include <kern_util.h> 19#include <kern_util.h>
14#include <os.h> 20#include <os.h>
21#include <timer-internal.h>
15 22
16void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 23void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
17{ 24{
@@ -24,81 +31,97 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
24 31
25static int itimer_shutdown(struct clock_event_device *evt) 32static int itimer_shutdown(struct clock_event_device *evt)
26{ 33{
27 disable_timer(); 34 os_timer_disable();
28 return 0; 35 return 0;
29} 36}
30 37
31static int itimer_set_periodic(struct clock_event_device *evt) 38static int itimer_set_periodic(struct clock_event_device *evt)
32{ 39{
33 set_interval(); 40 os_timer_set_interval(NULL, NULL);
34 return 0; 41 return 0;
35} 42}
36 43
37static int itimer_next_event(unsigned long delta, 44static int itimer_next_event(unsigned long delta,
38 struct clock_event_device *evt) 45 struct clock_event_device *evt)
39{ 46{
40 return timer_one_shot(delta + 1); 47 return os_timer_one_shot(delta);
41} 48}
42 49
43static struct clock_event_device itimer_clockevent = { 50static int itimer_one_shot(struct clock_event_device *evt)
44 .name = "itimer", 51{
52 os_timer_one_shot(1);
53 return 0;
54}
55
56static struct clock_event_device timer_clockevent = {
57 .name = "posix-timer",
45 .rating = 250, 58 .rating = 250,
46 .cpumask = cpu_all_mask, 59 .cpumask = cpu_all_mask,
47 .features = CLOCK_EVT_FEAT_PERIODIC | 60 .features = CLOCK_EVT_FEAT_PERIODIC |
48 CLOCK_EVT_FEAT_ONESHOT, 61 CLOCK_EVT_FEAT_ONESHOT,
49 .set_state_shutdown = itimer_shutdown, 62 .set_state_shutdown = itimer_shutdown,
50 .set_state_periodic = itimer_set_periodic, 63 .set_state_periodic = itimer_set_periodic,
51 .set_state_oneshot = itimer_shutdown, 64 .set_state_oneshot = itimer_one_shot,
52 .set_next_event = itimer_next_event, 65 .set_next_event = itimer_next_event,
53 .shift = 32, 66 .shift = 0,
67 .max_delta_ns = 0xffffffff,
68 .min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should be enough for anyone, same as 640K RAM
54 .irq = 0, 69 .irq = 0,
70 .mult = 1,
55}; 71};
56 72
57static irqreturn_t um_timer(int irq, void *dev) 73static irqreturn_t um_timer(int irq, void *dev)
58{ 74{
59 (*itimer_clockevent.event_handler)(&itimer_clockevent); 75 if (get_current()->mm != NULL)
76 {
77 /* userspace - relay signal, results in correct userspace timers */
78 os_alarm_process(get_current()->mm->context.id.u.pid);
79 }
80
81 (*timer_clockevent.event_handler)(&timer_clockevent);
60 82
61 return IRQ_HANDLED; 83 return IRQ_HANDLED;
62} 84}
63 85
64static cycle_t itimer_read(struct clocksource *cs) 86static cycle_t timer_read(struct clocksource *cs)
65{ 87{
66 return os_nsecs() / 1000; 88 return os_nsecs() / TIMER_MULTIPLIER;
67} 89}
68 90
69static struct clocksource itimer_clocksource = { 91static struct clocksource timer_clocksource = {
70 .name = "itimer", 92 .name = "timer",
71 .rating = 300, 93 .rating = 300,
72 .read = itimer_read, 94 .read = timer_read,
73 .mask = CLOCKSOURCE_MASK(64), 95 .mask = CLOCKSOURCE_MASK(64),
74 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 96 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
75}; 97};
76 98
77static void __init setup_itimer(void) 99static void __init timer_setup(void)
78{ 100{
79 int err; 101 int err;
80 102
81 err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); 103 err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
82 if (err != 0) 104 if (err != 0)
83 printk(KERN_ERR "register_timer : request_irq failed - " 105 printk(KERN_ERR "register_timer : request_irq failed - "
84 "errno = %d\n", -err); 106 "errno = %d\n", -err);
85 107
86 itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32); 108 err = os_timer_create(NULL);
87 itimer_clockevent.max_delta_ns = 109 if (err != 0) {
88 clockevent_delta2ns(60 * HZ, &itimer_clockevent); 110 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
89 itimer_clockevent.min_delta_ns = 111 return;
90 clockevent_delta2ns(1, &itimer_clockevent); 112 }
91 err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); 113
114 err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
92 if (err) { 115 if (err) {
93 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 116 printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
94 return; 117 return;
95 } 118 }
96 clockevents_register_device(&itimer_clockevent); 119 clockevents_register_device(&timer_clockevent);
97} 120}
98 121
99void read_persistent_clock(struct timespec *ts) 122void read_persistent_clock(struct timespec *ts)
100{ 123{
101 long long nsecs = os_nsecs(); 124 long long nsecs = os_persistent_clock_emulation();
102 125
103 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, 126 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
104 nsecs % NSEC_PER_SEC); 127 nsecs % NSEC_PER_SEC);
@@ -106,6 +129,6 @@ void read_persistent_clock(struct timespec *ts)
106 129
107void __init time_init(void) 130void __init time_init(void)
108{ 131{
109 timer_init(); 132 timer_set_signal_handler();
110 late_time_init = setup_itimer; 133 late_time_init = timer_setup;
111} 134}