spin-wait based kernel timer (for futex() timeout) implementation
This commit is contained in:
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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. */
|
||||
|
||||
@ -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",
|
||||
|
||||
Reference in New Issue
Block a user