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);
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;

View File

@ -22,6 +22,9 @@
#define USE_LARGE_PAGES
#include <waitq.h>
#include <futex.h>
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 <waitq.h>
#include <futex.h>
struct process_vm {
aal_atomic_t refcount;

View File

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

View File

@ -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));

View File

@ -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. */

View File

@ -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",