From e09b41010ba33a20a87472ee821fa407a5b8da36 Mon Sep 17 00:00:00 2001 From: José Pekkarinen Date: Mon, 11 Apr 2016 10:41:07 +0300 Subject: These changes are the raw update to linux-4.4.6-rt14. Kernel sources are taken from kernel.org, and rt patch from the rt wiki download page. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen --- kernel/arch/um/os-Linux/drivers/ethertap_user.c | 2 +- kernel/arch/um/os-Linux/drivers/tuntap_user.c | 6 +- kernel/arch/um/os-Linux/file.c | 1 + kernel/arch/um/os-Linux/helper.c | 6 +- kernel/arch/um/os-Linux/internal.h | 1 - kernel/arch/um/os-Linux/main.c | 7 +- kernel/arch/um/os-Linux/process.c | 6 + kernel/arch/um/os-Linux/signal.c | 49 ++--- kernel/arch/um/os-Linux/skas/mem.c | 6 +- kernel/arch/um/os-Linux/skas/process.c | 63 ++---- kernel/arch/um/os-Linux/start_up.c | 2 + kernel/arch/um/os-Linux/time.c | 249 ++++++++++++------------ 12 files changed, 197 insertions(+), 201 deletions(-) delete mode 100644 kernel/arch/um/os-Linux/internal.h (limited to 'kernel/arch/um/os-Linux') diff --git a/kernel/arch/um/os-Linux/drivers/ethertap_user.c b/kernel/arch/um/os-Linux/drivers/ethertap_user.c index b39b6696a..6d4918246 100644 --- a/kernel/arch/um/os-Linux/drivers/ethertap_user.c +++ b/kernel/arch/um/os-Linux/drivers/ethertap_user.c @@ -105,7 +105,7 @@ static int etap_tramp(char *dev, char *gate, int control_me, sprintf(data_fd_buf, "%d", data_remote); sprintf(version_buf, "%d", UML_NET_VERSION); if (gate != NULL) { - strcpy(gate_buf, gate); + strncpy(gate_buf, gate, 15); args = setup_args; } else args = nosetup_args; diff --git a/kernel/arch/um/os-Linux/drivers/tuntap_user.c b/kernel/arch/um/os-Linux/drivers/tuntap_user.c index 14126d917..c2e6e1dad 100644 --- a/kernel/arch/um/os-Linux/drivers/tuntap_user.c +++ b/kernel/arch/um/os-Linux/drivers/tuntap_user.c @@ -47,7 +47,7 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, } struct tuntap_pre_exec_data { - int stdout; + int stdout_fd; int close_me; }; @@ -55,7 +55,7 @@ static void tuntap_pre_exec(void *arg) { struct tuntap_pre_exec_data *data = arg; - dup2(data->stdout, 1); + dup2(data->stdout_fd, 1); close(data->close_me); } @@ -74,7 +74,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, sprintf(version_buf, "%d", UML_NET_VERSION); - data.stdout = remote; + data.stdout_fd = remote; data.close_me = me; pid = run_helper(tuntap_pre_exec, &data, argv); diff --git a/kernel/arch/um/os-Linux/file.c b/kernel/arch/um/os-Linux/file.c index 08d90fba9..26e016489 100644 --- a/kernel/arch/um/os-Linux/file.c +++ b/kernel/arch/um/os-Linux/file.c @@ -13,6 +13,7 @@ #include #include #include +#include #include static void copy_stat(struct uml_stat *dst, const struct stat64 *src) diff --git a/kernel/arch/um/os-Linux/helper.c b/kernel/arch/um/os-Linux/helper.c index e3ee4a51e..3f02d4232 100644 --- a/kernel/arch/um/os-Linux/helper.c +++ b/kernel/arch/um/os-Linux/helper.c @@ -96,7 +96,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) "ret = %d\n", -n); ret = n; } - CATCH_EINTR(waitpid(pid, NULL, __WCLONE)); + CATCH_EINTR(waitpid(pid, NULL, __WALL)); } out_free2: @@ -129,7 +129,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, return err; } if (stack_out == NULL) { - CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); + CATCH_EINTR(pid = waitpid(pid, &status, __WALL)); if (pid < 0) { err = -errno; printk(UM_KERN_ERR "run_helper_thread - wait failed, " @@ -148,7 +148,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, int helper_wait(int pid) { int ret, status; - int wflags = __WCLONE; + int wflags = __WALL; CATCH_EINTR(ret = waitpid(pid, &status, wflags)); if (ret < 0) { diff --git a/kernel/arch/um/os-Linux/internal.h b/kernel/arch/um/os-Linux/internal.h deleted file mode 100644 index 0dc2c9f13..000000000 --- a/kernel/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/kernel/arch/um/os-Linux/main.c b/kernel/arch/um/os-Linux/main.c index df9191acd..9d499de87 100644 --- a/kernel/arch/um/os-Linux/main.c +++ b/kernel/arch/um/os-Linux/main.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -163,13 +164,13 @@ int __init main(int argc, char **argv, char **envp) /* * This signal stuff used to be in the reboot case. However, - * sometimes a SIGVTALRM can come in when we're halting (reproducably + * sometimes a timer signal can come in when we're halting (reproducably * when writing out gcov information, presumably because that takes * 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/kernel/arch/um/os-Linux/process.c b/kernel/arch/um/os-Linux/process.c index 8408aba91..b3e0d4093 100644 --- a/kernel/arch/um/os-Linux/process.c +++ b/kernel/arch/um/os-Linux/process.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -89,6 +90,11 @@ int os_process_parent(int pid) return parent; } +void os_alarm_process(int pid) +{ + kill(pid, SIGALRM); +} + void os_stop_process(int pid) { kill(pid, SIGSTOP); diff --git a/kernel/arch/um/os-Linux/signal.c b/kernel/arch/um/os-Linux/signal.c index 7b605e4df..c211153ca 100644 --- a/kernel/arch/um/os-Linux/signal.c +++ b/kernel/arch/um/os-Linux/signal.c @@ -1,4 +1,6 @@ /* + * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) + * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) * Copyright (C) 2004 PathScale, Inc * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL @@ -13,7 +15,6 @@ #include #include #include -#include "internal.h" void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, @@ -23,7 +24,8 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGBUS] = bus_handler, [SIGSEGV] = segv_handler, [SIGIO] = sigio_handler, - [SIGVTALRM] = timer_handler }; + [SIGALRM] = timer_handler +}; static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { @@ -38,7 +40,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 != SIGALRM)) unblock_signals(); (*sig_info[sig])(sig, si, &r); @@ -55,8 +57,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 SIGALRM_BIT 1 +#define SIGALRM_MASK (1 << SIGALRM_BIT) static int signals_enabled; static unsigned int signals_pending; @@ -78,43 +80,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 timer_real_alarm_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); + timer_handler(SIGALRM, NULL, ®s); } -void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) +void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; enabled = signals_enabled; if (!signals_enabled) { - signals_pending |= SIGVTALRM_MASK; + signals_pending |= SIGALRM_MASK; return; } block_signals(); - real_alarm_handler(mc); + timer_real_alarm_handler(mc); set_signals(enabled); } -void timer_init(void) +void deliver_alarm(void) { + timer_alarm_handler(SIGALRM, NULL, NULL); +} + +void timer_set_signal_handler(void) { - set_handler(SIGVTALRM); + set_handler(SIGALRM); } 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 = { + .ss_flags = 0, + .ss_sp = sig_stack, + .ss_size = size - sizeof(void *) + }; if (sigaltstack(&stack, NULL) != 0) panic("enabling signal stack failed, errno = %d\n", errno); @@ -129,10 +135,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { [SIGIO] = sig_handler, [SIGWINCH] = sig_handler, - [SIGVTALRM] = alarm_handler + [SIGALRM] = timer_alarm_handler }; - static void hard_handler(int sig, siginfo_t *si, void *p) { struct ucontext *uc = p; @@ -186,9 +191,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, SIGALRM); if (sig == SIGSEGV) flags |= SA_NODEFER; @@ -281,8 +286,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 & SIGALRM_MASK) + timer_real_alarm_handler(NULL); } } diff --git a/kernel/arch/um/os-Linux/skas/mem.c b/kernel/arch/um/os-Linux/skas/mem.c index e7f8c945a..35015e3e1 100644 --- a/kernel/arch/um/os-Linux/skas/mem.c +++ b/kernel/arch/um/os-Linux/skas/mem.c @@ -18,7 +18,7 @@ #include #include -extern unsigned long batch_syscall_stub, __syscall_stub_start; +extern char batch_syscall_stub[], __syscall_stub_start[]; extern void wait_stub_done(int pid); @@ -38,8 +38,8 @@ static int __init init_syscall_regs(void) { get_safe_registers(syscall_regs, NULL); syscall_regs[REGS_IP_INDEX] = STUB_CODE + - ((unsigned long) &batch_syscall_stub - - (unsigned long) &__syscall_stub_start); + ((unsigned long) batch_syscall_stub - + (unsigned long) __syscall_stub_start); return 0; } diff --git a/kernel/arch/um/os-Linux/skas/process.c b/kernel/arch/um/os-Linux/skas/process.c index 7a9777570..b856c66eb 100644 --- a/kernel/arch/um/os-Linux/skas/process.c +++ b/kernel/arch/um/os-Linux/skas/process.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -45,7 +46,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 << SIGALRM) | (1 << SIGWINCH)) /* Signals that the stub will finish with - anything else is an error */ #define STUB_DONE_MASK (1 << SIGTRAP) @@ -137,9 +138,6 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) fatal_sigsegv(); - /* Mark this as a syscall */ - UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp); - if (!local_using_sysemu) { err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, @@ -174,30 +172,31 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, handle_syscall(regs); } -extern int __syscall_stub_start; +int get_syscall(struct uml_pt_regs *regs) +{ + UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp); + + return UPT_SYSCALL_NR(regs); +} + +extern char __syscall_stub_start[]; static int userspace_tramp(void *stack) { void *addr; - int err, fd; + int fd; unsigned long long offset; ptrace(PTRACE_TRACEME, 0, 0, 0); signal(SIGTERM, SIG_DFL); signal(SIGWINCH, SIG_IGN); - err = set_interval(); - if (err) { - printk(UM_KERN_ERR "userspace_tramp - setting timer failed, " - "errno = %d\n", err); - exit(1); - } /* * This has a pte, but it can't be mapped in with the usual * tlb_flush mechanism because this is part of that mechanism */ - fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); + fd = phys_mapping(to_phys(__syscall_stub_start), &offset); addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); if (addr == MAP_FAILED) { @@ -223,7 +222,7 @@ static int userspace_tramp(void *stack) unsigned long v = STUB_CODE + (unsigned long) stub_segv_handler - - (unsigned long) &__syscall_stub_start; + (unsigned long) __syscall_stub_start; set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); @@ -282,7 +281,7 @@ int start_userspace(unsigned long stub_stack) "errno = %d\n", errno); goto out_kill; } - } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); + } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM)); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { err = -EINVAL; @@ -315,8 +314,6 @@ int start_userspace(unsigned long stub_stack) 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 +322,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 @@ -401,18 +393,7 @@ void userspace(struct uml_pt_regs *regs) 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(); + case SIGALRM: break; case SIGIO: case SIGILL: @@ -447,7 +428,7 @@ static int __init init_thread_regs(void) /* Set parent's instruction pointer to start of clone-stub */ thread_regs[REGS_IP_INDEX] = STUB_CODE + (unsigned long) stub_clone_handler - - (unsigned long) &__syscall_stub_start; + (unsigned long) __syscall_stub_start; thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - sizeof(void *); #ifdef __SIGNAL_FRAMESIZE @@ -460,7 +441,6 @@ __initcall(init_thread_regs); 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; @@ -472,11 +452,10 @@ int copy_context_skas0(unsigned long new_stack, int pid) * 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 + }); err = ptrace_setregs(pid, thread_regs); if (err < 0) { diff --git a/kernel/arch/um/os-Linux/start_up.c b/kernel/arch/um/os-Linux/start_up.c index 47f1ff056..22a358ef1 100644 --- a/kernel/arch/um/os-Linux/start_up.c +++ b/kernel/arch/um/os-Linux/start_up.c @@ -94,6 +94,8 @@ static int start_ptraced_child(void) { int pid, n, status; + fflush(stdout); + pid = fork(); if (pid == 0) ptrace_child(); diff --git a/kernel/arch/um/os-Linux/time.c b/kernel/arch/um/os-Linux/time.c index e9824d5dd..0e39b9978 100644 --- a/kernel/arch/um/os-Linux/time.c +++ b/kernel/arch/um/os-Linux/time.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk}) + * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) + * Copyright (C) 2012-2014 Cisco Systems * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -10,177 +13,177 @@ #include #include #include -#include "internal.h" +#include +#include -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) { + + timer_t* t = timer; + + if(t == NULL) { + t = &event_high_res_timer; + } + + if (timer_create( + CLOCK_MONOTONIC, + NULL, + t) == -1) { + return -1; + } + return 0; } -long long disable_timer(void) +int os_timer_set_interval(void* timer, void* i) { - struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); - long long remain, max = UM_NSEC_PER_SEC / UM_HZ; + struct itimerspec its; + unsigned long long nsec; + timer_t* t = timer; + struct itimerspec* its_in = i; - 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; + nsec = UM_NSEC_PER_SEC / UM_HZ; - return remain; -} + 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; + } -long long os_nsecs(void) -{ - struct timeval tv; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = nsec; - gettimeofday(&tv, NULL); - return timeval_to_ns(&tv); -} + 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; -static inline long long timespec_to_us(const struct timespec *ts) -{ - return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + - ts->tv_nsec / UM_NSEC_PER_USEC; + 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 int after_sleep_interval(struct timespec *ts) +long long os_vnsecs(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; + struct timespec ts; - 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 }); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts); + return timespec_to_ns(&ts); +} - if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) - return -errno; +long long os_nsecs(void) +{ + 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; + if (nsecs <= 0) { + return; + } - nsecs = sleep_time(nsecs); - ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, - .tv_nsec = nsecs % UM_NSEC_PER_SEC }); + ts = ((struct timespec) { + .tv_sec = nsecs / UM_NSEC_PER_SEC, + .tv_nsec = nsecs % UM_NSEC_PER_SEC + }); - if (nanosleep(&ts, &ts) == 0) + /* + * Relay the signal if clock_nanosleep is interrupted. + */ + if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) { deliver_alarm(); - after_sleep_interval(&ts); + } } -- cgit 1.2.3-korg