diff options
-rw-r--r-- | arch/um/Makefile | 2 | ||||
-rw-r--r-- | arch/um/include/shared/os.h | 18 | ||||
-rw-r--r-- | arch/um/include/shared/skas/stub-data.h | 7 | ||||
-rw-r--r-- | arch/um/include/shared/timer-internal.h | 13 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 8 | ||||
-rw-r--r-- | arch/um/kernel/skas/clone.c | 6 | ||||
-rw-r--r-- | arch/um/kernel/skas/mmu.c | 3 | ||||
-rw-r--r-- | arch/um/kernel/time.c | 73 | ||||
-rw-r--r-- | arch/um/os-Linux/internal.h | 1 | ||||
-rw-r--r-- | arch/um/os-Linux/main.c | 7 | ||||
-rw-r--r-- | arch/um/os-Linux/process.c | 6 | ||||
-rw-r--r-- | arch/um/os-Linux/signal.c | 41 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 45 | ||||
-rw-r--r-- | arch/um/os-Linux/time.c | 249 |
14 files changed, 255 insertions, 224 deletions
diff --git a/arch/um/Makefile b/arch/um/Makefile index e3abe6f3156d..25ed4098640e 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
@@ -131,7 +131,7 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT) | |||
131 | # The wrappers will select whether using "malloc" or the kernel allocator. | 131 | # The wrappers will select whether using "malloc" or the kernel allocator. |
132 | LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc | 132 | LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc |
133 | 133 | ||
134 | LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) | 134 | LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -lrt |
135 | 135 | ||
136 | # Used by link-vmlinux.sh which has special support for um link | 136 | # Used by link-vmlinux.sh which has special support for um link |
137 | export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) | 137 | export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) |
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index f3cbaef20e04..868e6c3f83dd 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) | ||
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 4 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 5 | * Licensed under the GPL |
4 | */ | 6 | */ |
@@ -183,6 +185,7 @@ extern int create_mem_file(unsigned long long len); | |||
183 | /* process.c */ | 185 | /* process.c */ |
184 | extern unsigned long os_process_pc(int pid); | 186 | extern unsigned long os_process_pc(int pid); |
185 | extern int os_process_parent(int pid); | 187 | extern int os_process_parent(int pid); |
188 | extern void os_alarm_process(int pid); | ||
186 | extern void os_stop_process(int pid); | 189 | extern void os_stop_process(int pid); |
187 | extern void os_kill_process(int pid, int reap_child); | 190 | extern void os_kill_process(int pid, int reap_child); |
188 | extern void os_kill_ptraced_process(int pid, int reap_child); | 191 | extern void os_kill_ptraced_process(int pid, int reap_child); |
@@ -217,7 +220,7 @@ extern int set_umid(char *name); | |||
217 | extern char *get_umid(void); | 220 | extern char *get_umid(void); |
218 | 221 | ||
219 | /* signal.c */ | 222 | /* signal.c */ |
220 | extern void timer_init(void); | 223 | extern void timer_set_signal_handler(void); |
221 | extern void set_sigstack(void *sig_stack, int size); | 224 | extern void set_sigstack(void *sig_stack, int size); |
222 | extern void remove_sigstack(void); | 225 | extern void remove_sigstack(void); |
223 | extern void set_handler(int sig); | 226 | extern void set_handler(int sig); |
@@ -227,6 +230,7 @@ extern void unblock_signals(void); | |||
227 | extern int get_signals(void); | 230 | extern int get_signals(void); |
228 | extern int set_signals(int enable); | 231 | extern int set_signals(int enable); |
229 | extern int os_is_signal_stack(void); | 232 | extern int os_is_signal_stack(void); |
233 | extern void deliver_alarm(void); | ||
230 | 234 | ||
231 | /* util.c */ | 235 | /* util.c */ |
232 | extern void stack_protections(unsigned long address); | 236 | extern void stack_protections(unsigned long address); |
@@ -238,12 +242,16 @@ extern void um_early_printk(const char *s, unsigned int n); | |||
238 | extern void os_fix_helper_signals(void); | 242 | extern void os_fix_helper_signals(void); |
239 | 243 | ||
240 | /* time.c */ | 244 | /* time.c */ |
241 | extern void idle_sleep(unsigned long long nsecs); | 245 | extern void os_idle_sleep(unsigned long long nsecs); |
242 | extern int set_interval(void); | 246 | extern int os_timer_create(void* timer); |
243 | extern int timer_one_shot(int ticks); | 247 | extern int os_timer_set_interval(void* timer, void* its); |
244 | extern long long disable_timer(void); | 248 | extern int os_timer_one_shot(int ticks); |
249 | extern long long os_timer_disable(void); | ||
250 | extern long os_timer_remain(void* timer); | ||
245 | extern void uml_idle_timer(void); | 251 | extern void uml_idle_timer(void); |
252 | extern long long os_persistent_clock_emulation(void); | ||
246 | extern long long os_nsecs(void); | 253 | extern long long os_nsecs(void); |
254 | extern long long os_vnsecs(void); | ||
247 | 255 | ||
248 | /* skas/mem.c */ | 256 | /* skas/mem.c */ |
249 | extern long run_syscall_stub(struct mm_id * mm_idp, | 257 | extern long run_syscall_stub(struct mm_id * mm_idp, |
diff --git a/arch/um/include/shared/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h index f6ed92c3727d..a9deece956bf 100644 --- a/arch/um/include/shared/skas/stub-data.h +++ b/arch/um/include/shared/skas/stub-data.h | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | |||
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) | 4 | * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 5 | * Licensed under the GPL |
4 | */ | 6 | */ |
@@ -6,12 +8,11 @@ | |||
6 | #ifndef __STUB_DATA_H | 8 | #ifndef __STUB_DATA_H |
7 | #define __STUB_DATA_H | 9 | #define __STUB_DATA_H |
8 | 10 | ||
9 | #include <sys/time.h> | 11 | #include <time.h> |
10 | 12 | ||
11 | struct stub_data { | 13 | struct stub_data { |
12 | long offset; | 14 | unsigned long offset; |
13 | int fd; | 15 | int fd; |
14 | struct itimerval timer; | ||
15 | long err; | 16 | long err; |
16 | }; | 17 | }; |
17 | 18 | ||
diff --git a/arch/um/include/shared/timer-internal.h b/arch/um/include/shared/timer-internal.h new file mode 100644 index 000000000000..03e6f217f807 --- /dev/null +++ b/arch/um/include/shared/timer-internal.h | |||
@@ -0,0 +1,13 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 - 2014 Cisco Systems | ||
3 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #ifndef __TIMER_INTERNAL_H__ | ||
8 | #define __TIMER_INTERNAL_H__ | ||
9 | |||
10 | #define TIMER_MULTIPLIER 256 | ||
11 | #define TIMER_MIN_DELTA 500 | ||
12 | |||
13 | #endif | ||
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index a6d922672b9f..48af59aae129 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) | ||
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 4 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Copyright 2003 PathScale, Inc. | 5 | * Copyright 2003 PathScale, Inc. |
4 | * Licensed under the GPL | 6 | * Licensed under the GPL |
@@ -27,6 +29,7 @@ | |||
27 | #include <kern_util.h> | 29 | #include <kern_util.h> |
28 | #include <os.h> | 30 | #include <os.h> |
29 | #include <skas.h> | 31 | #include <skas.h> |
32 | #include <timer-internal.h> | ||
30 | 33 | ||
31 | /* | 34 | /* |
32 | * This is a per-cpu array. A processor only modifies its entry and it only | 35 | * This is a per-cpu array. A processor only modifies its entry and it only |
@@ -203,11 +206,8 @@ void initial_thread_cb(void (*proc)(void *), void *arg) | |||
203 | 206 | ||
204 | void arch_cpu_idle(void) | 207 | void arch_cpu_idle(void) |
205 | { | 208 | { |
206 | unsigned long long nsecs; | ||
207 | |||
208 | cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); | 209 | cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); |
209 | nsecs = disable_timer(); | 210 | os_idle_sleep(UM_NSEC_PER_SEC); |
210 | idle_sleep(nsecs); | ||
211 | local_irq_enable(); | 211 | local_irq_enable(); |
212 | } | 212 | } |
213 | 213 | ||
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 289771dadf81..0f25d41b1031 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 3 | * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -35,11 +36,6 @@ stub_clone_handler(void) | |||
35 | if (err) | 36 | if (err) |
36 | goto out; | 37 | goto out; |
37 | 38 | ||
38 | err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, | ||
39 | (long) &data->timer, 0); | ||
40 | if (err) | ||
41 | goto out; | ||
42 | |||
43 | remap_stack(data->fd, data->offset); | 39 | remap_stack(data->fd, data->offset); |
44 | goto done; | 40 | goto done; |
45 | 41 | ||
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index fda1deba1757..9591a66aa5c5 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 3 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -61,10 +62,12 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) | |||
61 | if (current->mm != NULL && current->mm != &init_mm) | 62 | if (current->mm != NULL && current->mm != &init_mm) |
62 | from_mm = ¤t->mm->context; | 63 | from_mm = ¤t->mm->context; |
63 | 64 | ||
65 | block_signals(); | ||
64 | if (from_mm) | 66 | if (from_mm) |
65 | to_mm->id.u.pid = copy_context_skas0(stack, | 67 | to_mm->id.u.pid = copy_context_skas0(stack, |
66 | from_mm->id.u.pid); | 68 | from_mm->id.u.pid); |
67 | else to_mm->id.u.pid = start_userspace(stack); | 69 | else to_mm->id.u.pid = start_userspace(stack); |
70 | unblock_signals(); | ||
68 | 71 | ||
69 | if (to_mm->id.u.pid < 0) { | 72 | if (to_mm->id.u.pid < 0) { |
70 | ret = to_mm->id.u.pid; | 73 | ret = to_mm->id.u.pid; |
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 | ||
16 | void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) | 23 | void 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 | ||
25 | static int itimer_shutdown(struct clock_event_device *evt) | 32 | static 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 | ||
31 | static int itimer_set_periodic(struct clock_event_device *evt) | 38 | static 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 | ||
37 | static int itimer_next_event(unsigned long delta, | 44 | static 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 | ||
43 | static struct clock_event_device itimer_clockevent = { | 50 | static int itimer_one_shot(struct clock_event_device *evt) |
44 | .name = "itimer", | 51 | { |
52 | os_timer_one_shot(1); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static 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 | ||
57 | static irqreturn_t um_timer(int irq, void *dev) | 73 | static 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 | ||
64 | static cycle_t itimer_read(struct clocksource *cs) | 86 | static cycle_t timer_read(struct clocksource *cs) |
65 | { | 87 | { |
66 | return os_nsecs() / 1000; | 88 | return os_nsecs() / TIMER_MULTIPLIER; |
67 | } | 89 | } |
68 | 90 | ||
69 | static struct clocksource itimer_clocksource = { | 91 | static 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 | ||
77 | static void __init setup_itimer(void) | 99 | static 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 | ||
99 | void read_persistent_clock(struct timespec *ts) | 122 | void 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 | ||
107 | void __init time_init(void) | 130 | void __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 | } |
diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h deleted file mode 100644 index 0dc2c9f135f6..000000000000 --- a/arch/um/os-Linux/internal.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc); | ||
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index df9191acd926..9d499de87e63 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 3 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -163,13 +164,13 @@ int __init main(int argc, char **argv, char **envp) | |||
163 | 164 | ||
164 | /* | 165 | /* |
165 | * This signal stuff used to be in the reboot case. However, | 166 | * This signal stuff used to be in the reboot case. However, |
166 | * sometimes a SIGVTALRM can come in when we're halting (reproducably | 167 | * sometimes a timer signal can come in when we're halting (reproducably |
167 | * when writing out gcov information, presumably because that takes | 168 | * when writing out gcov information, presumably because that takes |
168 | * some time) and cause a segfault. | 169 | * some time) and cause a segfault. |
169 | */ | 170 | */ |
170 | 171 | ||
171 | /* stop timers and set SIGVTALRM to be ignored */ | 172 | /* stop timers and set timer signal to be ignored */ |
172 | disable_timer(); | 173 | os_timer_disable(); |
173 | 174 | ||
174 | /* disable SIGIO for the fds and set SIGIO to be ignored */ | 175 | /* disable SIGIO for the fds and set SIGIO to be ignored */ |
175 | err = deactivate_all_fds(); | 176 | err = deactivate_all_fds(); |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index 8408aba915b2..b3e0d40932e1 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 3 | * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -89,6 +90,11 @@ int os_process_parent(int pid) | |||
89 | return parent; | 90 | return parent; |
90 | } | 91 | } |
91 | 92 | ||
93 | void os_alarm_process(int pid) | ||
94 | { | ||
95 | kill(pid, SIGALRM); | ||
96 | } | ||
97 | |||
92 | void os_stop_process(int pid) | 98 | void os_stop_process(int pid) |
93 | { | 99 | { |
94 | kill(pid, SIGSTOP); | 100 | kill(pid, SIGSTOP); |
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 036d0dbc7b52..c211153ca69a 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) | ||
3 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2004 PathScale, Inc | 4 | * Copyright (C) 2004 PathScale, Inc |
3 | * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 5 | * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
4 | * Licensed under the GPL | 6 | * Licensed under the GPL |
@@ -13,7 +15,6 @@ | |||
13 | #include <kern_util.h> | 15 | #include <kern_util.h> |
14 | #include <os.h> | 16 | #include <os.h> |
15 | #include <sysdep/mcontext.h> | 17 | #include <sysdep/mcontext.h> |
16 | #include "internal.h" | ||
17 | 18 | ||
18 | void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { | 19 | void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { |
19 | [SIGTRAP] = relay_signal, | 20 | [SIGTRAP] = relay_signal, |
@@ -23,7 +24,8 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { | |||
23 | [SIGBUS] = bus_handler, | 24 | [SIGBUS] = bus_handler, |
24 | [SIGSEGV] = segv_handler, | 25 | [SIGSEGV] = segv_handler, |
25 | [SIGIO] = sigio_handler, | 26 | [SIGIO] = sigio_handler, |
26 | [SIGVTALRM] = timer_handler }; | 27 | [SIGALRM] = timer_handler |
28 | }; | ||
27 | 29 | ||
28 | static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) | 30 | static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) |
29 | { | 31 | { |
@@ -38,7 +40,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) | |||
38 | } | 40 | } |
39 | 41 | ||
40 | /* enable signals if sig isn't IRQ signal */ | 42 | /* enable signals if sig isn't IRQ signal */ |
41 | if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) | 43 | if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM)) |
42 | unblock_signals(); | 44 | unblock_signals(); |
43 | 45 | ||
44 | (*sig_info[sig])(sig, si, &r); | 46 | (*sig_info[sig])(sig, si, &r); |
@@ -55,8 +57,8 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) | |||
55 | #define SIGIO_BIT 0 | 57 | #define SIGIO_BIT 0 |
56 | #define SIGIO_MASK (1 << SIGIO_BIT) | 58 | #define SIGIO_MASK (1 << SIGIO_BIT) |
57 | 59 | ||
58 | #define SIGVTALRM_BIT 1 | 60 | #define SIGALRM_BIT 1 |
59 | #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) | 61 | #define SIGALRM_MASK (1 << SIGALRM_BIT) |
60 | 62 | ||
61 | static int signals_enabled; | 63 | static int signals_enabled; |
62 | static unsigned int signals_pending; | 64 | static unsigned int signals_pending; |
@@ -78,36 +80,38 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) | |||
78 | set_signals(enabled); | 80 | set_signals(enabled); |
79 | } | 81 | } |
80 | 82 | ||
81 | static void real_alarm_handler(mcontext_t *mc) | 83 | static void timer_real_alarm_handler(mcontext_t *mc) |
82 | { | 84 | { |
83 | struct uml_pt_regs regs; | 85 | struct uml_pt_regs regs; |
84 | 86 | ||
85 | if (mc != NULL) | 87 | if (mc != NULL) |
86 | get_regs_from_mc(®s, mc); | 88 | get_regs_from_mc(®s, mc); |
87 | regs.is_user = 0; | 89 | timer_handler(SIGALRM, NULL, ®s); |
88 | unblock_signals(); | ||
89 | timer_handler(SIGVTALRM, NULL, ®s); | ||
90 | } | 90 | } |
91 | 91 | ||
92 | void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) | 92 | void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) |
93 | { | 93 | { |
94 | int enabled; | 94 | int enabled; |
95 | 95 | ||
96 | enabled = signals_enabled; | 96 | enabled = signals_enabled; |
97 | if (!signals_enabled) { | 97 | if (!signals_enabled) { |
98 | signals_pending |= SIGVTALRM_MASK; | 98 | signals_pending |= SIGALRM_MASK; |
99 | return; | 99 | return; |
100 | } | 100 | } |
101 | 101 | ||
102 | block_signals(); | 102 | block_signals(); |
103 | 103 | ||
104 | real_alarm_handler(mc); | 104 | timer_real_alarm_handler(mc); |
105 | set_signals(enabled); | 105 | set_signals(enabled); |
106 | } | 106 | } |
107 | 107 | ||
108 | void timer_init(void) | 108 | void deliver_alarm(void) { |
109 | timer_alarm_handler(SIGALRM, NULL, NULL); | ||
110 | } | ||
111 | |||
112 | void timer_set_signal_handler(void) | ||
109 | { | 113 | { |
110 | set_handler(SIGVTALRM); | 114 | set_handler(SIGALRM); |
111 | } | 115 | } |
112 | 116 | ||
113 | void set_sigstack(void *sig_stack, int size) | 117 | void set_sigstack(void *sig_stack, int size) |
@@ -131,10 +135,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { | |||
131 | 135 | ||
132 | [SIGIO] = sig_handler, | 136 | [SIGIO] = sig_handler, |
133 | [SIGWINCH] = sig_handler, | 137 | [SIGWINCH] = sig_handler, |
134 | [SIGVTALRM] = alarm_handler | 138 | [SIGALRM] = timer_alarm_handler |
135 | }; | 139 | }; |
136 | 140 | ||
137 | |||
138 | static void hard_handler(int sig, siginfo_t *si, void *p) | 141 | static void hard_handler(int sig, siginfo_t *si, void *p) |
139 | { | 142 | { |
140 | struct ucontext *uc = p; | 143 | struct ucontext *uc = p; |
@@ -188,9 +191,9 @@ void set_handler(int sig) | |||
188 | 191 | ||
189 | /* block irq ones */ | 192 | /* block irq ones */ |
190 | sigemptyset(&action.sa_mask); | 193 | sigemptyset(&action.sa_mask); |
191 | sigaddset(&action.sa_mask, SIGVTALRM); | ||
192 | sigaddset(&action.sa_mask, SIGIO); | 194 | sigaddset(&action.sa_mask, SIGIO); |
193 | sigaddset(&action.sa_mask, SIGWINCH); | 195 | sigaddset(&action.sa_mask, SIGWINCH); |
196 | sigaddset(&action.sa_mask, SIGALRM); | ||
194 | 197 | ||
195 | if (sig == SIGSEGV) | 198 | if (sig == SIGSEGV) |
196 | flags |= SA_NODEFER; | 199 | flags |= SA_NODEFER; |
@@ -283,8 +286,8 @@ void unblock_signals(void) | |||
283 | if (save_pending & SIGIO_MASK) | 286 | if (save_pending & SIGIO_MASK) |
284 | sig_handler_common(SIGIO, NULL, NULL); | 287 | sig_handler_common(SIGIO, NULL, NULL); |
285 | 288 | ||
286 | if (save_pending & SIGVTALRM_MASK) | 289 | if (save_pending & SIGALRM_MASK) |
287 | real_alarm_handler(NULL); | 290 | timer_real_alarm_handler(NULL); |
288 | } | 291 | } |
289 | } | 292 | } |
290 | 293 | ||
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index d38f4952d748..b856c66ebd3a 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) | ||
2 | * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | 3 | * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -45,7 +46,7 @@ static int ptrace_dump_regs(int pid) | |||
45 | * Signals that are OK to receive in the stub - we'll just continue it. | 46 | * Signals that are OK to receive in the stub - we'll just continue it. |
46 | * SIGWINCH will happen when UML is inside a detached screen. | 47 | * SIGWINCH will happen when UML is inside a detached screen. |
47 | */ | 48 | */ |
48 | #define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) | 49 | #define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH)) |
49 | 50 | ||
50 | /* Signals that the stub will finish with - anything else is an error */ | 51 | /* Signals that the stub will finish with - anything else is an error */ |
51 | #define STUB_DONE_MASK (1 << SIGTRAP) | 52 | #define STUB_DONE_MASK (1 << SIGTRAP) |
@@ -183,19 +184,13 @@ extern char __syscall_stub_start[]; | |||
183 | static int userspace_tramp(void *stack) | 184 | static int userspace_tramp(void *stack) |
184 | { | 185 | { |
185 | void *addr; | 186 | void *addr; |
186 | int err, fd; | 187 | int fd; |
187 | unsigned long long offset; | 188 | unsigned long long offset; |
188 | 189 | ||
189 | ptrace(PTRACE_TRACEME, 0, 0, 0); | 190 | ptrace(PTRACE_TRACEME, 0, 0, 0); |
190 | 191 | ||
191 | signal(SIGTERM, SIG_DFL); | 192 | signal(SIGTERM, SIG_DFL); |
192 | signal(SIGWINCH, SIG_IGN); | 193 | signal(SIGWINCH, SIG_IGN); |
193 | err = set_interval(); | ||
194 | if (err) { | ||
195 | printk(UM_KERN_ERR "userspace_tramp - setting timer failed, " | ||
196 | "errno = %d\n", err); | ||
197 | exit(1); | ||
198 | } | ||
199 | 194 | ||
200 | /* | 195 | /* |
201 | * This has a pte, but it can't be mapped in with the usual | 196 | * This has a pte, but it can't be mapped in with the usual |
@@ -286,7 +281,7 @@ int start_userspace(unsigned long stub_stack) | |||
286 | "errno = %d\n", errno); | 281 | "errno = %d\n", errno); |
287 | goto out_kill; | 282 | goto out_kill; |
288 | } | 283 | } |
289 | } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); | 284 | } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM)); |
290 | 285 | ||
291 | if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { | 286 | if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { |
292 | err = -EINVAL; | 287 | err = -EINVAL; |
@@ -319,8 +314,6 @@ int start_userspace(unsigned long stub_stack) | |||
319 | 314 | ||
320 | void userspace(struct uml_pt_regs *regs) | 315 | void userspace(struct uml_pt_regs *regs) |
321 | { | 316 | { |
322 | struct itimerval timer; | ||
323 | unsigned long long nsecs, now; | ||
324 | int err, status, op, pid = userspace_pid[0]; | 317 | int err, status, op, pid = userspace_pid[0]; |
325 | /* To prevent races if using_sysemu changes under us.*/ | 318 | /* To prevent races if using_sysemu changes under us.*/ |
326 | int local_using_sysemu; | 319 | int local_using_sysemu; |
@@ -329,13 +322,8 @@ void userspace(struct uml_pt_regs *regs) | |||
329 | /* Handle any immediate reschedules or signals */ | 322 | /* Handle any immediate reschedules or signals */ |
330 | interrupt_end(); | 323 | interrupt_end(); |
331 | 324 | ||
332 | if (getitimer(ITIMER_VIRTUAL, &timer)) | ||
333 | printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno); | ||
334 | nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + | ||
335 | timer.it_value.tv_usec * UM_NSEC_PER_USEC; | ||
336 | nsecs += os_nsecs(); | ||
337 | |||
338 | while (1) { | 325 | while (1) { |
326 | |||
339 | /* | 327 | /* |
340 | * This can legitimately fail if the process loads a | 328 | * This can legitimately fail if the process loads a |
341 | * bogus value into a segment register. It will | 329 | * bogus value into a segment register. It will |
@@ -405,18 +393,7 @@ void userspace(struct uml_pt_regs *regs) | |||
405 | case SIGTRAP: | 393 | case SIGTRAP: |
406 | relay_signal(SIGTRAP, (struct siginfo *)&si, regs); | 394 | relay_signal(SIGTRAP, (struct siginfo *)&si, regs); |
407 | break; | 395 | break; |
408 | case SIGVTALRM: | 396 | case SIGALRM: |
409 | now = os_nsecs(); | ||
410 | if (now < nsecs) | ||
411 | break; | ||
412 | block_signals(); | ||
413 | (*sig_info[sig])(sig, (struct siginfo *)&si, regs); | ||
414 | unblock_signals(); | ||
415 | nsecs = timer.it_value.tv_sec * | ||
416 | UM_NSEC_PER_SEC + | ||
417 | timer.it_value.tv_usec * | ||
418 | UM_NSEC_PER_USEC; | ||
419 | nsecs += os_nsecs(); | ||
420 | break; | 397 | break; |
421 | case SIGIO: | 398 | case SIGIO: |
422 | case SIGILL: | 399 | case SIGILL: |
@@ -464,7 +441,6 @@ __initcall(init_thread_regs); | |||
464 | 441 | ||
465 | int copy_context_skas0(unsigned long new_stack, int pid) | 442 | int copy_context_skas0(unsigned long new_stack, int pid) |
466 | { | 443 | { |
467 | struct timeval tv = { .tv_sec = 0, .tv_usec = UM_USEC_PER_SEC / UM_HZ }; | ||
468 | int err; | 444 | int err; |
469 | unsigned long current_stack = current_stub_stack(); | 445 | unsigned long current_stack = current_stub_stack(); |
470 | struct stub_data *data = (struct stub_data *) current_stack; | 446 | struct stub_data *data = (struct stub_data *) current_stack; |
@@ -476,11 +452,10 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
476 | * prepare offset and fd of child's stack as argument for parent's | 452 | * prepare offset and fd of child's stack as argument for parent's |
477 | * and child's mmap2 calls | 453 | * and child's mmap2 calls |
478 | */ | 454 | */ |
479 | *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), | 455 | *data = ((struct stub_data) { |
480 | .fd = new_fd, | 456 | .offset = MMAP_OFFSET(new_offset), |
481 | .timer = ((struct itimerval) | 457 | .fd = new_fd |
482 | { .it_value = tv, | 458 | }); |
483 | .it_interval = tv }) }); | ||
484 | 459 | ||
485 | err = ptrace_setregs(pid, thread_regs); | 460 | err = ptrace_setregs(pid, thread_regs); |
486 | if (err < 0) { | 461 | if (err < 0) { |
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index e9824d5dd7d5..0e39b9978729 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/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 | */ |
@@ -10,177 +13,177 @@ | |||
10 | #include <sys/time.h> | 13 | #include <sys/time.h> |
11 | #include <kern_util.h> | 14 | #include <kern_util.h> |
12 | #include <os.h> | 15 | #include <os.h> |
13 | #include "internal.h" | 16 | #include <string.h> |
17 | #include <timer-internal.h> | ||
14 | 18 | ||
15 | int set_interval(void) | 19 | static timer_t event_high_res_timer = 0; |
16 | { | ||
17 | int usec = UM_USEC_PER_SEC / UM_HZ; | ||
18 | struct itimerval interval = ((struct itimerval) { { 0, usec }, | ||
19 | { 0, usec } }); | ||
20 | |||
21 | if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) | ||
22 | return -errno; | ||
23 | 20 | ||
24 | return 0; | 21 | static inline long long timeval_to_ns(const struct timeval *tv) |
22 | { | ||
23 | return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + | ||
24 | tv->tv_usec * UM_NSEC_PER_USEC; | ||
25 | } | 25 | } |
26 | 26 | ||
27 | int timer_one_shot(int ticks) | 27 | static inline long long timespec_to_ns(const struct timespec *ts) |
28 | { | 28 | { |
29 | unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ; | 29 | return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + |
30 | unsigned long sec = usec / UM_USEC_PER_SEC; | 30 | ts->tv_nsec; |
31 | struct itimerval interval; | 31 | } |
32 | |||
33 | usec %= UM_USEC_PER_SEC; | ||
34 | interval = ((struct itimerval) { { 0, 0 }, { sec, usec } }); | ||
35 | 32 | ||
36 | if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) | 33 | long long os_persistent_clock_emulation (void) { |
37 | return -errno; | 34 | struct timespec realtime_tp; |
38 | 35 | ||
39 | return 0; | 36 | clock_gettime(CLOCK_REALTIME, &realtime_tp); |
37 | return timespec_to_ns(&realtime_tp); | ||
40 | } | 38 | } |
41 | 39 | ||
42 | /** | 40 | /** |
43 | * timeval_to_ns - Convert timeval to nanoseconds | 41 | * os_timer_create() - create an new posix (interval) timer |
44 | * @ts: pointer to the timeval variable to be converted | ||
45 | * | ||
46 | * Returns the scalar nanosecond representation of the timeval | ||
47 | * parameter. | ||
48 | * | ||
49 | * Ripped from linux/time.h because it's a kernel header, and thus | ||
50 | * unusable from here. | ||
51 | */ | 42 | */ |
52 | static inline long long timeval_to_ns(const struct timeval *tv) | 43 | int os_timer_create(void* timer) { |
53 | { | 44 | |
54 | return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + | 45 | timer_t* t = timer; |
55 | tv->tv_usec * UM_NSEC_PER_USEC; | 46 | |
47 | if(t == NULL) { | ||
48 | t = &event_high_res_timer; | ||
49 | } | ||
50 | |||
51 | if (timer_create( | ||
52 | CLOCK_MONOTONIC, | ||
53 | NULL, | ||
54 | t) == -1) { | ||
55 | return -1; | ||
56 | } | ||
57 | return 0; | ||
56 | } | 58 | } |
57 | 59 | ||
58 | long long disable_timer(void) | 60 | int os_timer_set_interval(void* timer, void* i) |
59 | { | 61 | { |
60 | struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); | 62 | struct itimerspec its; |
61 | long long remain, max = UM_NSEC_PER_SEC / UM_HZ; | 63 | unsigned long long nsec; |
64 | timer_t* t = timer; | ||
65 | struct itimerspec* its_in = i; | ||
62 | 66 | ||
63 | if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) | 67 | if(t == NULL) { |
64 | printk(UM_KERN_ERR "disable_timer - setitimer failed, " | 68 | t = &event_high_res_timer; |
65 | "errno = %d\n", errno); | 69 | } |
66 | 70 | ||
67 | remain = timeval_to_ns(&time.it_value); | 71 | nsec = UM_NSEC_PER_SEC / UM_HZ; |
68 | if (remain > max) | ||
69 | remain = max; | ||
70 | 72 | ||
71 | return remain; | 73 | if(its_in != NULL) { |
72 | } | 74 | its.it_value.tv_sec = its_in->it_value.tv_sec; |
75 | its.it_value.tv_nsec = its_in->it_value.tv_nsec; | ||
76 | } else { | ||
77 | its.it_value.tv_sec = 0; | ||
78 | its.it_value.tv_nsec = nsec; | ||
79 | } | ||
73 | 80 | ||
74 | long long os_nsecs(void) | 81 | its.it_interval.tv_sec = 0; |
75 | { | 82 | its.it_interval.tv_nsec = nsec; |
76 | struct timeval tv; | ||
77 | 83 | ||
78 | gettimeofday(&tv, NULL); | 84 | if(timer_settime(*t, 0, &its, NULL) == -1) { |
79 | return timeval_to_ns(&tv); | 85 | return -errno; |
80 | } | 86 | } |
81 | 87 | ||
82 | #ifdef UML_CONFIG_NO_HZ_COMMON | ||
83 | static int after_sleep_interval(struct timespec *ts) | ||
84 | { | ||
85 | return 0; | 88 | return 0; |
86 | } | 89 | } |
87 | 90 | ||
88 | static void deliver_alarm(void) | 91 | /** |
92 | * os_timer_remain() - returns the remaining nano seconds of the given interval | ||
93 | * timer | ||
94 | * Because this is the remaining time of an interval timer, which correspondends | ||
95 | * to HZ, this value can never be bigger than one second. Just | ||
96 | * the nanosecond part of the timer is returned. | ||
97 | * The returned time is relative to the start time of the interval timer. | ||
98 | * Return an negative value in an error case. | ||
99 | */ | ||
100 | long os_timer_remain(void* timer) | ||
89 | { | 101 | { |
90 | alarm_handler(SIGVTALRM, NULL, NULL); | 102 | struct itimerspec its; |
91 | } | 103 | timer_t* t = timer; |
92 | 104 | ||
93 | static unsigned long long sleep_time(unsigned long long nsecs) | 105 | if(t == NULL) { |
94 | { | 106 | t = &event_high_res_timer; |
95 | return nsecs; | 107 | } |
96 | } | ||
97 | 108 | ||
98 | #else | 109 | if(timer_gettime(t, &its) == -1) { |
99 | unsigned long long last_tick; | 110 | return -errno; |
100 | unsigned long long skew; | 111 | } |
101 | 112 | ||
102 | static void deliver_alarm(void) | 113 | return its.it_value.tv_nsec; |
103 | { | 114 | } |
104 | unsigned long long this_tick = os_nsecs(); | ||
105 | int one_tick = UM_NSEC_PER_SEC / UM_HZ; | ||
106 | 115 | ||
107 | /* Protection against the host's time going backwards */ | 116 | int os_timer_one_shot(int ticks) |
108 | if ((last_tick != 0) && (this_tick < last_tick)) | 117 | { |
109 | this_tick = last_tick; | 118 | struct itimerspec its; |
119 | unsigned long long nsec; | ||
120 | unsigned long sec; | ||
110 | 121 | ||
111 | if (last_tick == 0) | 122 | nsec = (ticks + 1); |
112 | last_tick = this_tick - one_tick; | 123 | sec = nsec / UM_NSEC_PER_SEC; |
124 | nsec = nsec % UM_NSEC_PER_SEC; | ||
113 | 125 | ||
114 | skew += this_tick - last_tick; | 126 | its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC; |
127 | its.it_value.tv_nsec = nsec; | ||
115 | 128 | ||
116 | while (skew >= one_tick) { | 129 | its.it_interval.tv_sec = 0; |
117 | alarm_handler(SIGVTALRM, NULL, NULL); | 130 | its.it_interval.tv_nsec = 0; // we cheat here |
118 | skew -= one_tick; | ||
119 | } | ||
120 | 131 | ||
121 | last_tick = this_tick; | 132 | timer_settime(event_high_res_timer, 0, &its, NULL); |
133 | return 0; | ||
122 | } | 134 | } |
123 | 135 | ||
124 | static unsigned long long sleep_time(unsigned long long nsecs) | 136 | /** |
137 | * os_timer_disable() - disable the posix (interval) timer | ||
138 | * Returns the remaining interval timer time in nanoseconds | ||
139 | */ | ||
140 | long long os_timer_disable(void) | ||
125 | { | 141 | { |
126 | return nsecs > skew ? nsecs - skew : 0; | 142 | struct itimerspec its; |
127 | } | ||
128 | 143 | ||
129 | static inline long long timespec_to_us(const struct timespec *ts) | 144 | memset(&its, 0, sizeof(struct itimerspec)); |
130 | { | 145 | timer_settime(event_high_res_timer, 0, &its, &its); |
131 | return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + | 146 | |
132 | ts->tv_nsec / UM_NSEC_PER_USEC; | 147 | return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec; |
133 | } | 148 | } |
134 | 149 | ||
135 | static int after_sleep_interval(struct timespec *ts) | 150 | long long os_vnsecs(void) |
136 | { | 151 | { |
137 | int usec = UM_USEC_PER_SEC / UM_HZ; | 152 | struct timespec ts; |
138 | long long start_usecs = timespec_to_us(ts); | ||
139 | struct timeval tv; | ||
140 | struct itimerval interval; | ||
141 | |||
142 | /* | ||
143 | * It seems that rounding can increase the value returned from | ||
144 | * setitimer to larger than the one passed in. Over time, | ||
145 | * this will cause the remaining time to be greater than the | ||
146 | * tick interval. If this happens, then just reduce the first | ||
147 | * tick to the interval value. | ||
148 | */ | ||
149 | if (start_usecs > usec) | ||
150 | start_usecs = usec; | ||
151 | |||
152 | start_usecs -= skew / UM_NSEC_PER_USEC; | ||
153 | if (start_usecs < 0) | ||
154 | start_usecs = 0; | ||
155 | 153 | ||
156 | tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, | 154 | clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts); |
157 | .tv_usec = start_usecs % UM_USEC_PER_SEC }); | 155 | return timespec_to_ns(&ts); |
158 | interval = ((struct itimerval) { { 0, usec }, tv }); | 156 | } |
159 | 157 | ||
160 | if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) | 158 | long long os_nsecs(void) |
161 | return -errno; | 159 | { |
160 | struct timespec ts; | ||
162 | 161 | ||
163 | return 0; | 162 | clock_gettime(CLOCK_MONOTONIC,&ts); |
163 | return timespec_to_ns(&ts); | ||
164 | } | 164 | } |
165 | #endif | ||
166 | 165 | ||
167 | void idle_sleep(unsigned long long nsecs) | 166 | /** |
167 | * os_idle_sleep() - sleep for a given time of nsecs | ||
168 | * @nsecs: nanoseconds to sleep | ||
169 | */ | ||
170 | void os_idle_sleep(unsigned long long nsecs) | ||
168 | { | 171 | { |
169 | struct timespec ts; | 172 | struct timespec ts; |
170 | 173 | ||
171 | /* | 174 | if (nsecs <= 0) { |
172 | * nsecs can come in as zero, in which case, this starts a | 175 | return; |
173 | * busy loop. To prevent this, reset nsecs to the tick | 176 | } |
174 | * interval if it is zero. | ||
175 | */ | ||
176 | if (nsecs == 0) | ||
177 | nsecs = UM_NSEC_PER_SEC / UM_HZ; | ||
178 | 177 | ||
179 | nsecs = sleep_time(nsecs); | 178 | ts = ((struct timespec) { |
180 | ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, | 179 | .tv_sec = nsecs / UM_NSEC_PER_SEC, |
181 | .tv_nsec = nsecs % UM_NSEC_PER_SEC }); | 180 | .tv_nsec = nsecs % UM_NSEC_PER_SEC |
181 | }); | ||
182 | 182 | ||
183 | if (nanosleep(&ts, &ts) == 0) | 183 | /* |
184 | * Relay the signal if clock_nanosleep is interrupted. | ||
185 | */ | ||
186 | if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) { | ||
184 | deliver_alarm(); | 187 | deliver_alarm(); |
185 | after_sleep_interval(&ts); | 188 | } |
186 | } | 189 | } |