spin-wait based kernel timer (for futex() timeout) implementation

This commit is contained in:
Balazs Gerofi bgerofi@riken.jp
2012-11-28 15:22:53 +09:00
parent b59e36e1a5
commit 092069fd80
6 changed files with 121 additions and 19 deletions

View File

@ -242,11 +242,14 @@ static int futex_wait(uint32_t __user *uaddr, uint32_t val,
queue_unlock(queue, irqflags); queue_unlock(queue, irqflags);
if (!list_empty(&futex.link)) { if (!list_empty(&futex.link)) {
// We don't have timers for now, let's sleep forever,
// and pretend we were woken up if (timeout) {
//time_remain = schedule_timeout(timeout); time_remain = schedule_timeout(timeout);
schedule(); }
time_remain = 10; else {
schedule();
time_remain = 0;
}
} }
cpu_local_var(current)->status = PS_RUNNING; cpu_local_var(current)->status = PS_RUNNING;

View File

@ -22,6 +22,9 @@
#define USE_LARGE_PAGES #define USE_LARGE_PAGES
#include <waitq.h>
#include <futex.h>
struct vm_range { struct vm_range {
struct list_head list; struct list_head list;
unsigned long start, end; unsigned long start, end;
@ -52,15 +55,15 @@ struct process {
// Runqueue list entry // Runqueue list entry
struct list_head sched_list; struct list_head sched_list;
aal_spinlock_t spin_sleep_lock;
int spin_sleep;
struct thread { struct thread {
int *clear_child_tid; int *clear_child_tid;
unsigned long tlsblock_base, tlsblock_limit; unsigned long tlsblock_base, tlsblock_limit;
} thread; } thread;
}; };
#include <waitq.h>
#include <futex.h>
struct process_vm { struct process_vm {
aal_atomic_t refcount; aal_atomic_t refcount;

View File

@ -18,7 +18,7 @@
#include <affinity.h> #include <affinity.h>
#include <time.h> #include <time.h>
#define TIMER_CPU_ID 227 //#define TIMER_CPU_ID 227
struct timer { struct timer {
uint64_t timeout; uint64_t timeout;

View File

@ -58,6 +58,9 @@ struct process *create_process(unsigned long user_pc)
init_process_vm(proc->vm); init_process_vm(proc->vm);
aal_mc_spinlock_init(&proc->spin_sleep_lock);
proc->spin_sleep = 0;
return proc; return proc;
} }
@ -434,10 +437,12 @@ void sched_init(void)
cpu_local_var(runq_len) = 0; cpu_local_var(runq_len) = 0;
aal_mc_spinlock_init(&cpu_local_var(runq_lock)); aal_mc_spinlock_init(&cpu_local_var(runq_lock));
#ifdef TIMER_CPU_ID
if (aal_mc_get_processor_id() == TIMER_CPU_ID) { if (aal_mc_get_processor_id() == TIMER_CPU_ID) {
init_timers(); init_timers();
wake_timers_loop(); wake_timers_loop();
} }
#endif
} }
void schedule(void) void schedule(void)
@ -514,8 +519,23 @@ void schedule(void)
int sched_wakeup_process(struct process *proc, int valid_states) int sched_wakeup_process(struct process *proc, int valid_states)
{ {
int status; int status;
int spin_slept = 0;
unsigned long irqstate; unsigned long irqstate;
struct cpu_local_var *v = get_cpu_local_var(proc->cpu_id); 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)); irqstate = aal_mc_spinlock_lock(&(v->runq_lock));

View File

@ -846,8 +846,6 @@ SYSCALL_DECLARE(madvise)
SYSCALL_DECLARE(futex) SYSCALL_DECLARE(futex)
{ {
// TODO: timespec support!
//struct timespec _utime;
uint64_t timeout = 0; // No timeout uint64_t timeout = 0; // No timeout
uint32_t val2 = 0; uint32_t val2 = 0;
@ -857,20 +855,47 @@ SYSCALL_DECLARE(futex)
struct timespec *utime = (struct timespec*)aal_mc_syscall_arg3(ctx); struct timespec *utime = (struct timespec*)aal_mc_syscall_arg3(ctx);
uint32_t *uaddr2 = (uint32_t *)aal_mc_syscall_arg4(ctx); uint32_t *uaddr2 = (uint32_t *)aal_mc_syscall_arg4(ctx);
uint32_t val3 = (uint32_t)aal_mc_syscall_arg5(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, /* Mask off the FUTEX_PRIVATE_FLAG,
* assume all futexes are address space private */ * assume all futexes are address space private */
op = (op & FUTEX_CMD_MASK); op = (op & FUTEX_CMD_MASK);
#if 0 if (utime && (op == FUTEX_WAIT_BITSET || op == FUTEX_WAIT)) {
if (utime && (op == FUTEX_WAIT)) { /* gettimeofday(&tv_now, NULL) from host */
if (copy_from_user(&_utime, utime, sizeof(_utime)) != 0) 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; 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. /* Requeue parameter in 'utime' if op == FUTEX_CMP_REQUEUE.
* number of waiters to wake in 'utime' if op == FUTEX_WAKE_OP. */ * number of waiters to wake in 'utime' if op == FUTEX_WAKE_OP. */

View File

@ -30,7 +30,7 @@
#define dkprintf(...) #define dkprintf(...)
#endif #endif
#define LOOP_TIMEOUT 1000 /* default 1000 */ #define LOOP_TIMEOUT 500
struct list_head timers; struct list_head timers;
aal_spinlock_t timers_lock; aal_spinlock_t timers_lock;
@ -47,6 +47,56 @@ uint64_t schedule_timeout(uint64_t timeout)
struct waitq_entry my_wait; struct waitq_entry my_wait;
struct timer my_timer; struct timer my_timer;
unsigned long irqflags; 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 */ /* Init waitq and wait entry for this timer */
my_timer.timeout = (timeout < LOOP_TIMEOUT) ? LOOP_TIMEOUT : timeout; my_timer.timeout = (timeout < LOOP_TIMEOUT) ? LOOP_TIMEOUT : timeout;
@ -72,6 +122,7 @@ uint64_t schedule_timeout(uint64_t timeout)
if (my_timer.timeout) { if (my_timer.timeout) {
list_del(&my_timer.list); list_del(&my_timer.list);
} }
aal_mc_spinlock_unlock(&timers_lock, irqflags); aal_mc_spinlock_unlock(&timers_lock, irqflags);
dkprintf("schedule_timeout() woken up, timeout: %lu\n", dkprintf("schedule_timeout() woken up, timeout: %lu\n",