diff options
Diffstat (limited to 'Source/Kernel/TaskManager')
-rw-r--r-- | Source/Kernel/TaskManager/Mutex.class.cpp | 28 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Mutex.class.h | 21 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Process.class.cpp | 68 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Process.class.h | 30 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Task.ns.cpp | 8 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Task.ns.h | 2 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Task.wtf.asm | 9 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Thread.class.cpp | 109 | ||||
-rw-r--r-- | Source/Kernel/TaskManager/Thread.class.h | 14 |
9 files changed, 203 insertions, 86 deletions
diff --git a/Source/Kernel/TaskManager/Mutex.class.cpp b/Source/Kernel/TaskManager/Mutex.class.cpp deleted file mode 100644 index 8ba274f..0000000 --- a/Source/Kernel/TaskManager/Mutex.class.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "Mutex.class.h" -#include <TaskManager/Task.ns.h> - -extern "C" u32int atomic_exchange(u32int* ptr, u32int newval); - -Mutex::Mutex(u32int locked) { - m_locked = locked; -} - -bool Mutex::lock() { - if (atomic_exchange(&m_locked, MUTEX_TRUE) == MUTEX_TRUE) return false; //The lock was already locked - return true; -} - -void Mutex::waitLock() { - while (atomic_exchange(&m_locked, MUTEX_TRUE) == MUTEX_TRUE) { - if (Task::currThread() != 0) Task::currThread()->sleep(10); //Wait 10ms - else return; - } -} - -void Mutex::unlock() { - m_locked = MUTEX_FALSE; -} - -bool Mutex::locked() { - return m_locked; -} diff --git a/Source/Kernel/TaskManager/Mutex.class.h b/Source/Kernel/TaskManager/Mutex.class.h deleted file mode 100644 index 5545559..0000000 --- a/Source/Kernel/TaskManager/Mutex.class.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef DEF_MUTEX_CLASS_H -#define DEF_MUTEX_CLASS_H - -#include <Core/common.wtf.h> - -#define MUTEX_FALSE 0 -#define MUTEX_TRUE 1 - -class Mutex { - private: - u32int m_locked; - - public: - Mutex(u32int locked = MUTEX_FALSE); - bool lock(); //Locks the mutex if it is not locked. Returns true if mutex could be locked, false if already locked - void waitLock(); //Locks the mutex, waiting for it to be unlocked before if necessary - void unlock(); - bool locked(); -}; - -#endif diff --git a/Source/Kernel/TaskManager/Process.class.cpp b/Source/Kernel/TaskManager/Process.class.cpp index cf8f00a..a2bbfb4 100644 --- a/Source/Kernel/TaskManager/Process.class.cpp +++ b/Source/Kernel/TaskManager/Process.class.cpp @@ -2,12 +2,26 @@ #include <TaskManager/Task.ns.h> #include <MemoryManager/PhysMem.ns.h> #include <VFS/File.class.h> +#include <Linker/Binary.proto.h> +#include <Process.iface.h> namespace Mem { extern Heap kheap; } -Process::Process() { //Private constructor, does nothing +call_t Process::m_callTable[] = { + CALL0(PRIF_EXIT, &Process::exitSC), + CALL1(PRIF_ALLOCPAGE, &Process::allocPageSC), + CALL1(PRIF_FREEPAGE, &Process::freePageSC), + CALL0(0, 0) +}; + +u32int Process::scall(u8int wat, u32int a, u32int b, u32int c, u32int d) { + if (wat == PRIF_SGETCPR) return Task::currProcess()->resId(); + return (u32int) - 1; +} + +Process::Process() : Ressource(PRIF_OBJTYPE, m_callTable) { //Private constructor, does nothing } Process* Process::createKernel(String cmdline, VirtualTerminal *vt) { @@ -35,13 +49,31 @@ Process* Process::createKernel(String cmdline, VirtualTerminal *vt) { return p; } -Process::Process(String cmdline, u32int uid) { +Process* Process::run(String filename, FSNode* cwd, u32int uid) { + File file(filename, FM_READ, cwd); + if (!file.valid()) return 0; + Binary* b = Binary::load(file); + if (b == 0) return 0; + Process* p = new Process(filename, uid); + thread_entry_t e = b->toProcess(p); + delete b; + if (e != 0) { + new Thread(p, e, 0); + return p; + } else { + delete p; + return 0; + } +} + +Process::Process(String cmdline, u32int uid) : Ressource(PRIF_OBJTYPE, m_callTable) { m_pid = Task::nextPid(); m_cmdline = cmdline; m_retval = 0; - m_state = P_RUNNING; + m_state = P_STARTING; m_uid = uid; m_vt = Task::currProcess()->getVirtualTerminal(); + m_fileDescriptors = 0; //Create page directory and user heap m_pagedir = new PageDirectory(kernelPageDirectory); m_pagedir->switchTo(); @@ -56,6 +88,10 @@ Process::~Process() { delete m_userHeap; } +void Process::start() { + if (m_state == P_STARTING) m_state = P_RUNNING; +} + void Process::exit() { for (u32int i = 0; i < m_threads.size(); i++) { delete m_threads[i]; @@ -65,7 +101,7 @@ void Process::exit() { iter->v()->close(false); delete iter->v(); } - delete m_fileDescriptors; //Will recursively delete whole list + if (m_fileDescriptors != 0) delete m_fileDescriptors; //Will recursively delete whole list m_state = P_FINISHED; } @@ -76,7 +112,7 @@ void Process::registerThread(Thread* t) { void Process::threadFinishes(Thread* thread, u32int retval) { // If it is the main thread of the process, or if it pagefaulted - if (thread == m_threads[0] or retval == E_PAGEFAULT) { + if (thread == m_threads[0] or retval == E_PAGEFAULT or retval == E_EXIT) { exit(); } else { //Simply unregister thread @@ -110,3 +146,25 @@ VirtualTerminal* Process::getVirtualTerminal() { void Process::setVirtualTerminal(VirtualTerminal* vt) { m_vt = vt; } + +u32int Process::exitSC() { + if (Task::currProcess() != this) return 1; + Task::currentThreadExits(E_EXIT); + return 0; +} + +u32int Process::allocPageSC(u32int pos) { + if (Task::currProcess() != this) return 1; + if ((pos & 0x00000FFF) != 0) pos = (pos & 0xFFFFF000) + 0x1000; + if (pos >= 0xC0000000) return 1; + m_pagedir->allocFrame(pos, true, true); + return 0; +} + +u32int Process::freePageSC(u32int pos) { + if (Task::currProcess() != this) return 1; + if ((pos & 0x00000FFF) != 0) pos = (pos & 0xFFFFF000) + 0x1000; + if (pos >= 0xC0000000) return 1; + m_pagedir->freeFrame(pos); + return 0; +} diff --git a/Source/Kernel/TaskManager/Process.class.h b/Source/Kernel/TaskManager/Process.class.h index ac9614e..89efd0c 100644 --- a/Source/Kernel/TaskManager/Process.class.h +++ b/Source/Kernel/TaskManager/Process.class.h @@ -1,19 +1,23 @@ #ifndef DEF_PROCESS_CLASS_H #define DEF_PROCESS_CLASS_H -#include <Library/String.class.h> -#include <Library/Vector.class.h> -#include <Library/SimpleList.class.h> +#include <String.class.h> +#include <Vector.class.h> +#include <SimpleList.class.h> #include <MemoryManager/PageDirectory.class.h> -#include <MemoryManager/Heap.class.h> +#include <Heap.class.h> #include <VTManager/VirtualTerminal.proto.h> +#include <VFS/File.class.h> + +#include <SyscallManager/Ressource.class.h> #define P_ZOMBIE 0 #define P_RUNNING 1 -#define P_FINISHED 2 +#define P_STARTING 2 +#define P_FINISHED 3 #define E_PAGEFAULT 0x0FFFFF00 -#define E_ABORTED 0x0FFFFF01 +#define E_EXIT 0x0FFFFF01 #define E_UNHANDLED_EXCEPTION 0x0FFFFF02 #define STACKSIZE 4096 //Could change @@ -24,7 +28,7 @@ class Thread; class File; -class Process { +class Process : public Ressource { friend class Thread; private: @@ -42,14 +46,23 @@ class Process { Vector<Thread*> m_threads; SimpleList<File*> *m_fileDescriptors; + + //System calls + static call_t m_callTable[]; + u32int exitSC(); + u32int allocPageSC(u32int); public: + static u32int scall(u8int, u32int, u32int, u32int, u32int); + static Process* createKernel(String cmdline, VirtualTerminal *vt); //Also creates a Thread for what's curently happening + static Process* run(String filename, FSNode* cwd, u32int uid); Process(String cmdline, u32int uid); ~Process(); Heap& heap() { return *m_userHeap; } + void start(); //Starts thread execution - sets m_state to P_RUNNING if == P_STARTING void exit(); //Exits properly process by killing all threads and deleting file descriptors void registerThread(Thread* t); //Called when a thread starts void threadFinishes(Thread* thread, u32int retval); //Called when a thread finishes @@ -61,7 +74,8 @@ class Process { VirtualTerminal* getVirtualTerminal(); void setVirtualTerminal(VirtualTerminal* vt); - + u32int getState() { return m_state; } + u32int freePageSC(u32int); }; #endif diff --git a/Source/Kernel/TaskManager/Task.ns.cpp b/Source/Kernel/TaskManager/Task.ns.cpp index a34f14f..aef07f3 100644 --- a/Source/Kernel/TaskManager/Task.ns.cpp +++ b/Source/Kernel/TaskManager/Task.ns.cpp @@ -1,5 +1,4 @@ #include "Task.ns.h" -#include <Library/Vector.class.h> #include <MemoryManager/PhysMem.ns.h> #define INVALID_TASK_MAGIC 0xBEEFFEED @@ -94,8 +93,11 @@ void doSwitch() { eip = t->getEip(); cr3 = currentProcess->getPagedir()->physicalAddr; + asm volatile("cli"); + + t->setKernelStack(); + asm volatile(" \ - cli; \ mov %0, %%ebp; \ mov %1, %%esp; \ mov %2, %%ecx; \ @@ -138,6 +140,7 @@ void currThreadExitProceed(u32int errcode) { } void currentThreadExits(u32int errcode) { //Call currThreadExitProceed with a working stack (we use temp_stack) + asm volatile("cli"); u32int* stack = &temp_stack[TEMP_STACK_SIZE]; stack--; *stack = errcode; @@ -146,7 +149,6 @@ void currentThreadExits(u32int errcode) { //Call currThreadExitProceed with a wo u32int esp = (u32int)(stack), ebp = (u32int)(stack + 1), eip = (u32int)currThreadExitProceed; asm volatile(" \ - cli; \ mov %0, %%ebp; \ mov %1, %%esp; \ mov %2, %%ecx; \ diff --git a/Source/Kernel/TaskManager/Task.ns.h b/Source/Kernel/TaskManager/Task.ns.h index c7c3d23..056e4c0 100644 --- a/Source/Kernel/TaskManager/Task.ns.h +++ b/Source/Kernel/TaskManager/Task.ns.h @@ -3,7 +3,7 @@ #include <TaskManager/Thread.class.h> #include <VTManager/VirtualTerminal.proto.h> -#include <Library/SimpleList.class.h> +#include <SimpleList.class.h> namespace Task { Thread* currThread(); diff --git a/Source/Kernel/TaskManager/Task.wtf.asm b/Source/Kernel/TaskManager/Task.wtf.asm index 77db18e..9f27bec 100644 --- a/Source/Kernel/TaskManager/Task.wtf.asm +++ b/Source/Kernel/TaskManager/Task.wtf.asm @@ -9,13 +9,6 @@ idle_task: hlt jmp idle_task -[GLOBAL atomic_exchange] -atomic_exchange: - mov ecx, [esp+4] ; Get lock address - mov eax, [esp+8] ; Get new value - xchg eax, [ecx] ; Old value goes in eax - ret - [GLOBAL copy_page_physical] copy_page_physical: push ebx ; According to __cdecl, we must preserve the contents of EBX. @@ -47,3 +40,5 @@ copy_page_physical: popf ; Pop EFLAGS back. pop ebx ; Get the original value of EBX back. ret + + diff --git a/Source/Kernel/TaskManager/Thread.class.cpp b/Source/Kernel/TaskManager/Thread.class.cpp index 6d62474..21ef954 100644 --- a/Source/Kernel/TaskManager/Thread.class.cpp +++ b/Source/Kernel/TaskManager/Thread.class.cpp @@ -2,17 +2,71 @@ #include <TaskManager/Task.ns.h> #include <MemoryManager/PageAlloc.ns.h> #include <DeviceManager/Time.ns.h> +#include <MemoryManager/GDT.ns.h> + +#include <Thread.iface.h> + +call_t Thread::m_callTable[] = { + CALL1(THIF_SLEEP, &Thread::sleepSC), + CALL1(THIF_FINISH, &Thread::finishSC), + CALL0(0, 0) +}; + +u32int Thread::scall(u8int wat, u32int a, u32int b, u32int c, u32int d) { + if (wat == THIF_SGETCTH) return Task::currThread()->resId(); + return (u32int) - 1; +} void runThread(Thread* thread, void* data, thread_entry_t entry_point) { - asm volatile("sti"); - u32int ret = entry_point(data); //Run ! - asm volatile("mov %0, %%eax; int $66;" : : "r"(ret)); //Syscall for thread ending + if (thread->m_isKernel) { + asm volatile("sti"); + u32int ret = entry_point(data); //Run ! + asm volatile("mov %0, %%eax; int $66;" : : "r"(ret)); //Syscall for thread ending + } else { + //Setup values on user stack + u32int *stack = (u32int*)((u32int)thread->m_userStack.addr + thread->m_userStack.size); + stack--; + *stack = (u32int)data; + stack--; + *stack = 0; + u32int esp = (u32int)stack, eip = (u32int)entry_point; + //Setup a false structure for returning from an interrupt : + //- update data segments to 0x23 = user data segment with RPL=3 + //- mov esp in ebx and eip in ecx + //- push value for ss : 0x23 (user data seg rpl3) + //- push value for esp + //- push flags + //- update flags, set IF = 1 (interrupts flag) + //- push value for cs : 0x1B = user code segment with RPL=3 + //- push eip + //- return from fake interrupt + asm volatile(" \ + mov $0x23, %%ax; \ + mov %%ax, %%ds; \ + mov %%ax, %%es; \ + mov %%ax, %%fs; \ + mov %%ax, %%gs; \ + \ + mov %0, %%ebx; \ + mov %1, %%ecx; \ + pushl $0x23; \ + pushl %%ebx; \ + pushf; \ + pop %%eax; \ + or $0x200, %%eax; \ + push %%eax; \ + pushl $0x1B; \ + push %%ecx; \ + iret; \ + " : : "r"(esp), "r"(eip)); + } } -Thread::Thread() { //Private constructor, does nothing +Thread::Thread() : Ressource(THIF_OBJTYPE, m_callTable) { //Private constructor, does nothing + m_xchgspace = 0; } -Thread::Thread(thread_entry_t entry_point, void* data, bool iskernel) { +Thread::Thread(thread_entry_t entry_point, void* data, bool iskernel) : Ressource(THIF_OBJTYPE, m_callTable) { if (iskernel) { setup(Task::getKernelProcess(), entry_point, data, true); } else { @@ -20,22 +74,28 @@ Thread::Thread(thread_entry_t entry_point, void* data, bool iskernel) { } } -Thread::Thread(Process* process, thread_entry_t entry_point, void* data) { +Thread::Thread(Process* process, thread_entry_t entry_point, void* data) : Ressource(THIF_OBJTYPE, m_callTable) { setup(process, entry_point, data, false); } Thread::~Thread() { Task::unregisterThread(this); - Mem::kfree(m_kernelStack.addr); - if (!m_isKernel) m_process->heap().free(m_userStack.addr); + Mem::free(m_kernelStack.addr); + m_process->getPagedir()->switchTo(); + if (m_userStack.addr != 0) { + m_process->heap().free(m_userStack.addr); + } + if (m_xchgspace != 0) { + m_process->heap().free(m_xchgspace); + } //Don't unregister thread in process, it has probably already been done } void Thread::setup(Process* process, thread_entry_t entry_point, void* data, bool isKernel) { - DEBUG("new Thread :: setup"); + m_xchgspace = 0; m_isKernel = isKernel; m_process = process; - m_kernelStack.addr = Mem::kalloc(STACKSIZE); + m_kernelStack.addr = Mem::alloc(STACKSIZE); m_kernelStack.size = STACKSIZE; if (m_isKernel) { @@ -111,11 +171,11 @@ void Thread::handleException(registers_t regs, int no) { *(m_process->m_vt) << "At:" << (u32int)faddr; *(m_process->m_vt) << "\nThread finishing.\n"; - finish(E_PAGEFAULT); + Task::currentThreadExits(E_PAGEFAULT); //Calling this will setup a new stack return; } *(m_process->m_vt) << "\nThread finishing.\n"; - finish(E_UNHANDLED_EXCEPTION); + Task::currentThreadExits(E_UNHANDLED_EXCEPTION); } void Thread::setState(u32int esp, u32int ebp, u32int eip) { @@ -124,12 +184,22 @@ void Thread::setState(u32int esp, u32int ebp, u32int eip) { m_eip = eip; } +void Thread::setKernelStack() { + GDT::tss_entry.esp0 = (u32int)(m_kernelStack.addr) + m_kernelStack.size; +} + u32int Thread::getEsp() { return m_esp; } u32int Thread::getEbp() { return m_ebp; } u32int Thread::getEip() { return m_eip; } Process* Thread::getProcess() { return m_process; } +void* Thread::mkXchgSpace(u32int sz) { + if (m_xchgspace != 0) m_process->heap().free(m_xchgspace); + m_xchgspace = m_process->heap().alloc(sz); + return m_xchgspace; +} + void Thread::sleep(u32int msecs) { m_state = T_SLEEPING; waitfor.m_time = Time::time() + msecs; @@ -145,6 +215,7 @@ void Thread::waitIRQ(u8int irq) { } bool Thread::runnable() { + if (m_process->getState() != P_RUNNING) return false; if (m_state == T_RUNNING) return true; if (m_state == T_SLEEPING and Time::time() >= waitfor.m_time) { m_state = T_RUNNING; @@ -152,3 +223,17 @@ bool Thread::runnable() { } return false; } + +u32int Thread::sleepSC(u32int msecs) { + if (this != Task::currThread()) return 1; + sleep(msecs); + return 0; +} + +u32int Thread::finishSC(u32int errcode) { + if (this != Task::currThread()) return 1; + Task::currentThreadExits(errcode); + return 0; +} + + diff --git a/Source/Kernel/TaskManager/Thread.class.h b/Source/Kernel/TaskManager/Thread.class.h index 9c8fa26..35a9fd6 100644 --- a/Source/Kernel/TaskManager/Thread.class.h +++ b/Source/Kernel/TaskManager/Thread.class.h @@ -11,7 +11,7 @@ typedef u32int(*thread_entry_t)(void*); -class Thread { +class Thread : public Ressource { friend class Process; //This might be useful friend void runThread(Thread*, void*, thread_entry_t); @@ -22,6 +22,8 @@ class Thread { u32int m_esp, m_ebp, m_eip; u8int m_state; //Is one of T_* defined above + void* m_xchgspace; + union { //What the thread might be waiting for u32int m_time; u8int m_irq; //An IRQ number @@ -35,7 +37,14 @@ class Thread { void setup(Process* process, thread_entry_t entry_point, void* data, bool isKernel); + //Syscalls + static call_t m_callTable[]; + u32int sleepSC(u32int msecs); + u32int finishSC(u32int errcode); + public: + static u32int scall(u8int, u32int, u32int, u32int, u32int); + Thread(thread_entry_t entry_point, void* data, bool iskernel = false); //Assumes process is current process, or is kprocess if isk Thread(Process* process, thread_entry_t entry_point, void* data); ~Thread(); @@ -43,11 +52,14 @@ class Thread { void handleException(registers_t regs, int no); void setState(u32int esp, u32int ebp, u32int eip); + void setKernelStack(); u32int getEsp(); u32int getEbp(); u32int getEip(); Process* getProcess(); + void* mkXchgSpace(u32int sz); + void sleep(u32int msecs); void waitIRQ(u8int irq); bool runnable(); //Called by scheduler |