On 10/05/15 15:34, Thomas Meyer wrote: >> Am 10.05.2015 um 14:35 schrieb Richard Weinberger >> <richard.weinber...@gmail.com>: >> >>> On Sun, May 10, 2015 at 1:14 AM, Thomas Meyer <tho...@m3y3r.de> wrote: >>> Hi, >>> >>> Changes: >>> - also create posix timer in stub_clone_handler() >>> - incorporated antons remarks >> Hm, this patch does a *lot* more than the changelog says. > Hi, yes PATCH was probably the wrong keyword in the subject line. It should > have been RFC. > I just wanted to have feedback of the current state of this patch/work.
Looks good, does it test out good - I will tell you during the week. I already have most of the testcases set up from the period when I did only the kernel part. The best test is running any of the kernel queueing disciplines. Stock UML is completely unable to do any of them correctly. I can probably concoct something related to timers and timeouts in protocols too to demo the breakage with the current timer state in these. > > I'm currently working on cleaning up the patch and switch from SIGUSR2 to > SIGNALRM, If you mean SIGALRM that had some issues. I tried that originally and gave up - that is why the patch uses SIGUSR2 - it is something nobody uses and it did not interfere with the existing use of ALRM and VTALRM. A. > which seems to be the natural thing for posix timers. > I will send this next patch as something that should be includable into the > kernel, i.e. With correct description and signed off line and so on. > > But feel free to have a look at v6 and give feedback. > > With kind regards > Thomas > >>> diff --git a/arch/um/Makefile b/arch/um/Makefile >>> index 17d4460..a4a434f 100644 >>> --- a/arch/um/Makefile >>> +++ b/arch/um/Makefile >>> @@ -130,7 +130,7 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT) >>> # The wrappers will select whether using "malloc" or the kernel allocator. >>> LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc >>> >>> -LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) >>> +LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -lrt >>> >>> # Used by link-vmlinux.sh which has special support for um link >>> export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) >>> diff --git a/arch/um/include/asm/irq.h b/arch/um/include/asm/irq.h >>> index 4a2037f..0f2a5b1 100644 >>> --- a/arch/um/include/asm/irq.h >>> +++ b/arch/um/include/asm/irq.h >>> @@ -16,8 +16,9 @@ >>> #define TELNETD_IRQ 12 >>> #define XTERM_IRQ 13 >>> #define RANDOM_IRQ 14 >>> +#define HRTIMER_IRQ 15 >>> >>> -#define LAST_IRQ RANDOM_IRQ >>> +#define LAST_IRQ HRTIMER_IRQ >>> #define NR_IRQS (LAST_IRQ + 1) >>> >>> #endif >>> diff --git a/arch/um/include/shared/as-layout.h >>> b/arch/um/include/shared/as-layout.h >>> index ca1843e..798aa6e 100644 >>> --- a/arch/um/include/shared/as-layout.h >>> +++ b/arch/um/include/shared/as-layout.h >>> @@ -17,7 +17,7 @@ >>> >>> /* Some constant macros are used in both assembler and >>> * C code. Therefore we cannot annotate them always with >>> - * 'UL' and other type specifiers unilaterally. We >>> + * 'UL' and other type specifiers unilaterally. We >>> * use the following macros to deal with this. >>> */ >>> >>> @@ -28,6 +28,13 @@ >>> #define _UML_AC(X, Y) __UML_AC(X, Y) >>> #endif >>> >>> +/** >>> + * userspace stub address space layout: >>> + * Below macros define the layout of the stub code and data >>> + * which are mapped in each userspace process: >>> + * - one page of code located at 0x100000 followed by >>> + * - one page of data >>> + */ >>> #define STUB_START _UML_AC(, 0x100000) >>> #define STUB_CODE _UML_AC((unsigned long), STUB_START) >>> #define STUB_DATA _UML_AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE) >>> diff --git a/arch/um/include/shared/kern_util.h >>> b/arch/um/include/shared/kern_util.h >>> index 83a91f9..0282b36 100644 >>> --- a/arch/um/include/shared/kern_util.h >>> +++ b/arch/um/include/shared/kern_util.h >>> @@ -37,6 +37,7 @@ extern void initial_thread_cb(void (*proc)(void *), void >>> *arg); >>> extern int is_syscall(unsigned long addr); >>> >>> extern void timer_handler(int sig, struct siginfo *unused_si, struct >>> uml_pt_regs *regs); >>> +extern void hrtimer_handler(int sig, struct siginfo *unused_si, struct >>> uml_pt_regs *regs); >>> >>> extern int start_uml(void); >>> extern void paging_init(void); >>> diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h >>> index d824528..7f7368b 100644 >>> --- a/arch/um/include/shared/os.h >>> +++ b/arch/um/include/shared/os.h >>> @@ -217,7 +217,8 @@ extern int set_umid(char *name); >>> extern char *get_umid(void); >>> >>> /* signal.c */ >>> -extern void timer_init(void); >>> +extern void uml_timer_set_signal_handler(void); >>> +extern void uml_hrtimer_set_signal_handler(void); >>> extern void set_sigstack(void *sig_stack, int size); >>> extern void remove_sigstack(void); >>> extern void set_handler(int sig); >>> @@ -238,12 +239,16 @@ extern void um_early_printk(const char *s, unsigned >>> int n); >>> extern void os_fix_helper_signals(void); >>> >>> /* time.c */ >>> -extern void idle_sleep(unsigned long long nsecs); >>> -extern int set_interval(void); >>> -extern int timer_one_shot(int ticks); >>> -extern long long disable_timer(void); >>> +extern void os_idle_sleep(unsigned long long nsecs); >>> +extern int os_timer_create(void* timer); >>> +extern int os_timer_set_interval(void* timer, void* its); >>> +extern int os_timer_one_shot(int ticks); >>> +extern long long os_timer_disable(void); >>> +extern long os_timer_remain(void* timer); >>> extern void uml_idle_timer(void); >>> +extern long long os_persistent_clock_emulation(void); >>> extern long long os_nsecs(void); >>> +extern long long os_vnsecs(void); >>> >>> /* skas/mem.c */ >>> 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 f6ed92c..f98b9e2 100644 >>> --- a/arch/um/include/shared/skas/stub-data.h >>> +++ b/arch/um/include/shared/skas/stub-data.h >>> @@ -6,12 +6,12 @@ >>> #ifndef __STUB_DATA_H >>> #define __STUB_DATA_H >>> >>> -#include <sys/time.h> >>> +#include <time.h> >>> >>> struct stub_data { >>> - long offset; >>> + unsigned long offset; >>> int fd; >>> - struct itimerval timer; >>> + struct itimerspec timer; >>> long err; >>> }; >>> >>> diff --git a/arch/um/include/shared/timer-internal.h >>> b/arch/um/include/shared/timer-internal.h >>> new file mode 100644 >>> index 0000000..afdc6dc >>> --- /dev/null >>> +++ b/arch/um/include/shared/timer-internal.h >>> @@ -0,0 +1,18 @@ >>> +/* >>> + * Copyright (C) 2012 - 2014 Cisco Systems >>> + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) >>> + * Licensed under the GPL >>> + */ >>> + >>> +#ifndef __TIMER_INTERNAL_H__ >>> +#define __TIMER_INTERNAL_H__ >>> + >>> +#define TIMER_MULTIPLIER 256 >>> +#define TIMER_MIN_DELTA 500 >>> + >>> +extern void timer_lock(void); >>> +extern void timer_unlock(void); >>> + >>> +extern long long hrtimer_disable(void); >>> + >>> +#endif >>> diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c >>> index 23cb935..4c1966a 100644 >>> --- a/arch/um/kernel/irq.c >>> +++ b/arch/um/kernel/irq.c >>> @@ -338,20 +338,20 @@ static struct irq_chip normal_irq_type = { >>> .irq_unmask = dummy, >>> }; >>> >>> -static struct irq_chip SIGVTALRM_irq_type = { >>> - .name = "SIGVTALRM", >>> - .irq_disable = dummy, >>> - .irq_enable = dummy, >>> - .irq_ack = dummy, >>> - .irq_mask = dummy, >>> - .irq_unmask = dummy, >>> +static struct irq_chip SIGUSR2_irq_type = { >>> + .name = "SIGUSR2", >>> + .irq_disable = dummy, >>> + .irq_enable = dummy, >>> + .irq_ack = dummy, >>> + .irq_mask = dummy, >>> + .irq_unmask = dummy, >>> }; >>> >>> void __init init_IRQ(void) >>> { >>> int i; >>> >>> - irq_set_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, >>> handle_edge_irq); >>> + irq_set_chip_and_handler(HRTIMER_IRQ, &SIGUSR2_irq_type, >>> handle_edge_irq); >>> >>> for (i = 1; i < NR_IRQS; i++) >>> irq_set_chip_and_handler(i, &normal_irq_type, >>> handle_edge_irq); >>> diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c >>> index 9034fc8..5f6642d 100644 >>> --- a/arch/um/kernel/physmem.c >>> +++ b/arch/um/kernel/physmem.c >>> @@ -119,14 +119,23 @@ void __init setup_physmem(unsigned long start, >>> unsigned long reserve_end, >>> len - bootmap_size - reserve); >>> } >>> >>> +/** >>> + * phys_mapping() - maps a physical address to an offset address >>> + * phys: the physical address >>> + * offset_out: the offset in the memory map area >>> + * >>> + * Returns an file descriptor, or -1 when unknown physical address >>> + */ >>> int phys_mapping(unsigned long phys, unsigned long long *offset_out) >>> { >>> int fd = -1; >>> >>> + /* first check normal memory */ >>> if (phys < physmem_size) { >>> fd = physmem_fd; >>> *offset_out = phys; >>> } >>> + /* than check io memory */ >>> else if (phys < __pa(end_iomem)) { >>> struct iomem_region *region = iomem_regions; >>> >>> @@ -140,6 +149,7 @@ int phys_mapping(unsigned long phys, unsigned long long >>> *offset_out) >>> region = region->next; >>> } >>> } >>> + /* last check highmem */ >>> else if (phys < __pa(end_iomem) + highmem) { >>> fd = physmem_fd; >>> *offset_out = phys - iomem_size; >>> diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c >>> index 68b9119..b8a8d10 100644 >>> --- a/arch/um/kernel/process.c >>> +++ b/arch/um/kernel/process.c >>> @@ -27,6 +27,7 @@ >>> #include <kern_util.h> >>> #include <os.h> >>> #include <skas.h> >>> +#include <timer-internal.h> >>> >>> /* >>> * This is a per-cpu array. A processor only modifies its entry and it >>> only >>> @@ -201,12 +202,8 @@ void initial_thread_cb(void (*proc)(void *), void *arg) >>> >>> void arch_cpu_idle(void) >>> { >>> - unsigned long long nsecs; >>> - >>> cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); >>> - nsecs = disable_timer(); >>> - idle_sleep(nsecs); >>> - local_irq_enable(); >>> + os_idle_sleep(UM_NSEC_PER_SEC / UM_HZ); >>> } >>> >>> int __cant_sleep(void) { >>> diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c >>> index 289771d..5f283b1 100644 >>> --- a/arch/um/kernel/skas/clone.c >>> +++ b/arch/um/kernel/skas/clone.c >>> @@ -20,37 +20,63 @@ >>> * on some systems. >>> */ >>> >>> +/** >>> + * stub_clone_handler() - userspace clone handler stub >>> + * >>> + * this stub clone hanlder is mmaped(?)/available in all userspace >>> + * processes. It's used to copy an mm context from an fork syscall in the >>> + * traced userspace process >>> + */ >>> void __attribute__ ((__section__ (".__syscall_stub"))) >>> stub_clone_handler(void) >>> { >>> struct stub_data *data = (struct stub_data *) STUB_DATA; >>> + struct sigevent sev; >>> + timer_t timerid; >>> long err; >>> >>> + /* clone "from" process */ >>> err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | >>> SIGCHLD, >>> STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void >>> *)); >>> - if (err != 0) >>> + /* Parent: exit here, child, continue */ >>> + if (err != 0) { >>> goto out; >>> + } >>> >>> + /* set child to ptrace */ >>> err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); >>> if (err) >>> goto out; >>> >>> - err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, >>> - (long) &data->timer, 0); >>> + /* create a new posix interval timer */ >>> + sev.sigev_notify = SIGEV_SIGNAL; >>> + sev.sigev_signo = SIGUSR2; >>> + sev.sigev_value.sival_ptr = NULL; >>> + >>> + err = stub_syscall3(__NR_timer_create, CLOCK_MONOTONIC, >>> + (long) &sev, (long) &timerid); >>> if (err) >>> goto out; >>> >>> + /* set interval to the given value from copy_context_skas0() */ >>> + err = stub_syscall4(__NR_timer_settime, (long) timerid, 0l, >>> + (long) &data->timer, 0l); >>> + if (err) >>> + goto out; >>> + >>> + /* switch to new stack */ >>> remap_stack(data->fd, data->offset); >>> goto done; >>> >>> out: >>> /* >>> - * save current result. >>> - * Parent: pid; >>> - * child: retcode of mmap already saved and it jumps around this >>> - * assignment >>> + * Save current result. >>> + * - Parent: pid from clone() call >>> + * - Child: "retcode of mmap already saved and it jumps around this >>> + * assignment"??? >>> */ >>> data->err = err; >>> + >>> done: >>> trap_myself(); >>> } >>> diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c >>> index 94abdcc..df9c9ab 100644 >>> --- a/arch/um/kernel/skas/mmu.c >>> +++ b/arch/um/kernel/skas/mmu.c >>> @@ -47,6 +47,13 @@ static int init_stub_pte(struct mm_struct *mm, unsigned >>> long proc, >>> return -ENOMEM; >>> } >>> >>> +/** >>> + * init_new_context() - creates or copies an mm context >>> + * @task: the belonging task >>> + * @mm: the mm struct to be setup/allocated >>> + * >>> + * called by mm_init() (kernel/fork.c) >>> + */ >>> int init_new_context(struct task_struct *task, struct mm_struct *mm) >>> { >>> struct mm_context *from_mm = NULL; >>> @@ -59,13 +66,15 @@ int init_new_context(struct task_struct *task, struct >>> mm_struct *mm) >>> goto out; >>> >>> to_mm->id.stack = stack; >>> - if (current->mm != NULL && current->mm != &init_mm) >>> + if (current->mm != NULL && current->mm != &init_mm) { >>> from_mm = ¤t->mm->context; >>> + } >>> >>> - if (from_mm) >>> - to_mm->id.u.pid = copy_context_skas0(stack, >>> - from_mm->id.u.pid); >>> - else to_mm->id.u.pid = start_userspace(stack); >>> + if (from_mm) { >>> + to_mm->id.u.pid = copy_context_skas0(stack, >>> from_mm->id.u.pid); >>> + } else { >>> + to_mm->id.u.pid = start_userspace(stack); >>> + } >>> >>> if (to_mm->id.u.pid < 0) { >>> ret = to_mm->id.u.pid; >>> diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c >>> index 527fa58..2b0c35a 100644 >>> --- a/arch/um/kernel/skas/process.c >>> +++ b/arch/um/kernel/skas/process.c >>> @@ -43,6 +43,9 @@ int __init start_uml(void) >>> &init_task.thread.switch_buf); >>> } >>> >>> +/** >>> + * current_stub_stack() - returns the address of the current mm stack >>> + */ >>> unsigned long current_stub_stack(void) >>> { >>> if (current->mm == NULL) >>> diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c >>> index 117568d..ed64037 100644 >>> --- a/arch/um/kernel/time.c >>> +++ b/arch/um/kernel/time.c >>> @@ -1,4 +1,5 @@ >>> /* >>> + * Copyright (C) 2012-2014 Cisco Systems >>> * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) >>> * Licensed under the GPL >>> */ >>> @@ -8,32 +9,36 @@ >>> #include <linux/interrupt.h> >>> #include <linux/jiffies.h> >>> #include <linux/threads.h> >>> +#include <linux/spinlock.h> >>> #include <asm/irq.h> >>> #include <asm/param.h> >>> #include <kern_util.h> >>> #include <os.h> >>> +#include <timer-internal.h> >>> >>> -void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs >>> *regs) >>> +void hrtimer_handler(int sig, struct siginfo *unused_si, struct >>> uml_pt_regs *regs) >>> { >>> unsigned long flags; >>> >>> local_irq_save(flags); >>> - do_IRQ(TIMER_IRQ, regs); >>> + do_IRQ(HRTIMER_IRQ, regs); >>> local_irq_restore(flags); >>> } >>> >>> -static void itimer_set_mode(enum clock_event_mode mode, >>> +static void timer_set_mode(enum clock_event_mode mode, >>> struct clock_event_device *evt) >>> { >>> switch (mode) { >>> case CLOCK_EVT_MODE_PERIODIC: >>> - set_interval(); >>> + os_timer_set_interval(NULL, NULL); >>> break; >>> >>> + case CLOCK_EVT_MODE_ONESHOT: >>> + os_timer_one_shot(1); >>> + >>> case CLOCK_EVT_MODE_SHUTDOWN: >>> case CLOCK_EVT_MODE_UNUSED: >>> - case CLOCK_EVT_MODE_ONESHOT: >>> - disable_timer(); >>> + os_timer_disable(); >>> break; >>> >>> case CLOCK_EVT_MODE_RESUME: >>> @@ -41,68 +46,74 @@ static void itimer_set_mode(enum clock_event_mode mode, >>> } >>> } >>> >>> -static int itimer_next_event(unsigned long delta, >>> +static int timer_next_event(unsigned long delta, >>> struct clock_event_device *evt) >>> { >>> - return timer_one_shot(delta + 1); >>> + return os_timer_one_shot(delta); >>> } >>> >>> -static struct clock_event_device itimer_clockevent = { >>> - .name = "itimer", >>> +static struct clock_event_device timer_clockevent = { >>> + .name = "timer", >>> .rating = 250, >>> .cpumask = cpu_all_mask, >>> .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, >>> - .set_mode = itimer_set_mode, >>> - .set_next_event = itimer_next_event, >>> - .shift = 32, >>> + .set_mode = timer_set_mode, >>> + .set_next_event = timer_next_event, >>> + .shift = 0, >>> + .max_delta_ns = 0xffffffff, >>> + .min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should >>> be enough for anyone, same as 640K RAM >>> .irq = 0, >>> + .mult = 1, >>> }; >>> >>> -static irqreturn_t um_timer(int irq, void *dev) >>> +static irqreturn_t um_timer_irq(int irq, void *dev) >>> { >>> - (*itimer_clockevent.event_handler)(&itimer_clockevent); >>> + (*timer_clockevent.event_handler)(&timer_clockevent); >>> >>> return IRQ_HANDLED; >>> } >>> >>> -static cycle_t itimer_read(struct clocksource *cs) >>> +static cycle_t timer_read(struct clocksource *cs) >>> { >>> - return os_nsecs() / 1000; >>> + return os_nsecs() / TIMER_MULTIPLIER; >>> } >>> >>> -static struct clocksource itimer_clocksource = { >>> - .name = "itimer", >>> +static struct clocksource timer_clocksource = { >>> + .name = "timer", >>> .rating = 300, >>> - .read = itimer_read, >>> + .read = timer_read, >>> .mask = CLOCKSOURCE_MASK(64), >>> .flags = CLOCK_SOURCE_IS_CONTINUOUS, >>> }; >>> >>> -static void __init setup_itimer(void) >>> +static void __init timer_setup(void) >>> { >>> int err; >>> >>> - err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); >>> - if (err != 0) >>> + err = request_irq(HRTIMER_IRQ, um_timer_irq, IRQF_TIMER, "hr >>> timer", NULL); >>> + if (err != 0) { >>> printk(KERN_ERR "register_timer : request_irq failed - " >>> "errno = %d\n", -err); >>> + return; >>> + } >>> + >>> + err = os_timer_create(NULL); >>> + if (err != 0) { >>> + printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); >>> + return; >>> + } >>> >>> - itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32); >>> - itimer_clockevent.max_delta_ns = >>> - clockevent_delta2ns(60 * HZ, &itimer_clockevent); >>> - itimer_clockevent.min_delta_ns = >>> - clockevent_delta2ns(1, &itimer_clockevent); >>> - err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); >>> + err = clocksource_register_hz(&timer_clocksource, >>> NSEC_PER_SEC/TIMER_MULTIPLIER); >>> if (err) { >>> printk(KERN_ERR "clocksource_register_hz returned %d\n", >>> err); >>> return; >>> } >>> - clockevents_register_device(&itimer_clockevent); >>> + clockevents_register_device(&timer_clockevent); >>> } >>> >>> void read_persistent_clock(struct timespec *ts) >>> { >>> - long long nsecs = os_nsecs(); >>> + long long nsecs = os_persistent_clock_emulation(); >>> >>> set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, >>> nsecs % NSEC_PER_SEC); >>> @@ -110,6 +121,6 @@ void read_persistent_clock(struct timespec *ts) >>> >>> void __init time_init(void) >>> { >>> - timer_init(); >>> - late_time_init = setup_itimer; >>> + uml_hrtimer_set_signal_handler(); >>> + late_time_init = timer_setup; >>> } >>> diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h >>> deleted file mode 100644 >>> index 0dc2c9f..0000000 >>> --- a/arch/um/os-Linux/internal.h >>> +++ /dev/null >>> @@ -1 +0,0 @@ >>> -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 df9191a..bd5907e 100644 >>> --- a/arch/um/os-Linux/main.c >>> +++ b/arch/um/os-Linux/main.c >>> @@ -168,8 +168,8 @@ int __init main(int argc, char **argv, char **envp) >>> * some time) and cause a segfault. >>> */ >>> >>> - /* stop timers and set SIGVTALRM to be ignored */ >>> - disable_timer(); >>> + /* stop timers and set timer signal to be ignored */ >>> + os_timer_disable(); >>> >>> /* disable SIGIO for the fds and set SIGIO to be ignored */ >>> err = deactivate_all_fds(); >>> diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c >>> index 7b605e4..ee6db2e 100644 >>> --- a/arch/um/os-Linux/signal.c >>> +++ b/arch/um/os-Linux/signal.c >>> @@ -13,7 +13,6 @@ >>> #include <kern_util.h> >>> #include <os.h> >>> #include <sysdep/mcontext.h> >>> -#include "internal.h" >>> >>> void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { >>> [SIGTRAP] = relay_signal, >>> @@ -23,7 +22,8 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct >>> uml_pt_regs *) = { >>> [SIGBUS] = bus_handler, >>> [SIGSEGV] = segv_handler, >>> [SIGIO] = sigio_handler, >>> - [SIGVTALRM] = timer_handler }; >>> + [SIGUSR2] = hrtimer_handler >>> +}; >>> >>> static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) >>> { >>> @@ -38,7 +38,7 @@ static void sig_handler_common(int sig, struct siginfo >>> *si, mcontext_t *mc) >>> } >>> >>> /* enable signals if sig isn't IRQ signal */ >>> - if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) >>> + if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM) && >>> (sig != SIGUSR2)) >>> unblock_signals(); >>> >>> (*sig_info[sig])(sig, si, &r); >>> @@ -55,8 +55,8 @@ static void sig_handler_common(int sig, struct siginfo >>> *si, mcontext_t *mc) >>> #define SIGIO_BIT 0 >>> #define SIGIO_MASK (1 << SIGIO_BIT) >>> >>> -#define SIGVTALRM_BIT 1 >>> -#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) >>> +#define SIGUSR2_BIT 2 >>> +#define SIGUSR2_MASK (1 << SIGUSR2_BIT) >>> >>> static int signals_enabled; >>> static unsigned int signals_pending; >>> @@ -78,46 +78,47 @@ void sig_handler(int sig, struct siginfo *si, >>> mcontext_t *mc) >>> set_signals(enabled); >>> } >>> >>> -static void real_alarm_handler(mcontext_t *mc) >>> +static void real_hralarm_handler(mcontext_t *mc) >>> { >>> struct uml_pt_regs regs; >>> >>> if (mc != NULL) >>> get_regs_from_mc(®s, mc); >>> regs.is_user = 0; >>> - unblock_signals(); >>> - timer_handler(SIGVTALRM, NULL, ®s); >>> + hrtimer_handler(SIGUSR2, NULL, ®s); >>> } >>> >>> -void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) >>> +void hralarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) >>> { >>> int enabled; >>> >>> enabled = signals_enabled; >>> if (!signals_enabled) { >>> - signals_pending |= SIGVTALRM_MASK; >>> + signals_pending |= SIGUSR2_MASK; >>> return; >>> } >>> >>> block_signals(); >>> - >>> - real_alarm_handler(mc); >>> + real_hralarm_handler(mc); >>> set_signals(enabled); >>> } >>> >>> -void timer_init(void) >>> +void uml_hrtimer_set_signal_handler(void) >>> { >>> - set_handler(SIGVTALRM); >>> + set_handler(SIGUSR2); >>> } >>> >>> void set_sigstack(void *sig_stack, int size) >>> { >>> - stack_t stack = ((stack_t) { .ss_flags = 0, >>> - .ss_sp = (__ptr_t) sig_stack, >>> - .ss_size = size - sizeof(void *) }); >>> + stack_t stack = ((stack_t) { >>> + .ss_flags = 0, >>> + .ss_sp = (__ptr_t) sig_stack, >>> + .ss_size = size - sizeof(void *) >>> + }); >>> >>> - if (sigaltstack(&stack, NULL) != 0) >>> + if (sigaltstack(&stack, NULL) != 0) { >>> panic("enabling signal stack failed, errno = %d\n", errno); >>> + } >>> } >>> >>> static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) >>> = { >>> @@ -129,10 +130,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo >>> *si, mcontext_t *mc) = { >>> >>> [SIGIO] = sig_handler, >>> [SIGWINCH] = sig_handler, >>> - [SIGVTALRM] = alarm_handler >>> + [SIGUSR2] = hralarm_handler >>> }; >>> >>> - >>> static void hard_handler(int sig, siginfo_t *si, void *p) >>> { >>> struct ucontext *uc = p; >>> @@ -176,6 +176,13 @@ static void hard_handler(int sig, siginfo_t *si, void >>> *p) >>> } while (pending); >>> } >>> >>> +/** >>> + * set_handler() - enable signal in process' signal mask >>> + * @sig: The signal to enable >>> + * >>> + * Enable the given signal in the process' signal mask and >>> + * attach hard_handler() as handler routine >>> + */ >>> void set_handler(int sig) >>> { >>> struct sigaction action; >>> @@ -186,9 +193,9 @@ void set_handler(int sig) >>> >>> /* block irq ones */ >>> sigemptyset(&action.sa_mask); >>> - sigaddset(&action.sa_mask, SIGVTALRM); >>> sigaddset(&action.sa_mask, SIGIO); >>> sigaddset(&action.sa_mask, SIGWINCH); >>> + sigaddset(&action.sa_mask, SIGUSR2); >>> >>> if (sig == SIGSEGV) >>> flags |= SA_NODEFER; >>> @@ -281,8 +288,8 @@ void unblock_signals(void) >>> if (save_pending & SIGIO_MASK) >>> sig_handler_common(SIGIO, NULL, NULL); >>> >>> - if (save_pending & SIGVTALRM_MASK) >>> - real_alarm_handler(NULL); >>> + if (save_pending & SIGUSR2_MASK) >>> + real_hralarm_handler(NULL); >>> } >>> } >>> >>> @@ -298,9 +305,11 @@ int set_signals(int enable) >>> return enable; >>> >>> ret = signals_enabled; >>> - if (enable) >>> + if (enable) { >>> unblock_signals(); >>> - else block_signals(); >>> + } else { >>> + block_signals(); >>> + } >>> >>> return ret; >>> } >>> diff --git a/arch/um/os-Linux/skas/process.c >>> b/arch/um/os-Linux/skas/process.c >>> index 7a97775..30065e1 100644 >>> --- a/arch/um/os-Linux/skas/process.c >>> +++ b/arch/um/os-Linux/skas/process.c >>> @@ -45,7 +45,7 @@ static int ptrace_dump_regs(int pid) >>> * Signals that are OK to receive in the stub - we'll just continue it. >>> * SIGWINCH will happen when UML is inside a detached screen. >>> */ >>> -#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) >>> +#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH) | (1 << SIGUSR2)) >>> >>> /* Signals that the stub will finish with - anything else is an error */ >>> #define STUB_DONE_MASK (1 << SIGTRAP) >>> @@ -176,17 +176,59 @@ static void handle_trap(int pid, struct uml_pt_regs >>> *regs, >>> >>> extern int __syscall_stub_start; >>> >>> +/** >>> + * userspace_tramp() - userspace trampoline >>> + * @stack: The address of the stub stack used for the new process >>> + * (used for SIGSEGV handling). >>> + * >>> + * The trampoline does execute as a new process after clone() >>> + * For each new userspace process the below code sets up >>> + * all necessary data: >>> + * 1.) enable ptrace from parent (the uml kernel) >>> + * 2.) Setup signal handling. Signals are inherited by the parent, i.e >>> + * the uml kernel >>> + * 3.) Create and start an posix (interval) timer for this process. >>> + * This timer will emulate the kernel timer ticks. >>> + * The timer signal will be processed by the kernel process in >>> userspace() >>> + * 4.) Map stub code page in the new process, i.e. the >>> + * userspace process: >>> + * The stub codes is used to catch syscalls from the userspace to >>> + * the kernel. >>> + * See linker scripts arch/um/kernel/dyn.lds.S (dynamic) resp. >>> + * arch/um/kernel/uml.lds.S (static) >>> + * for __syscall_stub_start defintion and >>> + * arch/um/kernel/skas/clone.c for the stub_handler itself. >>> + * 5.) Map stub data page in the new process, i.e. the >>> + * userspace process: >>> + * Setup an SIGSEGV handler into the new process. >>> + * Page faults will be catched and signaled to the kernel via this >>> + * mechanism. >>> + * See arch/x86/um/stub_segv.c for the handler itself. >>> + * 6.) Stop the new process and wait for the kernel to SIGCONT it agian >>> + * when it will get scheduled() >>> + */ >>> static int userspace_tramp(void *stack) >>> { >>> void *addr; >>> int err, fd; >>> unsigned long long offset; >>> + timer_t timer; >>> + >>> + struct stub_data *data = (struct stub_data *) stack; >>> >>> ptrace(PTRACE_TRACEME, 0, 0, 0); >>> >>> signal(SIGTERM, SIG_DFL); >>> signal(SIGWINCH, SIG_IGN); >>> - err = set_interval(); >>> + >>> + err = os_timer_create(&timer); >>> + if (err) { >>> + printk(UM_KERN_ERR "userspace_tramp - creation of timer >>> failed, " >>> + "errno = %d\n", err); >>> + exit(1); >>> + } >>> + >>> + err = os_timer_set_interval(&timer, &data->timer); >>> if (err) { >>> printk(UM_KERN_ERR "userspace_tramp - setting timer failed, >>> " >>> "errno = %d\n", err); >>> @@ -246,11 +288,18 @@ static int userspace_tramp(void *stack) >>> #define NR_CPUS 1 >>> int userspace_pid[NR_CPUS]; >>> >>> +/** >>> + * start_userspace() - start a new userspace process with a new mm context >>> + * @stub_stack: Address of the new process' stack >>> + * >>> + * called by init_new_context() >>> + */ >>> int start_userspace(unsigned long stub_stack) >>> { >>> void *stack; >>> unsigned long sp; >>> int pid, status, n, flags, err; >>> + struct stub_data *data = (struct stub_data *) stub_stack; >>> >>> stack = mmap(NULL, UM_KERN_PAGE_SIZE, >>> PROT_READ | PROT_WRITE | PROT_EXEC, >>> @@ -266,6 +315,14 @@ int start_userspace(unsigned long stub_stack) >>> >>> flags = CLONE_FILES | SIGCHLD; >>> >>> + *data = ((struct stub_data) { >>> + .timer = ((struct itimerspec) >>> + { .it_value.tv_sec = 0, >>> + .it_value.tv_nsec = os_timer_remain(NULL), >>> + .it_interval.tv_sec = 0, >>> + .it_interval.tv_nsec = UM_NSEC_PER_SEC / >>> UM_HZ }) >>> + }); >>> + >>> pid = clone(userspace_tramp, (void *) sp, flags, (void *) >>> stub_stack); >>> if (pid < 0) { >>> err = -errno; >>> @@ -313,10 +370,15 @@ int start_userspace(unsigned long stub_stack) >>> return err; >>> } >>> >>> +/** >>> + * userspace() - user space control loop >>> + * @regs: the register's save memory >>> + * >>> + * The main loop that traces and controls each spwaned userspace >>> + * process >>> + */ >>> void userspace(struct uml_pt_regs *regs) >>> { >>> - struct itimerval timer; >>> - unsigned long long nsecs, now; >>> int err, status, op, pid = userspace_pid[0]; >>> /* To prevent races if using_sysemu changes under us.*/ >>> int local_using_sysemu; >>> @@ -325,13 +387,8 @@ void userspace(struct uml_pt_regs *regs) >>> /* Handle any immediate reschedules or signals */ >>> interrupt_end(); >>> >>> - if (getitimer(ITIMER_VIRTUAL, &timer)) >>> - printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", >>> errno); >>> - nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC + >>> - timer.it_value.tv_usec * UM_NSEC_PER_USEC; >>> - nsecs += os_nsecs(); >>> - >>> while (1) { >>> + >>> /* >>> * This can legitimately fail if the process loads a >>> * bogus value into a segment register. It will >>> @@ -388,32 +445,19 @@ void userspace(struct uml_pt_regs *regs) >>> switch (sig) { >>> case SIGSEGV: >>> if (PTRACE_FULL_FAULTINFO) { >>> - get_skas_faultinfo(pid, >>> - >>> ®s->faultinfo); >>> - (*sig_info[SIGSEGV])(SIGSEGV, >>> (struct siginfo *)&si, >>> - regs); >>> + >>> get_skas_faultinfo(pid,®s->faultinfo); >>> + (*sig_info[SIGSEGV])(SIGSEGV, >>> (struct siginfo *)&si, regs); >>> + } else { >>> + handle_segv(pid, regs); >>> } >>> - else handle_segv(pid, regs); >>> break; >>> case SIGTRAP + 0x80: >>> - handle_trap(pid, regs, local_using_sysemu); >>> + handle_trap(pid, regs, local_using_sysemu); >>> break; >>> case SIGTRAP: >>> relay_signal(SIGTRAP, (struct siginfo >>> *)&si, regs); >>> break; >>> - case SIGVTALRM: >>> - now = os_nsecs(); >>> - if (now < nsecs) >>> - break; >>> - block_signals(); >>> - (*sig_info[sig])(sig, (struct siginfo >>> *)&si, regs); >>> - unblock_signals(); >>> - nsecs = timer.it_value.tv_sec * >>> - UM_NSEC_PER_SEC + >>> - timer.it_value.tv_usec * >>> - UM_NSEC_PER_USEC; >>> - nsecs += os_nsecs(); >>> - break; >>> + case SIGUSR2: >>> case SIGIO: >>> case SIGILL: >>> case SIGBUS: >>> @@ -448,8 +492,7 @@ static int __init init_thread_regs(void) >>> thread_regs[REGS_IP_INDEX] = STUB_CODE + >>> (unsigned long) stub_clone_handler - >>> (unsigned long) &__syscall_stub_start; >>> - thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - >>> - sizeof(void *); >>> + thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - >>> sizeof(void *); >>> #ifdef __SIGNAL_FRAMESIZE >>> thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; >>> #endif >>> @@ -458,26 +501,51 @@ static int __init init_thread_regs(void) >>> >>> __initcall(init_thread_regs); >>> >>> +/** >>> + * copy_context_skas0() - copy an mm context >>> + * new_stack: void pointer of new stack, a zeroed page >>> + * pid: the pid of the mm parent, this proces is >>> cloned >>> + * into a new one >>> + * >>> + * Copy an mm context from an existing task >>> + * 1.) get file descriptor and offset of the mmaped new_stack >>> + * 2.) set current stub stack's data: file descriptor, offset and timer >>> data >>> + * 3.) Restore parents registers to init_thread_regs() >>> + * 4.) Continue parent (==from_mm) in stub_clone_handler(), see also >>> + * init_thread_regs(). This will clone a new process with same >>> + * mm. >>> + * 5.) >>> + * >>> + * Returns the PID of the new process >>> + */ >>> int copy_context_skas0(unsigned long new_stack, int pid) >>> { >>> - struct timeval tv = { .tv_sec = 0, .tv_usec = UM_USEC_PER_SEC / >>> UM_HZ }; >>> int err; >>> unsigned long current_stack = current_stub_stack(); >>> struct stub_data *data = (struct stub_data *) current_stack; >>> struct stub_data *child_data = (struct stub_data *) new_stack; >>> unsigned long long new_offset; >>> + >>> int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); >>> >>> /* >>> * prepare offset and fd of child's stack as argument for parent's >>> * and child's mmap2 calls >>> */ >>> - *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), >>> - .fd = new_fd, >>> - .timer = ((struct itimerval) >>> - { .it_value = tv, >>> - .it_interval = tv }) >>> }); >>> - >>> + *data = ((struct stub_data) { >>> + .offset = MMAP_OFFSET(new_offset), >>> + .fd = new_fd, >>> + .timer = ((struct itimerspec) >>> + { .it_value.tv_sec = 0, >>> + .it_value.tv_nsec = >>> os_timer_remain(NULL), >>> + .it_interval.tv_sec = 0, >>> + .it_interval.tv_nsec = >>> UM_NSEC_PER_SEC / UM_HZ }) >>> + }); >>> + >>> + /* set parents regs >>> + * this set the registers to the saved registers done in the >>> initcall >>> + * init_thread_regs() >>> + */ >>> err = ptrace_setregs(pid, thread_regs); >>> if (err < 0) { >>> err = -errno; >>> @@ -486,6 +554,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) >>> return err; >>> } >>> >>> + /* set parents fp registers */ >>> err = put_fp_registers(pid, thread_fp_regs); >>> if (err < 0) { >>> printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " >>> @@ -493,7 +562,9 @@ int copy_context_skas0(unsigned long new_stack, int pid) >>> return err; >>> } >>> >>> - /* set a well known return code for detection of child write >>> failure */ >>> + /* set a well known return code for detection of child write >>> failure, >>> + * i.e. on the new stack >>> + */ >>> child_data->err = 12345678; >>> >>> /* >>> @@ -508,8 +579,10 @@ int copy_context_skas0(unsigned long new_stack, int >>> pid) >>> return err; >>> } >>> >>> + /* wait for parents stub_clone_handler() to finish */ >>> wait_stub_done(pid); >>> >>> + /* get childs pid, the pid of the cloned parent process */ >>> pid = data->err; >>> if (pid < 0) { >>> printk(UM_KERN_ERR "copy_context_skas0 - stub-parent >>> reports " >>> diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c >>> index e9824d5..5a7f49c 100644 >>> --- a/arch/um/os-Linux/time.c >>> +++ b/arch/um/os-Linux/time.c >>> @@ -1,4 +1,5 @@ >>> /* >>> + * Copyright (C) 2012-2014 Cisco Systems >>> * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) >>> * Licensed under the GPL >>> */ >>> @@ -10,177 +11,177 @@ >>> #include <sys/time.h> >>> #include <kern_util.h> >>> #include <os.h> >>> -#include "internal.h" >>> +#include <string.h> >>> +#include <timer-internal.h> >>> >>> -int set_interval(void) >>> -{ >>> - int usec = UM_USEC_PER_SEC / UM_HZ; >>> - struct itimerval interval = ((struct itimerval) { { 0, usec }, >>> - { 0, usec } }); >>> - >>> - if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) >>> - return -errno; >>> +static timer_t event_high_res_timer = 0; >>> >>> - return 0; >>> +static inline long long timeval_to_ns(const struct timeval *tv) >>> +{ >>> + return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + >>> + tv->tv_usec * UM_NSEC_PER_USEC; >>> } >>> >>> -int timer_one_shot(int ticks) >>> +static inline long long timespec_to_ns(const struct timespec *ts) >>> { >>> - unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ; >>> - unsigned long sec = usec / UM_USEC_PER_SEC; >>> - struct itimerval interval; >>> - >>> - usec %= UM_USEC_PER_SEC; >>> - interval = ((struct itimerval) { { 0, 0 }, { sec, usec } }); >>> + return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) + >>> + ts->tv_nsec; >>> +} >>> >>> - if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) >>> - return -errno; >>> +long long os_persistent_clock_emulation (void) { >>> + struct timespec realtime_tp; >>> >>> - return 0; >>> + clock_gettime(CLOCK_REALTIME, &realtime_tp); >>> + return timespec_to_ns(&realtime_tp); >>> } >>> >>> /** >>> - * timeval_to_ns - Convert timeval to nanoseconds >>> - * @ts: pointer to the timeval variable to be converted >>> - * >>> - * Returns the scalar nanosecond representation of the timeval >>> - * parameter. >>> - * >>> - * Ripped from linux/time.h because it's a kernel header, and thus >>> - * unusable from here. >>> + * os_timer_create() - create an new posix (interval) timer >>> */ >>> -static inline long long timeval_to_ns(const struct timeval *tv) >>> -{ >>> - return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + >>> - tv->tv_usec * UM_NSEC_PER_USEC; >>> -} >>> +int os_timer_create(void* timer) { >>> >>> -long long disable_timer(void) >>> -{ >>> - struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); >>> - long long remain, max = UM_NSEC_PER_SEC / UM_HZ; >>> + struct sigevent sev; >>> + timer_t* t = timer; >>> >>> - if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) >>> - printk(UM_KERN_ERR "disable_timer - setitimer failed, " >>> - "errno = %d\n", errno); >>> + if(t == NULL) { >>> + t = &event_high_res_timer; >>> + } >>> >>> - remain = timeval_to_ns(&time.it_value); >>> - if (remain > max) >>> - remain = max; >>> + sev.sigev_notify = SIGEV_SIGNAL; >>> + sev.sigev_signo = SIGUSR2; /* note - hrtimer now has its own signal >>> */ >>> + sev.sigev_value.sival_ptr = &event_high_res_timer; >>> >>> - return remain; >>> + if (timer_create( >>> + CLOCK_MONOTONIC, >>> + &sev, >>> + t) == -1) { >>> + return -1; >>> + } >>> + return 0; >>> } >>> >>> -long long os_nsecs(void) >>> +int os_timer_set_interval(void* timer, void* i) >>> { >>> - struct timeval tv; >>> + struct itimerspec its; >>> + unsigned long long nsec; >>> + timer_t* t = timer; >>> + struct itimerspec* its_in = i; >>> >>> - gettimeofday(&tv, NULL); >>> - return timeval_to_ns(&tv); >>> -} >>> + if(t == NULL) { >>> + t = &event_high_res_timer; >>> + } >>> + >>> + nsec = UM_NSEC_PER_SEC / UM_HZ; >>> + >>> + if(its_in != NULL) { >>> + its.it_value.tv_sec = its_in->it_value.tv_sec; >>> + its.it_value.tv_nsec = its_in->it_value.tv_nsec; >>> + } else { >>> + its.it_value.tv_sec = 0; >>> + its.it_value.tv_nsec = nsec; >>> + } >>> + >>> + its.it_interval.tv_sec = 0; >>> + its.it_interval.tv_nsec = nsec; >>> + >>> + if(timer_settime(*t, 0, &its, NULL) == -1) { >>> + return -errno; >>> + } >>> >>> -#ifdef UML_CONFIG_NO_HZ_COMMON >>> -static int after_sleep_interval(struct timespec *ts) >>> -{ >>> return 0; >>> } >>> >>> -static void deliver_alarm(void) >>> +/** >>> + * os_timer_remain() - returns the remaining nano seconds of the given >>> interval >>> + * timer >>> + * Because this is the remaining time of an interval timer, which >>> correspondends >>> + * to HZ, this value can never be bigger than one second. Just >>> + * the nanosecond part of the timer is returned. >>> + * The returned time is relative to the start time of the interval timer. >>> + * Return an negative value in an error case. >>> + */ >>> +long os_timer_remain(void* timer) >>> { >>> - alarm_handler(SIGVTALRM, NULL, NULL); >>> -} >>> + struct itimerspec its; >>> + timer_t* t = timer; >>> >>> -static unsigned long long sleep_time(unsigned long long nsecs) >>> -{ >>> - return nsecs; >>> -} >>> + if(t == NULL) { >>> + t = &event_high_res_timer; >>> + } >>> >>> -#else >>> -unsigned long long last_tick; >>> -unsigned long long skew; >>> + if(timer_gettime(t, &its) == -1) { >>> + return -errno; >>> + } >>> >>> -static void deliver_alarm(void) >>> -{ >>> - unsigned long long this_tick = os_nsecs(); >>> - int one_tick = UM_NSEC_PER_SEC / UM_HZ; >>> + return its.it_value.tv_nsec; >>> +} >>> >>> - /* Protection against the host's time going backwards */ >>> - if ((last_tick != 0) && (this_tick < last_tick)) >>> - this_tick = last_tick; >>> +int os_timer_one_shot(int ticks) >>> +{ >>> + struct itimerspec its; >>> + unsigned long long nsec; >>> + unsigned long sec; >>> >>> - if (last_tick == 0) >>> - last_tick = this_tick - one_tick; >>> + nsec = (ticks + 1); >>> + sec = nsec / UM_NSEC_PER_SEC; >>> + nsec = nsec % UM_NSEC_PER_SEC; >>> >>> - skew += this_tick - last_tick; >>> + its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC; >>> + its.it_value.tv_nsec = nsec; >>> >>> - while (skew >= one_tick) { >>> - alarm_handler(SIGVTALRM, NULL, NULL); >>> - skew -= one_tick; >>> - } >>> + its.it_interval.tv_sec = 0; >>> + its.it_interval.tv_nsec = 0; // we cheat here >>> >>> - last_tick = this_tick; >>> + timer_settime(event_high_res_timer, 0, &its, NULL); >>> + return 0; >>> } >>> >>> -static unsigned long long sleep_time(unsigned long long nsecs) >>> +/** >>> + * os_timer_disable() - disable the posix (interval) timer >>> + * Returns the remaining interval timer time in nanoseconds >>> + */ >>> +long long os_timer_disable(void) >>> { >>> - return nsecs > skew ? nsecs - skew : 0; >>> + struct itimerspec its; >>> + >>> + memset(&its, 0, sizeof(struct itimerspec)); >>> + timer_settime(event_high_res_timer, 0, &its, &its); >>> + >>> + return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec; >>> } >>> >>> -static inline long long timespec_to_us(const struct timespec *ts) >>> +long long os_vnsecs(void) >>> { >>> - return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + >>> - ts->tv_nsec / UM_NSEC_PER_USEC; >>> + struct timespec ts; >>> + >>> + clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts); >>> + return timespec_to_ns(&ts); >>> } >>> >>> -static int after_sleep_interval(struct timespec *ts) >>> +long long os_nsecs(void) >>> { >>> - int usec = UM_USEC_PER_SEC / UM_HZ; >>> - long long start_usecs = timespec_to_us(ts); >>> - struct timeval tv; >>> - struct itimerval interval; >>> - >>> - /* >>> - * It seems that rounding can increase the value returned from >>> - * setitimer to larger than the one passed in. Over time, >>> - * this will cause the remaining time to be greater than the >>> - * tick interval. If this happens, then just reduce the first >>> - * tick to the interval value. >>> - */ >>> - if (start_usecs > usec) >>> - start_usecs = usec; >>> - >>> - start_usecs -= skew / UM_NSEC_PER_USEC; >>> - if (start_usecs < 0) >>> - start_usecs = 0; >>> - >>> - tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, >>> - .tv_usec = start_usecs % UM_USEC_PER_SEC >>> }); >>> - interval = ((struct itimerval) { { 0, usec }, tv }); >>> - >>> - if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) >>> - return -errno; >>> + struct timespec ts; >>> >>> - return 0; >>> + clock_gettime(CLOCK_MONOTONIC,&ts); >>> + return timespec_to_ns(&ts); >>> } >>> -#endif >>> >>> -void idle_sleep(unsigned long long nsecs) >>> +/** >>> + * os_idle_sleep() - sleep for a given time of nsecs >>> + * @nsecs: nanoseconds to sleep >>> + */ >>> +void os_idle_sleep(unsigned long long nsecs) >>> { >>> struct timespec ts; >>> >>> - /* >>> - * nsecs can come in as zero, in which case, this starts a >>> - * busy loop. To prevent this, reset nsecs to the tick >>> - * interval if it is zero. >>> - */ >>> - if (nsecs == 0) >>> - nsecs = UM_NSEC_PER_SEC / UM_HZ; >>> - >>> - nsecs = sleep_time(nsecs); >>> - ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, >>> - .tv_nsec = nsecs % UM_NSEC_PER_SEC >>> }); >>> - >>> - if (nanosleep(&ts, &ts) == 0) >>> - deliver_alarm(); >>> - after_sleep_interval(&ts); >>> + if (nsecs <= 0) { >>> + return; >>> + } >>> + >>> + ts = ((struct timespec) { >>> + .tv_sec = nsecs / UM_NSEC_PER_SEC, >>> + .tv_nsec = nsecs % UM_NSEC_PER_SEC >>> + }); >>> + >>> + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); >>> } >>> diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c >>> index faee55e..10ecc06 100644 >>> --- a/arch/um/os-Linux/util.c >>> +++ b/arch/um/os-Linux/util.c >>> @@ -102,6 +102,7 @@ void os_fix_helper_signals(void) >>> signal(SIGWINCH, SIG_IGN); >>> signal(SIGINT, SIG_DFL); >>> signal(SIGTERM, SIG_DFL); >>> + signal(SIGUSR2, SIG_IGN); >>> } >>> >>> void os_dump_core(void) >>> >>> >>> >>> ------------------------------------------------------------------------------ >>> One dashboard for servers and applications across Physical-Virtual-Cloud >>> Widest out-of-the-box monitoring support with 50+ applications >>> Performance metrics, stats and reports that give you Actionable Insights >>> Deep dive visibility with transaction tracing using APM Insight. >>> http://ad.doubleclick.net/ddm/clk/290420510;117567292;y >>> _______________________________________________ >>> User-mode-linux-devel mailing list >>> User-mode-linux-devel@lists.sourceforge.net >>> https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel >> >> >> -- >> Thanks, >> //richard > ------------------------------------------------------------------------------ > One dashboard for servers and applications across Physical-Virtual-Cloud > Widest out-of-the-box monitoring support with 50+ applications > Performance metrics, stats and reports that give you Actionable Insights > Deep dive visibility with transaction tracing using APM Insight. > http://ad.doubleclick.net/ddm/clk/290420510;117567292;y > _______________________________________________ > User-mode-linux-devel mailing list > User-mode-linux-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel > ------------------------------------------------------------------------------ One dashboard for servers and applications across Physical-Virtual-Cloud Widest out-of-the-box monitoring support with 50+ applications Performance metrics, stats and reports that give you Actionable Insights Deep dive visibility with transaction tracing using APM Insight. http://ad.doubleclick.net/ddm/clk/290420510;117567292;y _______________________________________________ User-mode-linux-devel mailing list User-mode-linux-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel