diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/makefile | 2 | ||||
-rw-r--r-- | src/kernel/msghandler.C | 141 | ||||
-rw-r--r-- | src/kernel/syscall.C | 58 | ||||
-rw-r--r-- | src/kernel/vmmmgr.C | 5 |
4 files changed, 185 insertions, 21 deletions
diff --git a/src/kernel/makefile b/src/kernel/makefile index c3af165c9..5ccbf8da9 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -3,7 +3,7 @@ ROOTPATH = ../.. OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o -OBJS += block.o cpuid.o misc.o +OBJS += block.o cpuid.o misc.o msghandler.o include ${ROOTPATH}/config.mk diff --git a/src/kernel/msghandler.C b/src/kernel/msghandler.C new file mode 100644 index 000000000..f5f43fa1e --- /dev/null +++ b/src/kernel/msghandler.C @@ -0,0 +1,141 @@ +#include <assert.h> +#include <errno.h> +#include <kernel/msghandler.H> +#include <kernel/task.H> +#include <kernel/cpu.H> +#include <kernel/scheduler.H> +#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) +{ + // Save pending info for when we get the response. + MessageHandler_Pending* mp = new MessageHandler_Pending; + mp->key = i_key; + mp->task = i_task; + + // Send userspace message if one hasn't been sent for this key. + if (!iv_pending.find(i_key)) + { + // Create message. + msg_t* m = new msg_t; + m->type = i_type; + m->data[0] = reinterpret_cast<uint64_t>(i_key); + m->data[1] = reinterpret_cast<uint64_t>(i_data); + m->__reserved__async = 1; + + // Create pending response object. + MessagePending* mp = new MessagePending(); + mp->key = m; + mp->task = reinterpret_cast<task_t*>(this); + + // Send to userspace... + iv_msgq->lock.lock(); + task_t* waiter = iv_msgq->waiting.remove(); + if (NULL == waiter) // No waiting task, queue for msg_wait call. + { + iv_msgq->messages.insert(mp); + } + else // Waiting task, set msg as return and release. + { + TASK_SETRTN(waiter, (uint64_t) m); + iv_msgq->responses.insert(mp); + waiter->cpu = i_task->cpu; + TaskManager::setCurrentTask(waiter); + } + iv_msgq->lock.unlock(); + } + + // Defer task while waiting for message response. + if ((NULL != i_task) && (TaskManager::getCurrentTask() == i_task)) + { + i_task->cpu->scheduler->setNextRunnable(); + } + + // Insert pending info into our queue until response is recv'd. + iv_pending.insert(mp); +} + +int MessageHandler::recvMessage(msg_t* i_msg) +{ + // Verify userspace didn't give a non-kernel message type. + if (i_msg->type < MSG_FIRST_SYS_TYPE) + { + return -EINVAL; + } + + // Lock subsystem spinlock. + if (iv_lock) iv_lock->lock(); + + // Get <key, rc> from response. + MessageHandler_Pending::key_type key = + reinterpret_cast<MessageHandler_Pending::key_type>(i_msg->data[0]); + int msg_rc = static_cast<int>(i_msg->data[1]); + + // Handle all pending responses. + bool restored_task = false; + MessageHandler_Pending* mp = NULL; + while (NULL != (mp = iv_pending.find(key))) + { + // Call 'handle response'. + HandleResult rc = this->handleResponse( + static_cast<msg_sys_types_t>(i_msg->type), + key, mp->task, msg_rc); + + // Remove pending information from outstanding queue. + iv_pending.erase(mp); + delete mp; + + // If there is no associated task then there is nothing to do, find + // next pending response. + if (!mp->task) continue; + + // Handle action requested from 'handle response'. + if ((SUCCESS == rc) || (!msg_rc && UNHANDLED_RC == rc)) + { + // Successful response, resume task. + + if (!restored_task) // Immediately execute first deferred task. + { + restored_task = true; + TaskManager::setCurrentTask(mp->task); + } + else // Add other deferred tasks to scheduler ready queue. + { + mp->task->cpu->scheduler->addTask(mp->task); + } + } + else if (UNHANDLED_RC == rc) + { + // Unsuccessful, unhandled response. Kill task. + printk("Unhandled msg rc %d for key %p on task %d @ %p\n", + msg_rc, key, mp->task->tid, mp->task->context.nip); + Systemcalls::TaskEnd(mp->task); + } + else if (CONTINUE_DEFER == rc) + { + // Requested to continue deferring task. Do nothing. + } + else + { + // Logic bug (new HandleResult?). Shouldn't be here. + kassert(false); + } + } + + // Finished handling the response, unlock subsystem. + if (iv_lock) iv_lock->unlock(); + + return 0; +} + +MessageHandler::HandleResult MessageHandler::handleResponse( + msg_sys_types_t i_type, void* i_key, task_t* i_task, int i_rc) +{ + // Indicate nothing specific has been done for this response. Request + // default behavior of resume/kill task based on rc. + return UNHANDLED_RC; +} diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 51009195d..a71217bec 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -1,4 +1,5 @@ #include <assert.h> +#include <errno.h> #include <kernel/cpu.H> #include <kernel/cpumgr.H> #include <kernel/scheduler.H> @@ -12,6 +13,7 @@ #include <kernel/futexmgr.H> #include <kernel/cpuid.H> #include <kernel/misc.H> +#include <kernel/msghandler.H> extern "C" void kernel_execute_decrementer() @@ -110,18 +112,6 @@ void kernel_execute_system_call() } } -#define TASK_GETARGN(t, n) (t->context.gprs[n+4]) -#define TASK_GETARG0(t) (TASK_GETARGN(t,0)) -#define TASK_GETARG1(t) (TASK_GETARGN(t,1)) -#define TASK_GETARG2(t) (TASK_GETARGN(t,2)) -#define TASK_GETARG3(t) (TASK_GETARGN(t,3)) -#define TASK_GETARG4(t) (TASK_GETARGN(t,4)) -#define TASK_GETARG5(t) (TASK_GETARGN(t,5)) -#define TASK_GETARG6(t) (TASK_GETARGN(t,6)) -#define TASK_GETARG7(t) (TASK_GETARGN(t,7)) - -#define TASK_SETRTN(t, n) (t->context.gprs[3] = (n)) - namespace Systemcalls { void TaskYield(task_t* t) @@ -186,6 +176,12 @@ namespace Systemcalls msg_t* m = (msg_t*) TASK_GETARG1(t); m->__reserved__async = 0; // set to async msg. + if (m->type >= MSG_FIRST_SYS_TYPE) + { + TASK_SETRTN(t, -EINVAL); + return; + } + mq->lock.lock(); // Get waiting (server) task. @@ -213,11 +209,19 @@ namespace Systemcalls msg_t* m = (msg_t*) TASK_GETARG1(t); m->__reserved__async = 1; // set to sync msg. - mq->lock.lock(); + if (m->type >= MSG_FIRST_SYS_TYPE) + { + TASK_SETRTN(t, -EINVAL); + return; + } + + // Create pending response object. MessagePending* mp = new MessagePending(); mp->key = m; mp->task = t; + mq->lock.lock(); + // Get waiting (server) task. task_t* waiter = mq->waiting.remove(); if (NULL == waiter) // None found, add to 'messages' queue. @@ -249,20 +253,34 @@ namespace Systemcalls task_t* waiter = mp->task; mq->responses.erase(mp); + mq->lock.unlock(); delete mp; - waiter->cpu = t->cpu; - TaskManager::setCurrentTask(waiter); - TASK_SETRTN(waiter,0); - - TASK_SETRTN(t,0); - t->cpu->scheduler->addTask(t); + if (m->type >= MSG_FIRST_SYS_TYPE) + { + TASK_SETRTN(t, + ((MessageHandler*)waiter)->recvMessage(m)); + + if (TaskManager::getCurrentTask() != t) + { + t->cpu->scheduler->addTask(t); + } + } + else + { + waiter->cpu = t->cpu; + TaskManager::setCurrentTask(waiter); + TASK_SETRTN(waiter,0); + + TASK_SETRTN(t,0); + t->cpu->scheduler->addTask(t); + } } else { TASK_SETRTN(t, -1); + mq->lock.unlock(); } - mq->lock.unlock(); } void MsgWait(task_t* t) diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index 46fca9fef..74c3178d0 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -111,3 +111,8 @@ int VmmManager::mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size) return BaseSegment::mmAllocBlock(i_mq,i_va,i_size); } +Spinlock* VmmManager::getLock() +{ + return &Singleton<VmmManager>::instance().lock; +} + |