diff options
-rw-r--r-- | src/include/errno.h | 1 | ||||
-rw-r--r-- | src/include/kernel/syscalls.H | 2 | ||||
-rw-r--r-- | src/include/kernel/task.H | 39 | ||||
-rw-r--r-- | src/include/kernel/taskmgr.H | 133 | ||||
-rw-r--r-- | src/include/sys/syscall.h | 23 | ||||
-rw-r--r-- | src/include/sys/task.h | 82 | ||||
-rw-r--r-- | src/include/sys/vfs.h | 7 | ||||
-rw-r--r-- | src/include/util/locked/list.H | 53 | ||||
-rw-r--r-- | src/kernel/basesegment.C | 11 | ||||
-rw-r--r-- | src/kernel/cpumgr.C | 2 | ||||
-rw-r--r-- | src/kernel/exception.C | 15 | ||||
-rw-r--r-- | src/kernel/futexmgr.C | 4 | ||||
-rw-r--r-- | src/kernel/kernel.C | 16 | ||||
-rw-r--r-- | src/kernel/msghandler.C | 9 | ||||
-rw-r--r-- | src/kernel/scheduler.C | 4 | ||||
-rw-r--r-- | src/kernel/syscall.C | 74 | ||||
-rw-r--r-- | src/kernel/taskmgr.C | 216 | ||||
-rw-r--r-- | src/kernel/timemgr.C | 8 | ||||
-rw-r--r-- | src/lib/syscall_stub.S | 37 | ||||
-rw-r--r-- | src/lib/syscall_task.C | 53 | ||||
-rw-r--r-- | src/sys/vfs/vfs_main.C | 30 | ||||
-rw-r--r-- | src/usr/testcore/kernel/taskwaittest.H | 177 | ||||
-rw-r--r-- | src/usr/vfs/vfsrp.C | 8 |
23 files changed, 911 insertions, 93 deletions
diff --git a/src/include/errno.h b/src/include/errno.h index d4c296179..79eb30bbf 100644 --- a/src/include/errno.h +++ b/src/include/errno.h @@ -31,6 +31,7 @@ #define EFAULT 14 // Bad address #define EINVAL 22 // Invalid argument #define ENFILE 23 // Too many open files in system +#define EDEADLK 35 // Operation would cause deadlock. #define EWOULDBLOCK EAGAIN // operation would block diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H index 70dd436be..553fbf158 100644 --- a/src/include/kernel/syscalls.H +++ b/src/include/kernel/syscalls.H @@ -49,6 +49,8 @@ namespace Systemcalls TASK_END = 2, /** task_affinity_migrate_to_master() */ TASK_MIGRATE_TO_MASTER = 3, + /** task_wait() / task_wait_tid() */ + TASK_WAIT, /** msgq_create() */ MSGQ_CREATE, diff --git a/src/include/kernel/task.H b/src/include/kernel/task.H index cab925977..9ff0401ba 100644 --- a/src/include/kernel/task.H +++ b/src/include/kernel/task.H @@ -56,6 +56,30 @@ struct context_fp_t uint64_t fpscr; }; +enum task_states +{ + /** Task is currently running. */ + TASK_STATE_RUNNING = 'R', + /** Task is on scheduler queue ready to run. */ + TASK_STATE_READY = 'r', + /** Task has ended or crashed. */ + TASK_STATE_ENDED = 'E', + + /** Task is blocked on a futex. */ + TASK_STATE_BLOCK_FUTEX = 'f', + /** Task is blocked on a message queue. */ + TASK_STATE_BLOCK_MSG = 'M', + /** Task is defered due to a kernel->userspace request. */ + TASK_STATE_BLOCK_USRSPACE = 'u', + /** Task is blocked sleeping. */ + TASK_STATE_BLOCK_SLEEP = 's', + /** Task is blocked on join. */ + TASK_STATE_BLOCK_JOIN = 'j', +}; + + // Forward declaration. +struct task_tracking_t; + /** @struct task_t * @brief The kernel-level task structure. */ @@ -76,13 +100,24 @@ struct task_t * as been requested, so pinning can be used recursively. */ uint64_t affinity_pinned; + /** State of task */ + task_states state; + /** Extra info about the state. + * This is used when the task is blocked to give a pointer to the + * object the task is blocked on. */ + void* state_info; + + /** Pointer to tracking tree for joining, parent info, etc. */ + task_tracking_t* tracker; + + /** Detached state of the task. */ + bool detached; + // Pointers for queue containers. task_t* prev; task_t* next; }; -enum { TASK_DEFAULT_STACK_SIZE = 4 }; - // Macros for manipulating task's saved contexts. #define TASK_GETARGN(t, n) (t->context.gprs[n+4]) #define TASK_GETARG0(t) (TASK_GETARGN(t,0)) diff --git a/src/include/kernel/taskmgr.H b/src/include/kernel/taskmgr.H index db267523b..8f1deb264 100644 --- a/src/include/kernel/taskmgr.H +++ b/src/include/kernel/taskmgr.H @@ -26,31 +26,156 @@ #include <kernel/types.h> #include <util/lockfree/counter.H> #include <kernel/vmmmgr.H> +#include <sys/task.h> +#include <util/locked/list.H> +#include <kernel/spinlock.H> + // Forward declaration. +struct task_tracking_t; +struct task_wait_t; + /** Typedef for a list of task_tracking_t's. */ +typedef Util::Locked::List<task_tracking_t, tid_t> task_tracking_list_t; + +/** @struct task_tracking_t + * Stores the parent/child relationships and join information for tasks. + * + * The task_tracking_t's become a tree so that we can create a ps-like + * debug output and so that a task can do a wait() on all of its children. + */ +struct task_tracking_t +{ + typedef tid_t key_type; + + /** previous pointer for list. */ + task_tracking_t* prev; + /** next pointer for list. */ + task_tracking_t* next; + + /** pointer to parent's tracking info. */ + task_tracking_t* parent; + /** list of all children. */ + task_tracking_list_t children; + + /** tid as a key for list. */ + key_type key; + /** Pointer to task structure if it is still running. */ + task_t* task; + + /** Crash/clean-exit status if task has ended. */ + int status; + /** Return-value to task_end2() if task has ended. */ + void* retval; + /** Task-wait state object. */ + task_wait_t* wait_info; + + /** Record the original entry point of the thread for debug purpose. */ + void* entry_point; +}; + +/** @struct task_wait_t + * Stores the parameters for the task_wait syscall for a task which is + * deferred due to the syscall. + */ +struct task_wait_t +{ + /** Tid waiting on (or -1 for any). */ + int64_t tid; + /** Address to return the child status. */ + int* status; + /** Address to return the child return-value. */ + void** retval; +}; + +/** @class TaskManager + * Kernel management class to deal with task creation / exit. + */ class TaskManager { public: + /** @brief Returns a pointer to the currently running task on this + * CPU. + * + * @retval NULL - Kernel has never started running any tasks. + * @retval non-NULL - The task most recently running and/or will be + * running when kernel returns to user-space. + */ static task_t* getCurrentTask(); + + /** @brief Sets the current task pointer in this CPU object. + * + * @param[in] t - The task to assign on this CPU. + */ static void setCurrentTask(task_t* t); + /** Typedef for task entry points. */ typedef void(*task_fn_t)(void*); - static task_t* createTask(task_fn_t, void*); + + /** @brief Create a new task object. + * + * @param[in] t - The entry point to start the task at. + * @param[in] p - An argument pointer to pass to the task. + */ + static task_t* createTask(task_fn_t t, void* p); + + /** @brief End / destroy a task object. + * + * @param[in] t - The task to end. + * @param[in] retval - Return value from the task. + * @param[in] status - TASK_STATUS_* enumeration of how the task ended. + */ + static void endTask(task_t* t, void* retval, int status); + + /** @brief Perform the 'task_wait' for a task. + * + * Returns the child information if the requested child has already + * ended or defers the task if the child requested is still running. + * + * @param[in] t - The task requesting the wait. + * @param[in] tid - The child task requested to wait on or -1 for any. + * @param[out] status - The address to write the child status. + * @param[out] retval - The address to write the child retval. + */ + static void waitTask(task_t* t, int64_t tid, + int* status, void** retval); friend class CpuManager; + protected: TaskManager(); ~TaskManager() {}; + /** Create a new task where the entry point is idleTaskLoop. */ static task_t* createIdleTask(); private: - tid_t getNextTid() - { return iv_nextTid.next(); }; - Util::Lockfree::Counter<tid_t> iv_nextTid; + /** Get the next TID in the task sequence. */ + tid_t getNextTid() { return iv_nextTid.next(); }; + /** Run the idle task loop */ static void idleTaskLoop(void*); + + // Internal implementations of non-static / non-_ functions. task_t* _createIdleTask(); task_t* _createTask(task_fn_t, void*, bool); + void _endTask(task_t*, void*, int); + void _waitTask(task_t*, int64_t, int*, void**); + + /** Remove a tracker from the tracker-tree and delete it. + * + * @param[in] t - The tracker to remove. + * @note Spinlock-locking of the tracker-tree is the + * responsibility of the caller. + */ + void removeTracker(task_tracking_t* t); + + /** Atomic monotonically increasing counter to use for TIDs. */ + Util::Lockfree::Counter<tid_t> iv_nextTid; + + /** Task-tracking tree spinlock. */ + Spinlock iv_spinlock; + /** Task-tracking tree. */ + task_tracking_list_t iv_taskList; + }; #endif diff --git a/src/include/sys/syscall.h b/src/include/sys/syscall.h index f0972e949..b3d435edf 100644 --- a/src/include/sys/syscall.h +++ b/src/include/sys/syscall.h @@ -23,13 +23,21 @@ #ifndef __SYS_SYSCALL_H #define __SYS_SYSCALL_H +/** @file syscall.h + * @brief Defines syscall wrapper functions to get C-caller to put syscall + * parameters in the correct spots for ABI so kernel can pull them + * from the right position in the task structs. + */ + #ifdef __cplusplus -extern "C" +extern "C" { #endif #include <stdint.h> +#include <builtins.h> +// Normal system calls. void* _syscall0(uint64_t); void* _syscall1(uint64_t, void*); void* _syscall2(uint64_t, void*, void*); @@ -39,6 +47,19 @@ void* _syscall5(uint64_t, void*, void*, void*, void*, void*); void* _syscall6(uint64_t, void*, void*, void*, void*, void*, void*); void* _syscall7(uint64_t, void*, void*, void*, void*, void*, void*, void*); +// System calls which never return. Marked NO_RETURN so the compiler +// can make additional optimizations. +void* _syscall0_nr(uint64_t) NO_RETURN; +void* _syscall1_nr(uint64_t, void*) NO_RETURN; +void* _syscall2_nr(uint64_t, void*, void*) NO_RETURN; +void* _syscall3_nr(uint64_t, void*, void*, void*) NO_RETURN; +void* _syscall4_nr(uint64_t, void*, void*, void*, void*) NO_RETURN; +void* _syscall5_nr(uint64_t, void*, void*, void*, void*, void*) NO_RETURN; +void* _syscall6_nr(uint64_t, void*, void*, void*, void*, void*, void*) + NO_RETURN; +void* _syscall7_nr(uint64_t, void*, void*, void*, void*, void*, void*, void*) + NO_RETURN; + #ifdef __cplusplus } #include <kernel/syscalls.H> diff --git a/src/include/sys/task.h b/src/include/sys/task.h index 9f43996c4..0627784f1 100644 --- a/src/include/sys/task.h +++ b/src/include/sys/task.h @@ -27,6 +27,7 @@ #define __SYS_TASK_H #include <stdint.h> +#include <builtins.h> #include <kernel/types.h> #ifdef __cplusplus @@ -64,7 +65,17 @@ tid_t task_create(void(*start_routine)(void*), void* arg); * function. Therefore, returning from the entry point function will * also cause the task to end cleanly using this function. */ -void task_end(); +void task_end() NO_RETURN; + +/** @fn task_end2 + * @brief End the calling task with a return value. + * + * See POSIX pthread_exit. + * + * @param[in] retval - A pointer to return to the task performing task_join / + * task_wait on this task. + */ +void task_end2(void* retval) NO_RETURN; /** @fn task_gettid * @brief Get task ID of calling task. @@ -130,6 +141,75 @@ void task_affinity_unpin(); */ void task_affinity_migrate_to_master(); +/** @enum task_status + * @brief Status of how a task exited. + */ +enum task_status +{ + /** Task called task_end cleanly. */ + TASK_STATUS_EXITED_CLEAN, + /** Task crashed. Ended by the kernel due to error. */ + TASK_STATUS_CRASHED, +}; + +/** @fn task_detach + * @brief Sets the calling task to the 'detached' state, meaning no parent + * may task_wait_tid on it. + */ +void task_detach(); + +/** @fn task_wait_tid + * @brief Block calling task until a requested child process exits. + * + * See also: POSIX 'waitid' / Linux 'waitpid'. + * + * @param[in] tid - Task to wait for completion. + * + * @param[out] status - Optional address to write child status. + * @param[out] retval - Optional address to write return-value. + * + * Status values come from task_status enumeration. + * Retval values come from child's 'task_end2' parameter. + * + * @note All non-detached tasks must be waited on by their parent to ensure + * there are not kernel memory-leaks. + * + * @note If a parent task ends prior to waiting on its children, the children + * become parented by their grand-parents, who must do the wait. + * + * @return tid of child waited on or negative number on error. + * + * @retval EDEADLK - Performing this wait would deadlock the caller such as + * when it has no children. + * @retval EFAULT - Bad memory address given for status or retval parameter. + */ +tid_t task_wait_tid(tid_t tid, int* status, void** retval); + +/** @fn task_wait + * @brief Block calling task until any child process exits. + * + * See also: Linux 'wait'. + * + * @param[out] status - Optional address to write child status. + * @param[out] retval - Optional address to write return-value. + * + * Status values come from task_status enumeration. + * Retval values come from child's 'task_end2' parameter. + * + * @note All non-detached tasks must be waited on by their parent to ensure + * there are not kernel memory-leaks. + * + * @note If a parent task ends prior to waiting on its children, the children + * become parented by their grand-parents, who must do the wait. + * + * @return tid of child waited on or negative number on error. + * + * @retval EDEADLK - Performing this wait would deadlock the caller such as + * when it has no children. + * @retval EFAULT - Bad memory address given for status or retval parameter. + */ +tid_t task_wait(int* status, void** retval); + #ifdef __cplusplus } #endif diff --git a/src/include/sys/vfs.h b/src/include/sys/vfs.h index 6ab24c9b8..d427c0abb 100644 --- a/src/include/sys/vfs.h +++ b/src/include/sys/vfs.h @@ -102,14 +102,13 @@ extern uint64_t VFS_LAST_ADDRESS; VfsSystemModule * vfs_find_module(VfsSystemModule * i_table, const char * i_name); /** - * Call the module start routine + * Get the module's start routine * @param[in] i_module VfsSystemModule data for the module - * @param[in] i_param parameter to pass to task_create() for this module - * @return tid_t of started task or negative value on error. + * @return Function pointer of module's start or negative value on error. * @retval -ENOENT if i_module is NULL * @retval -ENOEXEC if there is no start() */ -tid_t vfs_exec(VfsSystemModule * i_module, void* i_param); +void* vfs_start_entrypoint(VfsSystemModule * i_module); /** * Change permissions on the virtual pages associated with the module diff --git a/src/include/util/locked/list.H b/src/include/util/locked/list.H index 5e06c5e8e..dc19ff193 100644 --- a/src/include/util/locked/list.H +++ b/src/include/util/locked/list.H @@ -46,6 +46,9 @@ namespace Util _T* find(_K& key) const; + bool empty(); + _T* begin(); + protected: _T* head; _T* tail; @@ -56,6 +59,31 @@ namespace Util void __unlock() const; }; + // SFINAE template to ensure compile fails if functions which are not + // SMP-safe are used on a 'locked' instance. + template<bool locked> + class __verify_list_is_smp_safe + { + public: + __verify_list_is_smp_safe() + { + class __util_locked_list_is_not_smp_safe; + __util_locked_list_is_not_smp_safe(); + } + }; + + // SFINAE template implementation to allow certain functions when the + // instance is not 'locked', assuming that caller is ensuring safety + // in some other way. + template<> + class __verify_list_is_smp_safe<false> + { + public: + __verify_list_is_smp_safe() + { + } + }; + template <typename _T, typename _K, bool locked, typename _S> _T* List<_T,_K,locked,_S>::remove() { @@ -169,6 +197,31 @@ namespace Util return node; } + + template <typename _T, typename _K, bool locked, typename _S> + bool List<_T, _K,locked,_S>::empty() + { + bool isEmpty = false; + + __lock(); + isEmpty = (head == NULL); + __unlock(); + + return isEmpty; + } + + template <typename _T, typename _K, bool locked, typename _S> + _T* List<_T, _K,locked,_S>::begin() + { + // Entirely not SMP-safe to return a pointer to a node if + // we are a locking instance. If we aren't locking we + // have to assume that the caller is ensuring SMP-safety + // globally in some other way. Use SFINAE technique to + // ensure begin() fails on locked lists. + __verify_list_is_smp_safe<locked>(); + return head; + } + } } 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); } diff --git a/src/lib/syscall_stub.S b/src/lib/syscall_stub.S index aca533338..6c839346c 100644 --- a/src/lib/syscall_stub.S +++ b/src/lib/syscall_stub.S @@ -1,24 +1,24 @@ # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. -# +# # $Source: src/lib/syscall_stub.S $ -# +# # IBM CONFIDENTIAL -# +# # COPYRIGHT International Business Machines Corp. 2010 - 2011 -# +# # p1 -# +# # Object Code Only (OCO) source materials # Licensed Internal Code Source Materials # IBM HostBoot Licensed Internal Code -# +# # The source code for this program is not published or other- # wise divested of its trade secrets, irrespective of what has # been deposited with the U.S. Copyright Office. -# +# # Origin: 30 -# +# # IBM_PROLOG_END .section .text @@ -41,3 +41,24 @@ _syscall6: _syscall7: sc blr + +.global _syscall0_nr +.global _syscall1_nr +.global _syscall2_nr +.global _syscall3_nr +.global _syscall4_nr +.global _syscall5_nr +.global _syscall6_nr +.global _syscall7_nr + +_syscall0_nr: +_syscall1_nr: +_syscall2_nr: +_syscall3_nr: +_syscall4_nr: +_syscall5_nr: +_syscall6_nr: +_syscall7_nr: + sc +1: + b 1b diff --git a/src/lib/syscall_task.C b/src/lib/syscall_task.C index 38b8adee4..a00b779f7 100644 --- a/src/lib/syscall_task.C +++ b/src/lib/syscall_task.C @@ -49,8 +49,12 @@ tid_t task_create(void(*fn)(void*), void* ptr) void task_end() { - _syscall0(TASK_END); // no return. - return; + _syscall1_nr(TASK_END, NULL); // no return. +} + +void task_end2(void* retval) +{ + _syscall1_nr(TASK_END, retval); // no return. } tid_t task_gettid() @@ -69,8 +73,8 @@ cpuid_t task_getcpuid() tid_t task_exec(const char* file, void* ptr) { - // The VFS process is responsible for finding the module and creating the - // new process. So, we send a message over to that process. + // The VFS process is responsible for finding the module and entry point + // address, so we send a message over to that process. tid_t child = 0; int rc = 0; @@ -80,7 +84,6 @@ tid_t task_exec(const char* file, void* ptr) msg_t* msg = msg_allocate(); msg->type = VFS_MSG_EXEC; msg->data[0] = (uint64_t) file; - msg->data[1] = (uint64_t) ptr; if (vfsQ) { msg_sendrecv(vfsQ, msg); @@ -93,8 +96,17 @@ tid_t task_exec(const char* file, void* ptr) if (0 == rc) { - // Get child ID from message data 0. - child = (tid_t) msg->data[0]; + // Get fn ptr or error from message data 0. + int64_t value = *reinterpret_cast<int64_t*>(&msg->data[0]); + if (value < 0) + { + child = value; + } + else + { + child = task_create(reinterpret_cast<void(*)(void*)>(msg->data[0]), + ptr); + } } else { @@ -129,3 +141,30 @@ void task_affinity_migrate_to_master() { _syscall0(TASK_MIGRATE_TO_MASTER); } + +void task_detach() +{ + // Get task structure. + register task_t* task; + asm volatile("mr %0, 13" : "=r"(task)); + + task->detached = true; + // This does not need any sync instruction because the setting is + // only used by the kernel and it requires a context-sync operation + // to enter kernel mode. +} + +tid_t task_wait_tid(tid_t tid, int* status, void** retval) +{ + return static_cast<tid_t>( + reinterpret_cast<uint64_t>( + _syscall3(TASK_WAIT,(void*)tid,status,retval))); +} + +tid_t task_wait(int* status, void** retval) +{ + return static_cast<tid_t>( + reinterpret_cast<uint64_t>( + _syscall3(TASK_WAIT,(void*)-1,status,retval))); +} + diff --git a/src/sys/vfs/vfs_main.C b/src/sys/vfs/vfs_main.C index 06a7f9d07..17de12295 100644 --- a/src/sys/vfs/vfs_main.C +++ b/src/sys/vfs/vfs_main.C @@ -39,16 +39,6 @@ const char* VFS_ROOT_MSG_VFS = "/msg/vfs"; void vfs_module_init(); -/** - * Call the module start routine - * @param[in] i_module VfsSystemModule data for the module - * @param[in] i_param parameter to pass to task_create() for this module - * @return tid_t of started task or negative value on error. - * @retval -ENOENT if i_module is NULL - * @retval -ENOEXEC if there is no start() - */ -tid_t vfs_exec(VfsSystemModule * i_module, void* i_param); - struct VfsPath { char key[64]; @@ -123,13 +113,14 @@ void vfs_main(void* i_barrier) vfs_find_module(VFS_MODULES, (const char *) msg->data[0]); - tid_t child = vfs_exec(module,(void*) msg->data[1]); + void* fnptr = vfs_start_entrypoint(module); // child == -ENOENT means module not found in base image // so send a message to VFS_MSG queue to look in the // extended image VFS_MSG queue will handle the // msg_respond() - if( child == (tid_t)-ENOENT ) // forward msg to usr vfs + if( fnptr == reinterpret_cast<void*>(-ENOENT) ) + // forward msg to usr vfs { VfsEntry::key_type k; strcpy(k.key, VFS_ROOT_MSG_VFS); @@ -144,13 +135,13 @@ void vfs_main(void* i_barrier) } else // Cant find VFS_MSG queue - not started yet { - msg->data[0] = child; + msg->data[0] = (uint64_t) fnptr; msg_respond(vfsMsgQ, msg); } } else // send back child (or errno) { - msg->data[0] = child; + msg->data[0] = (uint64_t) fnptr; msg_respond(vfsMsgQ, msg); } } @@ -165,21 +156,22 @@ void vfs_main(void* i_barrier) // ---------------------------------------------------------------------------- -tid_t vfs_exec(VfsSystemModule * i_module, void* i_param) +void* vfs_start_entrypoint(VfsSystemModule * i_module) { - tid_t child = -ENOENT; + void* ptr = reinterpret_cast<void*>(-ENOENT); if(i_module != NULL) { if (i_module->start == NULL) { - child = -ENOEXEC; // module has no start() routine + // module has no start() routine + ptr = reinterpret_cast<void*>(-ENOEXEC); } else { - child = task_create(i_module->start, i_param); + ptr = reinterpret_cast<void*>(i_module->start); } } - return child; + return ptr; } diff --git a/src/usr/testcore/kernel/taskwaittest.H b/src/usr/testcore/kernel/taskwaittest.H new file mode 100644 index 000000000..00ec0990f --- /dev/null +++ b/src/usr/testcore/kernel/taskwaittest.H @@ -0,0 +1,177 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/testcore/kernel/tasktest.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2011 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +/** @file tasktest.H + * @brief Test cases for task interfaces. + */ + +#include <cxxtest/TestSuite.H> +#include <sys/task.h> +#include <sys/time.h> +#include <errno.h> +#include <kernel/console.H> +#include <kernel/timemgr.H> + +#define NS_PER_SEC (1000000ull) +#define TEN_CTX_SWITCHES ((NS_PER_SEC/TimeManager::TIMESLICE_PER_SEC)*10) + +class TaskWaitTest : public CxxTest::TestSuite +{ + public: + + void testWaitAfterChildExit() + { + int status = 0x1234; + tid_t child = task_create(&WaitSomeTime, NULL); + WaitSomeLongerTime(NULL); + + // Join with that child task to clean it up. + if (child != task_wait_tid(child, &status, NULL)) + { + TS_FAIL("Failed to join with test-case child."); + } + if (status != TASK_STATUS_EXITED_CLEAN) + { + TS_FAIL("Task status is incorrect after wait."); + } + } + + void testWaitBeforeChildExit() + { + tid_t child = task_create(&WaitSomeLongerTime, NULL); + WaitSomeTime(NULL); + + // Join with that child task to clean it up. + if (child != task_wait_tid(child, NULL, NULL)) + { + TS_FAIL("Failed to join with test-case child."); + } + } + + void testWaitOnTwoChildren() + { + tid_t child[2] = { task_create(&WaitSomeTime, NULL), + task_create(&WaitSomeTime, NULL) }; + + tid_t completed = 0; + + completed = task_wait(NULL, NULL); + if ((completed != child[0]) && (completed != child[1])) + { + TS_FAIL("Different child returned than one waited on."); + } + + completed = task_wait(NULL, NULL); + if ((completed != child[0]) && (completed != child[1])) + { + TS_FAIL("Different child returned than one waited on."); + } + } + + void testWaitOnGrandchild() + { + tid_t child = task_create(&TaskWithChild, NULL); + void* retval; + + task_wait_tid(child, NULL, &retval); + + tid_t grandchild = static_cast<tid_t>( + reinterpret_cast<uint64_t>(retval)); + + if (grandchild != task_wait_tid(grandchild, NULL, NULL)) + { + TS_FAIL("Grand-child task was not joined with."); + } + } + + void testWaitOnCrash() + { + int status = 1234; + tid_t child = task_create(&TaskThatCrashes, NULL); + + task_wait_tid(child, &status, NULL); + + if (status != TASK_STATUS_CRASHED) + { + TS_FAIL("Task wait status is incorrect."); + } + } + + void testWaitDeadlock() + { + // Check for any thread when we don't have a child. + if (((tid_t)-EDEADLK) != task_wait(NULL, NULL)) + { + TS_FAIL("Deadlock condition not detected."); + } + + // Check for waiting on the wrong task. + tid_t child = task_create(&WaitSomeTime, NULL); + if (((tid_t)-EDEADLK) != task_wait_tid(0, NULL, NULL)) + { + TS_FAIL("Deadlock condition not detected."); + } + + // Join with that child task to clean it up. + if (child != task_wait_tid(child, NULL, NULL)) + { + TS_FAIL("Failed to join with test-case child."); + } + } + + void testWaitAddrFault() + { + if (((tid_t)-EFAULT) != task_wait((int*)4, NULL)) + { + TS_FAIL("Bad address on status not caught."); + } + + if (((tid_t)-EFAULT) != task_wait(NULL, (void**)4)) + { + TS_FAIL("Bad address on ret-val not caught."); + } + } + + static void WaitSomeTime(void* retval) + { + nanosleep(0,TEN_CTX_SWITCHES); + if (retval) task_end2(retval); + } + + static void WaitSomeLongerTime(void* retval) + { + nanosleep(0, 2*TEN_CTX_SWITCHES); + if (retval) task_end2(retval); + } + + static void TaskWithChild(void* unused) + { + tid_t child = task_create(&WaitSomeTime, NULL); + task_end2(reinterpret_cast<void*>(child)); + } + + static void TaskThatCrashes(void* unused) + { + printk("Test case: Expect to see uncaught exception!"); + *(int64_t*)(0) = 0xDEADC0DE; + } +}; diff --git a/src/usr/vfs/vfsrp.C b/src/usr/vfs/vfsrp.C index 266cdecba..9c178e92a 100644 --- a/src/usr/vfs/vfsrp.C +++ b/src/usr/vfs/vfsrp.C @@ -314,8 +314,8 @@ void VfsRp::_load_unload(msg_t * i_msg) { // Module does not exist in extended image. // If it exists then it is in the base image and it's already - // initialized, however, we still should not be here, so put out a - // trace msg; + // initialized, however, we still should not be here, so put out a + // trace msg; // If it does not exist anywhere then also create an error log TRACFCOMP(g_trac_vfs, ERR_MRK"load Module not found: %s", (const char *) i_msg->data[0]); @@ -362,11 +362,9 @@ void VfsRp::_exec(msg_t * i_msg) VFS_EXTENDED_MODULE_TABLE_OFFSET), (const char*) msg1->data[0]); - tid_t child = vfs_exec(module, (void*) msg1->data[1]); - msg_q_t vfsRmsgQ = (msg_q_t) i_msg->data[1]; - msg1->data[0] = child; + msg1->data[0] = (uint64_t) vfs_start_entrypoint(module); msg_respond(vfsRmsgQ,msg1); msg_free(i_msg); |