summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2011-10-03 16:12:51 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2011-10-24 13:33:20 -0500
commit4962a22309cd7e3586aa57817689b18d67ca71c7 (patch)
tree2bfd610d6ed048f7d4a35717211eca06b15d1f69 /src/kernel
parent21185b30cd99a00f01e15edba28402cdc00de1d1 (diff)
downloadtalos-hostboot-4962a22309cd7e3586aa57817689b18d67ca71c7.tar.gz
talos-hostboot-4962a22309cd7e3586aa57817689b18d67ca71c7.zip
Support task_wait / task_wait_tid syscalls:
- Add task_end2 syscall to allow pthread_exit-like retval. - Add/maintain task states. - Create task parent/child tracking tree. - Add task_detach function. - Implement wait syscalls. Make task_exec caller the parent of spawned task: Previously the task_exec call caused a message to the VFS task, which called task_create and returned the tid in response to the message. This causes the parent of the spawned task to appear to be the VFS task. Modify task_exec / VFS handling to instead return the entry point address on the message and have task_exec call task_create directly itself. Change-Id: I6b6796f45875de37b1ab01e7596639b073820b95 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/443 Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: Andrew J. Geissler <andrewg@us.ibm.com>
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/basesegment.C11
-rw-r--r--src/kernel/cpumgr.C2
-rw-r--r--src/kernel/exception.C15
-rw-r--r--src/kernel/futexmgr.C4
-rw-r--r--src/kernel/kernel.C16
-rw-r--r--src/kernel/msghandler.C9
-rw-r--r--src/kernel/scheduler.C4
-rw-r--r--src/kernel/syscall.C74
-rw-r--r--src/kernel/taskmgr.C216
-rw-r--r--src/kernel/timemgr.C8
10 files changed, 317 insertions, 42 deletions
diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C
index 4cb2c39cb..dee18600a 100644
--- a/src/kernel/basesegment.C
+++ b/src/kernel/basesegment.C
@@ -131,7 +131,14 @@ int BaseSegment::_mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size)
uint64_t BaseSegment::findPhysicalAddress(uint64_t i_vaddr) const
{
- if(i_vaddr < iv_physMemSize) return i_vaddr;
+ if(i_vaddr < iv_physMemSize)
+ {
+ // Anything in the physical address size is valid (and linear mapped)
+ // except NULL.
+ if (i_vaddr >= PAGE_SIZE)
+ return i_vaddr;
+ else return -EFAULT;
+ }
return (iv_block ? iv_block->findPhysicalAddress(i_vaddr) : -EFAULT);
}
@@ -170,7 +177,7 @@ int BaseSegment::_mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access
// Check to see if there is a next block
if (l_block->iv_nextBlock)
{
- // set local block to the next block
+ // set local block to the next block
l_block = l_block->iv_nextBlock;
}
else
diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C
index 01af160f1..86e8653bf 100644
--- a/src/kernel/cpumgr.C
+++ b/src/kernel/cpumgr.C
@@ -149,7 +149,6 @@ void CpuManager::startCPU(ssize_t i)
if (currentCPU)
{
- setSPRG3((uint64_t) cv_cpus[i]->idle_task);
setDEC(TimeManager::getTimeSliceCount());
}
return;
@@ -157,7 +156,6 @@ void CpuManager::startCPU(ssize_t i)
void CpuManager::startSlaveCPU(cpu_t* cpu)
{
- setSPRG3((uint64_t) cpu->idle_task);
setDEC(TimeManager::getTimeSliceCount());
return;
diff --git a/src/kernel/exception.C b/src/kernel/exception.C
index 6f015a57c..cbe97b220 100644
--- a/src/kernel/exception.C
+++ b/src/kernel/exception.C
@@ -29,7 +29,6 @@
#include <kernel/vmmmgr.H>
#include <kernel/cpuid.H>
-namespace Systemcalls { void TaskEnd(task_t*); }
namespace ExceptionHandles
{
bool HvEmulation(task_t*);
@@ -54,7 +53,7 @@ void kernel_execute_prog_ex()
if (!handled)
{
printk("Program exception, killing task %d\n", t->tid);
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
@@ -78,7 +77,7 @@ void kernel_execute_data_storage()
{
printk("Data Storage exception on %d: %lx, %lx\n",
t->tid, getDAR(), getDSISR());
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
@@ -87,7 +86,7 @@ void kernel_execute_data_segment()
{
task_t* t = TaskManager::getCurrentTask();
printk("Data Segment exception, killing task %d\n", t->tid);
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
const uint64_t EXCEPTION_SRR1_INSTR_MASK = 0x0000000040000000;
@@ -110,7 +109,7 @@ void kernel_execute_inst_storage()
{
printk("Inst Storage exception on %d: %lx, %lx\n",
t->tid, getSRR0(), getSRR1());
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
@@ -119,7 +118,7 @@ void kernel_execute_inst_segment()
{
task_t* t = TaskManager::getCurrentTask();
printk("Inst Segment exception, killing task %d\n", t->tid);
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
extern "C"
@@ -127,7 +126,7 @@ void kernel_execute_alignment()
{
task_t* t = TaskManager::getCurrentTask();
printk("Alignment exception, killing task %d\n", t->tid);
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
extern "C"
@@ -136,7 +135,7 @@ void kernel_execute_hype_emu_assist()
task_t* t = TaskManager::getCurrentTask();
printk("HypeEmu: Illegal instruction in task %d\n"
"\tHSSR0 = %lx, HEIR = %lx\n", t->tid, getHSRR0(), getHEIR());
- Systemcalls::TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
namespace ExceptionHandles
diff --git a/src/kernel/futexmgr.C b/src/kernel/futexmgr.C
index e350e54a4..ec0b5ed64 100644
--- a/src/kernel/futexmgr.C
+++ b/src/kernel/futexmgr.C
@@ -68,6 +68,10 @@ uint64_t FutexManager::_wait(task_t* i_task, uint64_t * i_addr, uint64_t i_val)
waiter->key = i_addr;
waiter->task = i_task;
+ // Set blocked state.
+ i_task->state = TASK_STATE_BLOCK_FUTEX;
+ i_task->state_info = i_addr;
+
// Now add the futex/task it to the wait queue
iv_list.insert(waiter);
iv_lock.unlock();
diff --git a/src/kernel/kernel.C b/src/kernel/kernel.C
index 46ca11342..557a1c81c 100644
--- a/src/kernel/kernel.C
+++ b/src/kernel/kernel.C
@@ -43,7 +43,7 @@ extern uint64_t kernel_other_thread_spinlock;
class Kernel
{
public:
- void cppBootstrap();
+ void cppBootstrap();
void memBootstrap();
void cpuBootstrap();
void inittaskBootstrap();
@@ -56,19 +56,22 @@ extern "C"
int main()
{
printk("Booting %s kernel...\n\n", "Hostboot");
-
+
+ // Erase task-pointer so that TaskManager::getCurrentTask() returns NULL.
+ setSPRG3(NULL);
+
Kernel& kernel = Singleton<Kernel>::instance();
kernel.cppBootstrap();
- kernel.memBootstrap();
+ kernel.memBootstrap();
kernel.cpuBootstrap();
kernel.inittaskBootstrap();
-
+
// Ready to let the other CPUs go.
lwsync();
kernel_other_thread_spinlock = 1;
- kernel_dispatch_task(); // no return.
+ kernel_dispatch_task(); // no return.
while(1);
return 0;
}
@@ -76,6 +79,9 @@ int main()
extern "C"
int smp_slave_main(cpu_t* cpu)
{
+ // Erase task-pointer so that TaskManager::getCurrentTask() returns NULL.
+ setSPRG3(NULL);
+
CpuManager::init_slave_smp(cpu);
VmmManager::init_slb();
cpu->scheduler->setNextRunnable();
diff --git a/src/kernel/msghandler.C b/src/kernel/msghandler.C
index 32da05673..82dab7f8f 100644
--- a/src/kernel/msghandler.C
+++ b/src/kernel/msghandler.C
@@ -29,8 +29,6 @@
#include <kernel/taskmgr.H>
#include <kernel/console.H>
-namespace Systemcalls { void TaskEnd(task_t*); };
-
void MessageHandler::sendMessage(msg_sys_types_t i_type, void* i_key,
void* i_data, task_t* i_task)
{
@@ -74,6 +72,11 @@ void MessageHandler::sendMessage(msg_sys_types_t i_type, void* i_key,
// Defer task while waiting for message response.
if ((NULL != i_task) && (TaskManager::getCurrentTask() == i_task))
{
+ // Set block status.
+ i_task->state = TASK_STATE_BLOCK_USRSPACE;
+ i_task->state_info = i_key;
+
+ // Select next task off scheduler.
i_task->cpu->scheduler->setNextRunnable();
}
@@ -138,7 +141,7 @@ int MessageHandler::recvMessage(msg_t* i_msg)
// Unsuccessful, unhandled response. Kill task.
printk("Unhandled msg rc %d for key %p on task %d @ %p\n",
msg_rc, key, deferred_task->tid, deferred_task->context.nip);
- Systemcalls::TaskEnd(deferred_task);
+ TaskManager::endTask(deferred_task, NULL, TASK_STATUS_CRASHED);
}
else if (CONTINUE_DEFER == rc)
{
diff --git a/src/kernel/scheduler.C b/src/kernel/scheduler.C
index 28f70debd..8a8da89a4 100644
--- a/src/kernel/scheduler.C
+++ b/src/kernel/scheduler.C
@@ -31,6 +31,8 @@
void Scheduler::addTask(task_t* t)
{
+ t->state = TASK_STATE_READY;
+
if (t->cpu->idle_task != t)
{
// If task is pinned to this CPU, add to the per-CPU queue.
@@ -53,6 +55,8 @@ void Scheduler::addTask(task_t* t)
void Scheduler::addTaskMasterCPU(task_t* t)
{
+ t->state = TASK_STATE_READY;
+
if (t->cpu->idle_task != t)
{
cpu_t* master = CpuManager::getMasterCPU();
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index cb4650c7a..53fdb287e 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -62,6 +62,7 @@ namespace Systemcalls
void TaskStart(task_t*);
void TaskEnd(task_t*);
void TaskMigrateToMaster(task_t*);
+ void TaskWait(task_t*);
void MsgQCreate(task_t*);
void MsgQDestroy(task_t*);
void MsgQRegisterRoot(task_t*);
@@ -91,6 +92,7 @@ namespace Systemcalls
&TaskStart, // TASK_START
&TaskEnd, // TASK_END
&TaskMigrateToMaster, // TASK_MIGRATE_TO_MASTER
+ &TaskWait, // TASK_WAIT
&MsgQCreate, // MSGQ_CREATE
&MsgQDestroy, // MSGQ_DESTROY
@@ -163,19 +165,8 @@ namespace Systemcalls
void TaskEnd(task_t* t)
{
- // Make sure task pointers are updated before we delete this task.
- t->cpu->scheduler->setNextRunnable();
-
- // TODO: Deal with join.
-
- // Clean up task memory.
- // Delete FP context.
- if (t->fp_context)
- delete t->fp_context;
- // Delete stack.
- StackSegment::deleteStack(t->tid);
- // Delete task struct.
- delete t;
+ TaskManager::endTask(t, (void*)TASK_GETARG0(t),
+ TASK_STATUS_EXITED_CLEAN);
}
void TaskMigrateToMaster(task_t* t)
@@ -194,6 +185,46 @@ namespace Systemcalls
t->cpu->scheduler->setNextRunnable();
}
+ void TaskWait(task_t* t)
+ {
+ int64_t tid = static_cast<int64_t>(TASK_GETARG0(t));
+ int* status = reinterpret_cast<int*>(TASK_GETARG1(t));
+ void** retval = reinterpret_cast<void**>(TASK_GETARG2(t));
+
+ // Validate status address and convert to kernel address.
+ if (status != NULL)
+ {
+ uint64_t addr =
+ VmmManager::findPhysicalAddress(
+ reinterpret_cast<uint64_t>(status));
+
+ if (addr == (static_cast<uint64_t>(-EFAULT)))
+ {
+ TASK_SETRTN(t, -EFAULT);
+ return;
+ }
+ status = reinterpret_cast<int*>(addr);
+ }
+
+ // Validate retval address and convert to kernel address.
+ if (retval != NULL)
+ {
+ uint64_t addr =
+ VmmManager::findPhysicalAddress(
+ reinterpret_cast<uint64_t>(retval));
+
+ if (addr == (static_cast<uint64_t>(-EFAULT)))
+ {
+ TASK_SETRTN(t, -EFAULT);
+ return;
+ }
+ retval = reinterpret_cast<void**>(addr);
+ }
+
+ // Perform wait.
+ TaskManager::waitTask(t, tid, status, retval);
+ }
+
void MsgQCreate(task_t* t)
{
TASK_SETRTN(t, (uint64_t) new MessageQueue());
@@ -281,6 +312,8 @@ namespace Systemcalls
MessagePending* mp = new MessagePending();
mp->key = m;
mp->task = t;
+ t->state = TASK_STATE_BLOCK_MSG;
+ t->state_info = mq;
mq->lock.lock();
@@ -355,6 +388,8 @@ namespace Systemcalls
if (NULL == mp)
{
mq->waiting.insert(t);
+ t->state = TASK_STATE_BLOCK_MSG;
+ t->state_info = mq;
t->cpu->scheduler->setNextRunnable();
}
else
@@ -414,8 +449,7 @@ namespace Systemcalls
TimeManager::delayTask(t, TASK_GETARG0(t), TASK_GETARG1(t));
TASK_SETRTN(t, 0);
- Scheduler* s = t->cpu->scheduler;
- s->setNextRunnable();
+ t->cpu->scheduler->setNextRunnable();
}
/**
@@ -445,7 +479,7 @@ namespace Systemcalls
{
printk("Task %d terminated. No physical address found for address 0x%p",
t->tid, (void *) uaddr);
- TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
@@ -470,7 +504,7 @@ namespace Systemcalls
{
printk("Task %d terminated. No physical address found for address 0x%p",
t->tid, (void *) uaddr);
- TaskEnd(t);
+ TaskManager::endTask(t, NULL, TASK_STATUS_CRASHED);
}
}
@@ -529,12 +563,12 @@ namespace Systemcalls
* @param[in] t: The task used to set Page Permissions for a given block
*/
void MmSetPermission(task_t* t)
- {
+ {
void* va = (void*)TASK_GETARG0(t);
uint64_t size = (uint64_t)TASK_GETARG1(t);
PAGE_PERMISSIONS access_type = (PAGE_PERMISSIONS)TASK_GETARG2(t);
-
+
TASK_SETRTN(t, VmmManager::mmSetPermission(va,size, access_type));
}
-
+
};
diff --git a/src/kernel/taskmgr.C b/src/kernel/taskmgr.C
index 04d91c4f8..0ed493801 100644
--- a/src/kernel/taskmgr.C
+++ b/src/kernel/taskmgr.C
@@ -26,6 +26,9 @@
#include <kernel/pagemgr.H>
#include <kernel/cpumgr.H>
#include <kernel/stacksegment.H>
+#include <kernel/stacksegment.H>
+#include <kernel/cpu.H>
+#include <kernel/scheduler.H>
#include <sys/task.h>
#include <arch/ppc.H>
#include <string.h>
@@ -50,6 +53,7 @@ task_t* TaskManager::getCurrentTask()
void TaskManager::setCurrentTask(task_t* t)
{
t->cpu = CpuManager::getCurrentCPU();
+ t->state = TASK_STATE_RUNNING;
setSPRG3((uint64_t)t);
return;
}
@@ -68,6 +72,16 @@ task_t* TaskManager::createTask(TaskManager::task_fn_t t, void* p)
return Singleton<TaskManager>::instance()._createTask(t, p, true);
}
+void TaskManager::endTask(task_t* t, void* retval, int status)
+{
+ Singleton<TaskManager>::instance()._endTask(t,retval,status);
+}
+
+void TaskManager::waitTask(task_t* t, int64_t tid, int* status, void** retval)
+{
+ Singleton<TaskManager>::instance()._waitTask(t,tid,status,retval);
+}
+
task_t* TaskManager::_createIdleTask()
{
return this->_createTask(&TaskManager::idleTaskLoop, NULL, false);
@@ -113,6 +127,208 @@ task_t* TaskManager::_createTask(TaskManager::task_fn_t t,
// Clear FP context (start with FP disabled on all tasks).
task->fp_context = NULL;
+ // Clear task state info.
+ task->state = TASK_STATE_READY;
+ task->state_info = NULL;
+
+ // Create tracker instance for this task.
+ task_tracking_t* tracker = new task_tracking_t;
+ tracker->key = task->tid;
+ tracker->task = task;
+ tracker->status = -1;
+ tracker->retval = NULL;
+ tracker->wait_info = NULL;
+ tracker->entry_point = reinterpret_cast<void*>(t);
+ task->tracker = tracker;
+
+ // Assign parent for tracker instance, add to task tree.
+ iv_spinlock.lock();
+ task_t* parent = getCurrentTask();
+ if (NULL == parent)
+ {
+ tracker->parent = NULL;
+ iv_taskList.insert(tracker);
+ }
+ else
+ {
+ tracker->parent = parent->tracker;
+ parent->tracker->children.insert(tracker);
+ }
+ iv_spinlock.unlock();
+
return task;
}
+
+void TaskManager::_endTask(task_t* t, void* retval, int status)
+{
+ // Update task state.
+ t->state = TASK_STATE_ENDED;
+
+ // Make sure task pointers are updated before we delete this task.
+ if (getCurrentTask() == t)
+ t->cpu->scheduler->setNextRunnable();
+
+ // Update status in tracker.
+ t->tracker->status = status;
+ t->tracker->retval = retval;
+ t->tracker->task = NULL; // NULL signifies task is complete for now.
+
+ iv_spinlock.lock();
+
+ if (t->detached) // If detached, just clean up the tracker.
+ {
+ removeTracker(t->tracker);
+ }
+ else // If not detached, do join.
+ {
+ if (t->tracker->parent && t->tracker->parent->wait_info)
+ {
+ task_tracking_t* parent = t->tracker->parent;
+
+ if ((parent->wait_info->tid < 0) ||
+ (parent->wait_info->tid == t->tid))
+ {
+ if (parent->wait_info->status)
+ {
+ *(parent->wait_info->status) = status;
+ }
+ if (parent->wait_info->retval)
+ {
+ *(parent->wait_info->retval) = retval;
+ }
+ delete parent->wait_info;
+ parent->wait_info = NULL;
+ lwsync(); // Ensure status is pushed to memory before parent
+ // task begins execution.
+
+ TASK_SETRTN(parent->task, t->tid);
+ removeTracker(t->tracker);
+ parent->task->cpu->scheduler->addTask(parent->task);
+ }
+ }
+ }
+ iv_spinlock.unlock();
+
+ // Clean up task memory.
+ // Delete FP context.
+ if (t->fp_context)
+ delete t->fp_context;
+ // Delete stack.
+ StackSegment::deleteStack(t->tid);
+ // Delete task struct.
+ delete t;
+}
+
+void TaskManager::_waitTask(task_t* t, int64_t tid, int* status, void** retval)
+{
+ iv_spinlock.lock();
+
+ do
+ {
+ // Search for a candidate completed child task.
+ task_tracking_t* child_task = NULL;
+
+ if (tid < 0) // -1 => Look for any task.
+ {
+ task_tracking_t* children = t->tracker->children.begin();
+ if (!children)
+ {
+ // No children at all, this is a deadlock.
+ TASK_SETRTN(t, -EDEADLK);
+ break;
+ }
+ while(children)
+ {
+ if (!children->task)
+ {
+ child_task = children;
+ children = NULL;
+ }
+ else
+ {
+ children = children->next;
+ }
+ }
+ }
+ else // Look for a specific task.
+ {
+ // This copy is needed to create a reference of the appropriate
+ // type to pass into the 'find' function. Otherwise, you get
+ // type-punned reference errors.
+ task_tracking_t::key_type _tid = tid;
+
+ child_task = t->tracker->children.find(_tid);
+
+ // Check that we aren't asking to wait on a task that isn't our
+ // child, potential deadlock.
+ if (NULL == child_task)
+ {
+ TASK_SETRTN(t, -EDEADLK);
+ break;
+ }
+ }
+
+ // If there was a finished task found return information to caller.
+ if (child_task && (child_task->task == NULL))
+ {
+ TASK_SETRTN(t, child_task->key);
+ if (status)
+ {
+ *status = child_task->status;
+ }
+ if (retval)
+ {
+ *retval = child_task->retval;
+ }
+ removeTracker(child_task);
+ }
+ else // Otherwise, create wait-info to defer task.
+ {
+ task_wait_t* tj = t->tracker->wait_info = new task_wait_t;
+ tj->tid = tid;
+ tj->status = status;
+ tj->retval = retval;
+
+ t->state = TASK_STATE_BLOCK_JOIN;
+ t->state_info = reinterpret_cast<void*>(tid);
+
+ t->cpu->scheduler->setNextRunnable();
+ }
+
+ } while(0);
+
+ iv_spinlock.unlock();
+
+ return;
+}
+
+void TaskManager::removeTracker(task_tracking_t* t)
+{
+ task_tracking_list_t* trackingList = NULL;
+
+ task_tracking_t* parent = NULL;
+
+ if (t->parent)
+ {
+ trackingList = &t->parent->children;
+ parent = t->parent;
+ }
+ else // Parent is kernel.
+ {
+ trackingList = &iv_taskList;
+ }
+
+ // Remove tracker from parent list.
+ trackingList->erase(t);
+
+ // Add children to parent.
+ while(task_tracking_t* child = t->children.remove())
+ {
+ child->parent = parent;
+ trackingList->insert(child);
+ }
+
+ // Delete tracker object.
+ delete t;
+}
diff --git a/src/kernel/timemgr.C b/src/kernel/timemgr.C
index cbe72440b..896871a4d 100644
--- a/src/kernel/timemgr.C
+++ b/src/kernel/timemgr.C
@@ -23,6 +23,7 @@
#include <kernel/timemgr.H>
#include <kernel/scheduler.H>
#include <util/singleton.H>
+#include <kernel/task.H>
uint64_t TimeManager::iv_timebaseFreq = 0xFFFFFFFF;
@@ -40,7 +41,7 @@ uint64_t TimeManager::convertSecToTicks(uint64_t i_sec, uint64_t i_nsec)
{
// This code will handle times almost up to a year without overflowing a
// uint64. This should be more than sufficient for our purposes.
-
+
// Result = ((sec * 10^9 + nsec) * tb) / 10^9.
uint64_t result = ((i_sec * 1000000000ULL) + i_nsec);
result *= (iv_timebaseFreq / 1000000);
@@ -57,10 +58,13 @@ void TimeManager::_delayTask(task_t* t, uint64_t i_sec, uint64_t i_nsec)
{
_TimeManager_Delay_t* node = new _TimeManager_Delay_t();
- node->key = this->getCurrentTimeBase() +
+ node->key = this->getCurrentTimeBase() +
this->convertSecToTicks(i_sec, i_nsec);
node->task = t;
+ t->state = TASK_STATE_BLOCK_SLEEP;
+ t->state_info = (void*)node->key;
+
iv_taskList[getPIR()].insert(node);
}
OpenPOWER on IntegriCloud