From 092069fd80c6d13bf8e965ba7a879467223869b1 Mon Sep 17 00:00:00 2001 From: "Balazs Gerofi bgerofi@riken.jp" Date: Wed, 28 Nov 2012 15:22:53 +0900 Subject: [PATCH] spin-wait based kernel timer (for futex() timeout) implementation --- kernel/futex.c | 13 ++++++---- kernel/include/process.h | 9 ++++--- kernel/include/timer.h | 2 +- kernel/process.c | 20 +++++++++++++++ kernel/syscall.c | 43 +++++++++++++++++++++++++------- kernel/timer.c | 53 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 121 insertions(+), 19 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 76113c35..5d2c0fd3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -242,11 +242,14 @@ static int futex_wait(uint32_t __user *uaddr, uint32_t val, queue_unlock(queue, irqflags); if (!list_empty(&futex.link)) { - // We don't have timers for now, let's sleep forever, - // and pretend we were woken up - //time_remain = schedule_timeout(timeout); - schedule(); - time_remain = 10; + + if (timeout) { + time_remain = schedule_timeout(timeout); + } + else { + schedule(); + time_remain = 0; + } } cpu_local_var(current)->status = PS_RUNNING; diff --git a/kernel/include/process.h b/kernel/include/process.h index eb620c2d..1b0543f5 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -22,6 +22,9 @@ #define USE_LARGE_PAGES +#include +#include + struct vm_range { struct list_head list; unsigned long start, end; @@ -52,15 +55,15 @@ struct process { // Runqueue list entry struct list_head sched_list; + aal_spinlock_t spin_sleep_lock; + int spin_sleep; + struct thread { int *clear_child_tid; unsigned long tlsblock_base, tlsblock_limit; } thread; }; -#include -#include - struct process_vm { aal_atomic_t refcount; diff --git a/kernel/include/timer.h b/kernel/include/timer.h index d048b6b7..c32a863c 100644 --- a/kernel/include/timer.h +++ b/kernel/include/timer.h @@ -18,7 +18,7 @@ #include #include -#define TIMER_CPU_ID 227 +//#define TIMER_CPU_ID 227 struct timer { uint64_t timeout; diff --git a/kernel/process.c b/kernel/process.c index dc5d5fa8..6fb62c04 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -58,6 +58,9 @@ struct process *create_process(unsigned long user_pc) init_process_vm(proc->vm); + aal_mc_spinlock_init(&proc->spin_sleep_lock); + proc->spin_sleep = 0; + return proc; } @@ -434,10 +437,12 @@ void sched_init(void) cpu_local_var(runq_len) = 0; aal_mc_spinlock_init(&cpu_local_var(runq_lock)); +#ifdef TIMER_CPU_ID if (aal_mc_get_processor_id() == TIMER_CPU_ID) { init_timers(); wake_timers_loop(); } +#endif } void schedule(void) @@ -514,8 +519,23 @@ void schedule(void) int sched_wakeup_process(struct process *proc, int valid_states) { int status; + int spin_slept = 0; unsigned long irqstate; struct cpu_local_var *v = get_cpu_local_var(proc->cpu_id); + + irqstate = aal_mc_spinlock_lock(&(proc->spin_sleep_lock)); + if (proc->spin_sleep) { + dkprintf("sched_wakeup_process() spin wakeup: cpu_id: %d\n", + proc->cpu_id); + + spin_slept = 1; + proc->spin_sleep = 0; + status = 0; + } + aal_mc_spinlock_unlock(&(proc->spin_sleep_lock), irqstate); + + if (spin_slept) + return status; irqstate = aal_mc_spinlock_lock(&(v->runq_lock)); diff --git a/kernel/syscall.c b/kernel/syscall.c index 604a19e4..34be6299 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -846,8 +846,6 @@ SYSCALL_DECLARE(madvise) SYSCALL_DECLARE(futex) { - // TODO: timespec support! - //struct timespec _utime; uint64_t timeout = 0; // No timeout uint32_t val2 = 0; @@ -857,20 +855,47 @@ SYSCALL_DECLARE(futex) struct timespec *utime = (struct timespec*)aal_mc_syscall_arg3(ctx); uint32_t *uaddr2 = (uint32_t *)aal_mc_syscall_arg4(ctx); uint32_t val3 = (uint32_t)aal_mc_syscall_arg5(ctx); + + dkprintf("futex,uaddr=%lx,op=%x, val=%x, utime=%lx, uaddr2=%lx, val3=%x, []=%x\n", (unsigned long)uaddr, op, val, utime, uaddr2, val3, *uaddr); /* Mask off the FUTEX_PRIVATE_FLAG, * assume all futexes are address space private */ op = (op & FUTEX_CMD_MASK); -#if 0 - if (utime && (op == FUTEX_WAIT)) { - if (copy_from_user(&_utime, utime, sizeof(_utime)) != 0) + if (utime && (op == FUTEX_WAIT_BITSET || op == FUTEX_WAIT)) { + /* gettimeofday(&tv_now, NULL) from host */ + struct syscall_request request AAL_DMA_ALIGN; + struct timeval tv_now; + request.number = 96; + unsigned long __phys; + + dkprintf("futex,utime and FUTEX_WAIT_*, uaddr=%lx, []=%x\n", (unsigned long)uaddr, *uaddr); + + if (aal_mc_pt_virt_to_phys(cpu_local_var(current)->vm->page_table, + (void *)&tv_now, &__phys)) { + return -EFAULT; + } + + request.args[0] = __phys; + + int r = do_syscall(&request, ctx); + + if (r < 0) { return -EFAULT; - if (!timespec_valid(&_utime)) - return -EINVAL; - timeout = timespec_to_ns(_utime); + } + + dkprintf("futex, FUTEX_WAIT_*, arg3 != NULL, pc=%lx\n", (unsigned long)aal_mc_syscall_pc(ctx)); + dkprintf("now->tv_sec=%016ld,tv_nsec=%016ld\n", tv_now.tv_sec, tv_now.tv_usec * 1000); + dkprintf("utime->tv_sec=%016ld,tv_nsec=%016ld\n", utime->tv_sec, utime->tv_nsec); + + long nsec_now = ((long)tv_now.tv_sec * 1000000000ULL) + + tv_now.tv_usec * 1000; + long nsec_timeout = ((long)utime->tv_sec * 1000000000ULL) + + utime->tv_nsec * 1; + long diff_nsec = nsec_timeout - nsec_now; + + timeout = (diff_nsec / 1000) * 1100; // (usec * 1.1GHz) } -#endif /* Requeue parameter in 'utime' if op == FUTEX_CMP_REQUEUE. * number of waiters to wake in 'utime' if op == FUTEX_WAKE_OP. */ diff --git a/kernel/timer.c b/kernel/timer.c index 0c527660..b4be9616 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -30,7 +30,7 @@ #define dkprintf(...) #endif -#define LOOP_TIMEOUT 1000 /* default 1000 */ +#define LOOP_TIMEOUT 500 struct list_head timers; aal_spinlock_t timers_lock; @@ -47,6 +47,56 @@ uint64_t schedule_timeout(uint64_t timeout) struct waitq_entry my_wait; struct timer my_timer; unsigned long irqflags; + struct process *proc = cpu_local_var(current); + + irqflags = aal_mc_spinlock_lock(&proc->spin_sleep_lock); + dkprintf("schedule_timeout() spin sleep timeout: %lu\n", timeout); + proc->spin_sleep = 1; + aal_mc_spinlock_unlock(&proc->spin_sleep_lock, irqflags); + + /* Spin sleep.. */ + for (;;) { + uint64_t t_s = rdtsc(); + uint64_t t_e; + int spin_over = 0; + + irqflags = aal_mc_spinlock_lock(&proc->spin_sleep_lock); + + /* Woken up by someone? */ + if (!proc->spin_sleep) { + t_e = rdtsc(); + + spin_over = 1; + if ((t_e - t_s) < timeout) { + timeout -= (t_e - t_s); + } + else { + timeout = 1; + } + } + + aal_mc_spinlock_unlock(&proc->spin_sleep_lock, irqflags); + + t_s = rdtsc(); + + while ((rdtsc() - t_s) < LOOP_TIMEOUT) { + cpu_pause(); + } + + if (timeout < LOOP_TIMEOUT) { + timeout = 0; + spin_over = 1; + } + else { + timeout -= LOOP_TIMEOUT; + } + + if (spin_over) { + dkprintf("schedule_timeout() spin woken up, timeout: %lu\n", + timeout); + return timeout; + } + } /* Init waitq and wait entry for this timer */ my_timer.timeout = (timeout < LOOP_TIMEOUT) ? LOOP_TIMEOUT : timeout; @@ -72,6 +122,7 @@ uint64_t schedule_timeout(uint64_t timeout) if (my_timer.timeout) { list_del(&my_timer.list); } + aal_mc_spinlock_unlock(&timers_lock, irqflags); dkprintf("schedule_timeout() woken up, timeout: %lu\n",