summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/include/shared/os.h18
-rw-r--r--arch/um/include/shared/skas/stub-data.h7
-rw-r--r--arch/um/include/shared/timer-internal.h13
-rw-r--r--arch/um/kernel/process.c8
-rw-r--r--arch/um/kernel/skas/clone.c6
-rw-r--r--arch/um/kernel/skas/mmu.c3
-rw-r--r--arch/um/kernel/time.c73
-rw-r--r--arch/um/os-Linux/internal.h1
-rw-r--r--arch/um/os-Linux/main.c7
-rw-r--r--arch/um/os-Linux/process.c6
-rw-r--r--arch/um/os-Linux/signal.c41
-rw-r--r--arch/um/os-Linux/skas/process.c45
-rw-r--r--arch/um/os-Linux/time.c249
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.
132LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc 132LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
133 133
134LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) 134LD_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
137export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) 137export 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 */
184extern unsigned long os_process_pc(int pid); 186extern unsigned long os_process_pc(int pid);
185extern int os_process_parent(int pid); 187extern int os_process_parent(int pid);
188extern void os_alarm_process(int pid);
186extern void os_stop_process(int pid); 189extern void os_stop_process(int pid);
187extern void os_kill_process(int pid, int reap_child); 190extern void os_kill_process(int pid, int reap_child);
188extern void os_kill_ptraced_process(int pid, int reap_child); 191extern void os_kill_ptraced_process(int pid, int reap_child);
@@ -217,7 +220,7 @@ extern int set_umid(char *name);
217extern char *get_umid(void); 220extern char *get_umid(void);
218 221
219/* signal.c */ 222/* signal.c */
220extern void timer_init(void); 223extern void timer_set_signal_handler(void);
221extern void set_sigstack(void *sig_stack, int size); 224extern void set_sigstack(void *sig_stack, int size);
222extern void remove_sigstack(void); 225extern void remove_sigstack(void);
223extern void set_handler(int sig); 226extern void set_handler(int sig);
@@ -227,6 +230,7 @@ extern void unblock_signals(void);
227extern int get_signals(void); 230extern int get_signals(void);
228extern int set_signals(int enable); 231extern int set_signals(int enable);
229extern int os_is_signal_stack(void); 232extern int os_is_signal_stack(void);
233extern void deliver_alarm(void);
230 234
231/* util.c */ 235/* util.c */
232extern void stack_protections(unsigned long address); 236extern void stack_protections(unsigned long address);
@@ -238,12 +242,16 @@ extern void um_early_printk(const char *s, unsigned int n);
238extern void os_fix_helper_signals(void); 242extern void os_fix_helper_signals(void);
239 243
240/* time.c */ 244/* time.c */
241extern void idle_sleep(unsigned long long nsecs); 245extern void os_idle_sleep(unsigned long long nsecs);
242extern int set_interval(void); 246extern int os_timer_create(void* timer);
243extern int timer_one_shot(int ticks); 247extern int os_timer_set_interval(void* timer, void* its);
244extern long long disable_timer(void); 248extern int os_timer_one_shot(int ticks);
249extern long long os_timer_disable(void);
250extern long os_timer_remain(void* timer);
245extern void uml_idle_timer(void); 251extern void uml_idle_timer(void);
252extern long long os_persistent_clock_emulation(void);
246extern long long os_nsecs(void); 253extern long long os_nsecs(void);
254extern long long os_vnsecs(void);
247 255
248/* skas/mem.c */ 256/* skas/mem.c */
249extern long run_syscall_stub(struct mm_id * mm_idp, 257extern 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
11struct stub_data { 13struct 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
204void arch_cpu_idle(void) 207void 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 = &current->mm->context; 63 from_mm = &current->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
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}
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 @@
1void 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
93void os_alarm_process(int pid)
94{
95 kill(pid, SIGALRM);
96}
97
92void os_stop_process(int pid) 98void 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
18void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { 19void (*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
28static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) 30static 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
61static int signals_enabled; 63static int signals_enabled;
62static unsigned int signals_pending; 64static 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
81static void real_alarm_handler(mcontext_t *mc) 83static 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(&regs, mc); 88 get_regs_from_mc(&regs, mc);
87 regs.is_user = 0; 89 timer_handler(SIGALRM, NULL, &regs);
88 unblock_signals();
89 timer_handler(SIGVTALRM, NULL, &regs);
90} 90}
91 91
92void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) 92void 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
108void timer_init(void) 108void deliver_alarm(void) {
109 timer_alarm_handler(SIGALRM, NULL, NULL);
110}
111
112void timer_set_signal_handler(void)
109{ 113{
110 set_handler(SIGVTALRM); 114 set_handler(SIGALRM);
111} 115}
112 116
113void set_sigstack(void *sig_stack, int size) 117void 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
138static void hard_handler(int sig, siginfo_t *si, void *p) 141static 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[];
183static int userspace_tramp(void *stack) 184static 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
320void userspace(struct uml_pt_regs *regs) 315void 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
465int copy_context_skas0(unsigned long new_stack, int pid) 442int 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
15int set_interval(void) 19static 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; 21static 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
27int timer_one_shot(int ticks) 27static 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) 33long 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 */
52static inline long long timeval_to_ns(const struct timeval *tv) 43int 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
58long long disable_timer(void) 60int 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
74long 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
83static int after_sleep_interval(struct timespec *ts)
84{
85 return 0; 88 return 0;
86} 89}
87 90
88static 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 */
100long 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
93static 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) {
99unsigned long long last_tick; 110 return -errno;
100unsigned long long skew; 111 }
101 112
102static 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 */ 116int 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
124static 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 */
140long long os_timer_disable(void)
125{ 141{
126 return nsecs > skew ? nsecs - skew : 0; 142 struct itimerspec its;
127}
128 143
129static 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
135static int after_sleep_interval(struct timespec *ts) 150long 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) 158long 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
167void idle_sleep(unsigned long long nsecs) 166/**
167 * os_idle_sleep() - sleep for a given time of nsecs
168 * @nsecs: nanoseconds to sleep
169 */
170void 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}