summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/futexmgr.C54
-rw-r--r--src/kernel/syscall.C105
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
OpenPOWER on IntegriCloud