diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/futexmgr.C | 54 | ||||
-rw-r--r-- | src/kernel/syscall.C | 105 |
2 files changed, 105 insertions, 54 deletions
diff --git a/src/kernel/futexmgr.C b/src/kernel/futexmgr.C index 606e26c8c..f66452543 100644 --- a/src/kernel/futexmgr.C +++ b/src/kernel/futexmgr.C @@ -42,9 +42,11 @@ uint64_t FutexManager::wait(task_t* i_task, uint64_t * i_addr, uint64_t i_val) //----------------------------------------------------------------------------- -uint64_t FutexManager::wake(uint64_t * i_addr, uint64_t i_count) +uint64_t FutexManager::wake(uint64_t * i_futex1, uint64_t i_count1, + uint64_t * i_futex2, uint64_t i_count2) { - return Singleton<FutexManager>::instance()._wake(i_addr, i_count); + return Singleton<FutexManager>::instance()._wake(i_futex1, i_count1, + i_futex2, i_count2); } //----------------------------------------------------------------------------- @@ -57,7 +59,7 @@ uint64_t FutexManager::_wait(task_t* i_task, uint64_t * i_addr, uint64_t i_val) if(unlikely(*i_addr != i_val)) { - // some other thread has modified the futex + // some other task has modified the futex // bail-out retry required. iv_lock.unlock(); rc = EWOULDBLOCK; @@ -81,18 +83,22 @@ uint64_t FutexManager::_wait(task_t* i_task, uint64_t * i_addr, uint64_t i_val) return rc; } -//----------------------------------------------------------------------------- -uint64_t FutexManager::_wake(uint64_t * i_addr, uint64_t i_count) +// Wake processes. Any number of processes in excess of count1 are not +// woken up but moved to futex2. the number of processes to move +// is capped by count2. +uint64_t FutexManager::_wake(uint64_t * i_futex1, uint64_t i_count1, + uint64_t * i_futex2, uint64_t i_count2 + ) { uint64_t started = 0; - // Remove task(s) from futex queue - // Put it/them on the run queue iv_lock.lock(); - while(started < i_count) + + // First start up to i_count1 task(s) + while(started < i_count1) { - _FutexWait_t * waiter = iv_list.find(i_addr); + _FutexWait_t * waiter = iv_list.find(i_futex1); if(waiter == NULL) { break; @@ -109,6 +115,36 @@ uint64_t FutexManager::_wake(uint64_t * i_addr, uint64_t i_count) wait_task->cpu->scheduler->addTask(wait_task); ++started; } + + if(i_futex2 && i_count2) + { + uint64_t moved = 0; + + // Move up to i_count2 tasks to futex2 + while(moved < i_count2) + { + // What if *i_futex2 got modified !!!! TODO + // Do we need a safety check here (another val param) ???? + _FutexWait_t * waiter = iv_list.find(i_futex1); + if(waiter == NULL) + { + break; + } + + task_t * wait_task = waiter->task; + iv_list.erase(waiter); + + kassert(wait_task != NULL); // should never happen, but... + + waiter->key = i_futex2; + wait_task->state_info = i_futex2; + + iv_list.insert(waiter); + ++moved; + } + } + + iv_lock.unlock(); return started; diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 561218b00..f0f5b81f0 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -40,6 +40,7 @@ #include <kernel/stacksegment.H> #include <kernel/heapmgr.H> #include <kernel/intmsghandler.H> +#include <sys/sync.h> extern "C" void kernel_execute_decrementer() @@ -87,8 +88,7 @@ namespace Systemcalls void DevMap(task_t*); void DevUnmap(task_t*); void TimeNanosleep(task_t*); - void FutexWait(task_t *t); - void FutexWake(task_t *t); + void Futex(task_t *t); void Shutdown(task_t *t); void CpuCoreType(task_t *t); void CpuDDLevel(task_t *t); @@ -119,8 +119,7 @@ namespace Systemcalls &TimeNanosleep, // TIME_NANOSLEEP - &FutexWait, // FUTEX_WAIT - &FutexWake, // FUTEX_WAKE + &Futex, // SYS_FUTEX operations &Shutdown, // MISC_SHUTDOWN &CpuCoreType, // MISC_CPUCORETYPE @@ -475,62 +474,78 @@ namespace Systemcalls t->cpu->scheduler->setNextRunnable(); } - /** - * Put task on wait queue based on futex - * @param[in] t: The task to block - */ - void FutexWait(task_t * t) + + void Futex(task_t * t) { - uint64_t uaddr = (uint64_t) TASK_GETARG0(t); - uint64_t val = (uint64_t) TASK_GETARG1(t); + uint64_t op = static_cast<uint64_t>(TASK_GETARG0(t)); + uint64_t futex = static_cast<uint64_t>(TASK_GETARG1(t)); + uint64_t val = static_cast<uint64_t>(TASK_GETARG2(t)); + uint64_t val2 = static_cast<uint64_t>(TASK_GETARG3(t)); + uint64_t futex2 = static_cast<uint64_t>(TASK_GETARG4(t)); + uint64_t rc = 0; // Set RC to success initially. TASK_SETRTN(t,0); - //translate uaddr from user space to kernel space - uaddr = VmmManager::findPhysicalAddress(uaddr); - if(uaddr != (uint64_t)(-EFAULT)) - { - uint64_t rc = FutexManager::wait(t,(uint64_t *)uaddr,val); - if (rc != 0) // Can only set rc if we still have control of the task, - // which is only (for certain) on error rc's. - { - TASK_SETRTN(t,rc); - } - } - else + futex = VmmManager::findPhysicalAddress(futex); + if(futex == (static_cast<uint64_t>(-EFAULT))) { printk("Task %d terminated. No physical address found for address 0x%p", - t->tid, (void *) uaddr); + t->tid, + reinterpret_cast<void *>(futex)); + TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED); + return; } - } - /** - * Wake tasks on futex wait queue - * @param[in] t: The current task - */ - void FutexWake(task_t * t) - { - uint64_t uaddr = (uint64_t) TASK_GETARG0(t); - uint64_t count = (uint64_t) TASK_GETARG1(t); + uint64_t * futex_p = reinterpret_cast<uint64_t *>(futex); - // translate uaddr from user space to kernel space - uaddr = VmmManager::findPhysicalAddress(uaddr); - if(uaddr != (uint64_t)(-EFAULT)) + switch(op) { - uint64_t started = FutexManager::wake((uint64_t *)uaddr,count); + case FUTEX_WAIT: // Put task on wait queue based on futex - TASK_SETRTN(t,started); - } - else - { - printk("Task %d terminated. No physical address found for address 0x%p", - t->tid, (void *) uaddr); - TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED); - } + rc = FutexManager::wait(t, futex_p, val); + + // Can only be set rc if control of the task is still had, + // which is only, for certain, on error rc's + if(rc != 0) + { + TASK_SETRTN(t,rc); + } + break; + + case FUTEX_WAKE: // Wake task(s) on the futex wait queue + + rc = FutexManager::wake(futex_p, val); + TASK_SETRTN(t,rc); + break; + + case FUTEX_REQUEUE: + // Wake (val) task(s) on futex && requeue remaining tasks on futex2 + + futex2 = VmmManager::findPhysicalAddress(futex2); + if(futex2 == (static_cast<uint64_t>(-EFAULT))) + { + printk("Task %d terminated. No physical address found for address 0x%p", + t->tid, + reinterpret_cast<void *>(futex2)); + + TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED); + return; + } + + rc = FutexManager::wake(futex_p, val, + reinterpret_cast<uint64_t *>(futex2), + val2); + break; + + default: + printk("ERROR Futex invalid op %ld\n",op); + TASK_SETRTN(t,static_cast<uint64_t>(-EINVAL)); + }; } + /** * Shutdown all CPUs * @param[in] t: The current task |