mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-13 08:19:18 +00:00
Update kernel
This commit is contained in:
@ -40,6 +40,7 @@ namespace InterProcessCommunication
|
||||
|
||||
IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
|
||||
{
|
||||
UNUSED(Type);
|
||||
SmartLock(this->IPCLock);
|
||||
IPCHandle *Hnd = (IPCHandle *)mem->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1));
|
||||
|
||||
@ -57,17 +58,18 @@ namespace InterProcessCommunication
|
||||
IPCErrorCode IPC::Destroy(IPCID ID)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
for (size_t i = 0; i < Handles.size(); i++)
|
||||
forItr(itr, Handles)
|
||||
{
|
||||
if (Handles[i]->ID == ID)
|
||||
if ((*itr)->ID == ID)
|
||||
{
|
||||
vfs->Delete(Handles[i]->Node);
|
||||
mem->FreePages(Handles[i], TO_PAGES(sizeof(IPCHandle) + 1));
|
||||
Handles.remove(i);
|
||||
vfs->Delete((*itr)->Node);
|
||||
mem->FreePages((*itr), TO_PAGES(sizeof(IPCHandle) + 1));
|
||||
Handles.erase(itr);
|
||||
debug("Destroyed IPC with ID %d", ID);
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
debug("Failed to destroy IPC with ID %d", ID);
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
@ -201,7 +203,7 @@ namespace InterProcessCommunication
|
||||
warn("Interrupts are disabled. This may cause a kernel hang.");
|
||||
debug("Waiting for IPC %d (now %s)", ID, Hnd->Listening ? "listening" : "ready");
|
||||
while (Hnd->Listening)
|
||||
TaskManager->Schedule();
|
||||
TaskManager->Yield();
|
||||
debug("IPC %d is ready", ID);
|
||||
return IPCSuccess;
|
||||
}
|
||||
|
220
Tasking/Process.cpp
Normal file
220
Tasking/Process.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <task.hpp>
|
||||
|
||||
#include <dumper.hpp>
|
||||
#include <convert.h>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#if defined(a64)
|
||||
#include "../Architecture/amd64/cpu/apic.hpp"
|
||||
#include "../Architecture/amd64/cpu/gdt.hpp"
|
||||
#elif defined(a32)
|
||||
#include "../Architecture/i386/cpu/apic.hpp"
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
// #define DEBUG_TASKING 1
|
||||
|
||||
#ifdef DEBUG_TASKING
|
||||
#define tskdbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync
|
||||
#else
|
||||
#define tskdbg(m, ...)
|
||||
#endif
|
||||
|
||||
using namespace InterProcessCommunication;
|
||||
using namespace VirtualFileSystem;
|
||||
using VirtualFileSystem::NodeFlags;
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
void PCB::Rename(const char *name)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
assert(strlen(name) > 0);
|
||||
|
||||
trace("Renaming thread %s to %s", this->Name, name);
|
||||
if (this->Name)
|
||||
delete[] this->Name;
|
||||
this->Name = new char[strlen(name) + 1];
|
||||
strcpy((char *)this->Name, name);
|
||||
}
|
||||
|
||||
void PCB::SetWorkingDirectory(VirtualFileSystem::Node *node)
|
||||
{
|
||||
debug("Setting working directory of process %s to %#lx (%s)",
|
||||
this->Name, node, node->Name);
|
||||
CurrentWorkingDirectory = node;
|
||||
}
|
||||
|
||||
PCB::PCB(Task *ctx, PCB *Parent, const char *Name,
|
||||
TaskExecutionMode ExecutionMode, void *Image,
|
||||
bool DoNotCreatePageTable,
|
||||
uint16_t UserID, uint16_t GroupID)
|
||||
{
|
||||
assert(ctx != nullptr);
|
||||
assert(ExecutionMode >= _ExecuteModeMin);
|
||||
assert(ExecutionMode <= _ExecuteModeMax);
|
||||
|
||||
this->ctx = ctx;
|
||||
this->ID = ctx->NextPID++;
|
||||
if (this->Name)
|
||||
delete[] this->Name;
|
||||
this->Name = new char[strlen(Name) + 1];
|
||||
strcpy((char *)this->Name, Name);
|
||||
this->ExitCode = KILL_CRASH;
|
||||
this->Security.ExecutionMode = ExecutionMode;
|
||||
|
||||
if (Parent == nullptr)
|
||||
this->Parent = ctx->GetCurrentProcess();
|
||||
else
|
||||
this->Parent = Parent;
|
||||
|
||||
if (this->Parent &&
|
||||
UserID == UINT16_MAX &&
|
||||
GroupID == UINT16_MAX)
|
||||
{
|
||||
UserID = this->Parent->Security.Real.UserID;
|
||||
GroupID = this->Parent->Security.Real.GroupID;
|
||||
}
|
||||
|
||||
this->Security.Real.UserID = UserID;
|
||||
this->Security.Real.GroupID = GroupID;
|
||||
this->Security.Effective.UserID = UserID;
|
||||
this->Security.Effective.GroupID = GroupID;
|
||||
|
||||
char ProcFSName[16];
|
||||
sprintf(ProcFSName, "%d", this->ID);
|
||||
this->ProcessDirectory = vfs->Create(ProcFSName, DIRECTORY, ProcFS);
|
||||
this->memDirectory = vfs->Create("mem", DIRECTORY, this->ProcessDirectory);
|
||||
this->FileDescriptors = new FileDescriptorTable(this);
|
||||
this->IPC = new class IPC((void *)this);
|
||||
|
||||
if (!DoNotCreatePageTable)
|
||||
{
|
||||
OwnPageTable = true;
|
||||
switch (ExecutionMode)
|
||||
{
|
||||
case TaskExecutionMode::System:
|
||||
fixme("Mode not supported.");
|
||||
[[fallthrough]];
|
||||
case TaskExecutionMode::Kernel:
|
||||
{
|
||||
this->Security.IsCritical = true;
|
||||
#if defined(a64)
|
||||
this->PageTable = (Memory::PageTable *)CPU::x64::readcr3().raw;
|
||||
#elif defined(a32)
|
||||
this->PageTable = (Memory::PageTable *)CPU::x32::readcr3().raw;
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
debug("Process %s(%d) has page table at %#lx",
|
||||
this->Name, this->ID, this->PageTable);
|
||||
break;
|
||||
}
|
||||
case TaskExecutionMode::User:
|
||||
{
|
||||
#if defined(a64)
|
||||
this->PageTable = (Memory::PageTable *)KernelAllocator.RequestPages(TO_PAGES(sizeof(Memory::PageTable) + 1));
|
||||
memcpy(this->PageTable,
|
||||
KernelPageTable,
|
||||
sizeof(Memory::PageTable));
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
debug("Process %s(%d) has page table at %#lx",
|
||||
this->Name, this->ID, this->PageTable);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
this->Memory = new Memory::MemMgr(this->PageTable, this->memDirectory);
|
||||
|
||||
if (Image)
|
||||
{
|
||||
this->ELFSymbolTable = new SymbolResolver::Symbols((uintptr_t)Image);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("No image provided for process \"%s\"(%d)",
|
||||
this->Name, this->ID);
|
||||
}
|
||||
|
||||
if (Parent)
|
||||
Parent->Children.push_back(this);
|
||||
|
||||
debug("Process page table: %#lx", this->PageTable);
|
||||
debug("Created process \"%s\"(%d). Parent \"%s\"(%d)",
|
||||
this->Name, this->ID,
|
||||
Parent ? this->Parent->Name : "None",
|
||||
Parent ? this->Parent->ID : 0);
|
||||
|
||||
this->Info.SpawnTime = TimeManager->GetCounter();
|
||||
ctx->ProcessList.push_back(this);
|
||||
}
|
||||
|
||||
PCB::~PCB()
|
||||
{
|
||||
debug("Destroying process \"%s\"(%d)",
|
||||
this->Name, this->ID);
|
||||
|
||||
ctx->ProcessList.erase(std::find(ctx->ProcessList.begin(),
|
||||
ctx->ProcessList.end(),
|
||||
this));
|
||||
|
||||
if (this->ELFSymbolTable)
|
||||
delete this->ELFSymbolTable;
|
||||
|
||||
delete this->IPC;
|
||||
delete this->FileDescriptors;
|
||||
delete this->Memory;
|
||||
delete[] this->Name;
|
||||
|
||||
if (this->PageTable && OwnPageTable)
|
||||
{
|
||||
size_t PTPgs = TO_PAGES(sizeof(Memory::PageTable) + 1);
|
||||
KernelAllocator.FreePages(this->PageTable, PTPgs);
|
||||
}
|
||||
|
||||
foreach (auto pcb in this->Children)
|
||||
delete pcb;
|
||||
|
||||
foreach (auto tcb in this->Threads)
|
||||
delete tcb;
|
||||
|
||||
vfs->Delete(this->ProcessDirectory, true);
|
||||
|
||||
if (this->Parent)
|
||||
{
|
||||
std::vector<Tasking::PCB *> &pChild = this->Parent->Children;
|
||||
|
||||
pChild.erase(std::find(pChild.begin(),
|
||||
pChild.end(),
|
||||
this));
|
||||
}
|
||||
}
|
||||
}
|
@ -34,8 +34,6 @@
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
NewLock(SchedulerLock);
|
||||
|
||||
/* FIXME: On screen task manager is corrupting the stack... */
|
||||
// #define ON_SCREEN_SCHEDULER_TASK_MANAGER 1
|
||||
|
||||
@ -127,14 +125,15 @@ namespace Tasking
|
||||
fnp_schedbg("%d processes", ProcessList.size());
|
||||
#ifdef DEBUG_FIND_NEW_PROCESS
|
||||
foreach (auto process in ProcessList)
|
||||
fnp_schedbg("Process %d %s", process->ID, process->Name);
|
||||
fnp_schedbg("Process %d %s", process->ID,
|
||||
process->Name);
|
||||
#endif
|
||||
foreach (auto process in ProcessList)
|
||||
{
|
||||
if (InvalidPCB(process))
|
||||
continue;
|
||||
|
||||
switch (process->Status)
|
||||
switch (process->Status.load())
|
||||
{
|
||||
case TaskStatus::Ready:
|
||||
fnp_schedbg("Ready process (%s)%d",
|
||||
@ -158,7 +157,7 @@ namespace Tasking
|
||||
if (InvalidTCB(thread))
|
||||
continue;
|
||||
|
||||
if (thread->Status != TaskStatus::Ready)
|
||||
if (thread->Status.load() != TaskStatus::Ready)
|
||||
continue;
|
||||
|
||||
if (thread->Info.Affinity[CurrentCPU->ID] == false)
|
||||
@ -177,17 +176,22 @@ namespace Tasking
|
||||
{
|
||||
CPUData *CurrentCPU = (CPUData *)CPUDataPointer;
|
||||
|
||||
for (size_t i = 0; i < CurrentCPU->CurrentProcess->Threads.size(); i++)
|
||||
size_t ThreadsSize = CurrentCPU->CurrentProcess->Threads.size();
|
||||
|
||||
for (size_t i = 0; i < ThreadsSize; i++)
|
||||
{
|
||||
if (CurrentCPU->CurrentProcess->Threads[i] == CurrentCPU->CurrentThread.load())
|
||||
{
|
||||
size_t TempIndex = i;
|
||||
RetryAnotherThread:
|
||||
if (TempIndex + 1 >= ThreadsSize)
|
||||
break;
|
||||
|
||||
TCB *nextThread = CurrentCPU->CurrentProcess->Threads[TempIndex + 1];
|
||||
|
||||
if (unlikely(InvalidTCB(nextThread)))
|
||||
{
|
||||
if (TempIndex > CurrentCPU->CurrentProcess->Threads.size())
|
||||
if (TempIndex > ThreadsSize)
|
||||
break;
|
||||
TempIndex++;
|
||||
|
||||
@ -200,7 +204,7 @@ namespace Tasking
|
||||
CurrentCPU->CurrentProcess->Threads[i]->ID,
|
||||
nextThread->Name, nextThread->ID);
|
||||
|
||||
if (nextThread->Status != TaskStatus::Ready)
|
||||
if (nextThread->Status.load() != TaskStatus::Ready)
|
||||
{
|
||||
gnat_schedbg("Thread %d is not ready", nextThread->ID);
|
||||
TempIndex++;
|
||||
@ -213,7 +217,7 @@ namespace Tasking
|
||||
CurrentCPU->CurrentThread = nextThread;
|
||||
gnat_schedbg("[thd 0 -> end] Scheduling thread %d parent of %s->%d Procs %d",
|
||||
nextThread->ID, nextThread->Parent->Name,
|
||||
CurrentCPU->CurrentProcess->Threads.size(), ProcessList.size());
|
||||
ThreadsSize, ProcessList.size());
|
||||
return true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
@ -253,7 +257,7 @@ namespace Tasking
|
||||
continue;
|
||||
}
|
||||
|
||||
if (process->Status != TaskStatus::Ready)
|
||||
if (process->Status.load() != TaskStatus::Ready)
|
||||
{
|
||||
gnap_schedbg("Process %d is not ready", process->ID);
|
||||
continue;
|
||||
@ -267,7 +271,7 @@ namespace Tasking
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thread->Status != TaskStatus::Ready)
|
||||
if (thread->Status.load() != TaskStatus::Ready)
|
||||
{
|
||||
gnap_schedbg("Thread %d is not ready", thread->ID);
|
||||
continue;
|
||||
@ -299,7 +303,7 @@ namespace Tasking
|
||||
continue;
|
||||
}
|
||||
|
||||
if (process->Status != TaskStatus::Ready)
|
||||
if (process->Status.load() != TaskStatus::Ready)
|
||||
{
|
||||
sspt_schedbg("Process %d is not ready", process->ID);
|
||||
continue;
|
||||
@ -313,7 +317,7 @@ namespace Tasking
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thread->Status != TaskStatus::Ready)
|
||||
if (thread->Status.load() != TaskStatus::Ready)
|
||||
{
|
||||
sspt_schedbg("Thread %d is not ready", thread->ID);
|
||||
continue;
|
||||
@ -339,14 +343,14 @@ namespace Tasking
|
||||
if (InvalidPCB(process))
|
||||
continue;
|
||||
|
||||
if (process->Status == TaskStatus::Terminated ||
|
||||
process->Status == TaskStatus::Stopped)
|
||||
if (process->Status.load() == TaskStatus::Terminated ||
|
||||
process->Status.load() == TaskStatus::Zombie)
|
||||
continue;
|
||||
|
||||
bool AllThreadsSleeping = true;
|
||||
foreach (auto thread in process->Threads)
|
||||
{
|
||||
if (thread->Status != TaskStatus::Sleeping)
|
||||
if (thread->Status.load() != TaskStatus::Sleeping)
|
||||
{
|
||||
AllThreadsSleeping = false;
|
||||
break;
|
||||
@ -354,9 +358,9 @@ namespace Tasking
|
||||
}
|
||||
|
||||
if (AllThreadsSleeping)
|
||||
process->Status = TaskStatus::Sleeping;
|
||||
else if (process->Status == TaskStatus::Sleeping)
|
||||
process->Status = TaskStatus::Ready;
|
||||
process->Status.store(TaskStatus::Sleeping);
|
||||
else if (process->Status.load() == TaskStatus::Sleeping)
|
||||
process->Status.store(TaskStatus::Ready);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,8 +371,8 @@ namespace Tasking
|
||||
if (InvalidPCB(process))
|
||||
continue;
|
||||
|
||||
if (process->Status == TaskStatus::Terminated ||
|
||||
process->Status == TaskStatus::Stopped)
|
||||
if (process->Status.load() == TaskStatus::Terminated ||
|
||||
process->Status.load() == TaskStatus::Zombie)
|
||||
continue;
|
||||
|
||||
foreach (auto thread in process->Threads)
|
||||
@ -376,15 +380,15 @@ namespace Tasking
|
||||
if (InvalidTCB(thread))
|
||||
continue;
|
||||
|
||||
if (thread->Status != TaskStatus::Sleeping)
|
||||
if (thread->Status.load() != TaskStatus::Sleeping)
|
||||
continue;
|
||||
|
||||
/* Check if the thread is ready to wake up. */
|
||||
if (thread->Info.SleepUntil < TimeManager->GetCounter())
|
||||
{
|
||||
if (process->Status == TaskStatus::Sleeping)
|
||||
process->Status = TaskStatus::Ready;
|
||||
thread->Status = TaskStatus::Ready;
|
||||
if (process->Status.load() == TaskStatus::Sleeping)
|
||||
process->Status.store(TaskStatus::Ready);
|
||||
thread->Status.store(TaskStatus::Ready);
|
||||
|
||||
thread->Info.SleepUntil = 0;
|
||||
wut_schedbg("Thread \"%s\"(%d) woke up.", thread->Name, thread->ID);
|
||||
@ -407,8 +411,8 @@ namespace Tasking
|
||||
"AAFF00", /* Ready */
|
||||
"00AA00", /* Running */
|
||||
"FFAA00", /* Sleeping */
|
||||
"FFAA00", /* Waiting */
|
||||
"FF0088", /* Stopped */
|
||||
"FFAA00", /* Blocked */
|
||||
"FF0088", /* Zombie */
|
||||
"FF0000", /* Terminated */
|
||||
};
|
||||
|
||||
@ -526,10 +530,10 @@ namespace Tasking
|
||||
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||
|
||||
if (CurrentCPU->CurrentProcess->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Ready;
|
||||
if (CurrentCPU->CurrentThread->Status == TaskStatus::Running)
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Ready;
|
||||
if (CurrentCPU->CurrentProcess->Status.load() == TaskStatus::Running)
|
||||
CurrentCPU->CurrentProcess->Status.store(TaskStatus::Ready);
|
||||
if (CurrentCPU->CurrentThread->Status.load() == TaskStatus::Running)
|
||||
CurrentCPU->CurrentThread->Status.store(TaskStatus::Ready);
|
||||
|
||||
this->UpdateProcessStatus();
|
||||
schedbg("Passed UpdateProcessStatus");
|
||||
@ -537,6 +541,9 @@ namespace Tasking
|
||||
this->WakeUpThreads();
|
||||
schedbg("Passed WakeUpThreads");
|
||||
|
||||
if (this->SchedulerUpdateTrapFrame)
|
||||
goto Success;
|
||||
|
||||
if (this->GetNextAvailableThread(CurrentCPU))
|
||||
{
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
@ -586,11 +593,16 @@ namespace Tasking
|
||||
CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID);
|
||||
|
||||
if (!ProcessNotChanged)
|
||||
UpdateUsage(&CurrentCPU->CurrentProcess->Info, &CurrentCPU->CurrentProcess->Security, CurrentCPU->ID);
|
||||
UpdateUsage(&CurrentCPU->CurrentThread->Info, &CurrentCPU->CurrentThread->Security, CurrentCPU->ID);
|
||||
UpdateUsage(&CurrentCPU->CurrentProcess->Info,
|
||||
CurrentCPU->CurrentProcess->Security.ExecutionMode,
|
||||
CurrentCPU->ID);
|
||||
|
||||
CurrentCPU->CurrentProcess->Status = TaskStatus::Running;
|
||||
CurrentCPU->CurrentThread->Status = TaskStatus::Running;
|
||||
UpdateUsage(&CurrentCPU->CurrentThread->Info,
|
||||
CurrentCPU->CurrentThread->Security.ExecutionMode,
|
||||
CurrentCPU->ID);
|
||||
|
||||
CurrentCPU->CurrentProcess->Status.store(TaskStatus::Running);
|
||||
CurrentCPU->CurrentThread->Status.store(TaskStatus::Running);
|
||||
|
||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||
|
||||
@ -613,18 +625,18 @@ namespace Tasking
|
||||
OnScreenTaskManagerUpdate();
|
||||
#endif
|
||||
|
||||
switch (CurrentCPU->CurrentProcess->Security.TrustLevel)
|
||||
switch (CurrentCPU->CurrentProcess->Security.ExecutionMode)
|
||||
{
|
||||
case TaskTrustLevel::System:
|
||||
case TaskTrustLevel::Kernel:
|
||||
case TaskExecutionMode::System:
|
||||
case TaskExecutionMode::Kernel:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, (uint64_t)CurrentCPU->CurrentThread);
|
||||
break;
|
||||
case TaskTrustLevel::User:
|
||||
case TaskExecutionMode::User:
|
||||
// wrmsr(MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->gs);
|
||||
break;
|
||||
default:
|
||||
error("Unknown trust level %d.",
|
||||
CurrentCPU->CurrentProcess->Security.TrustLevel);
|
||||
CurrentCPU->CurrentProcess->Security.ExecutionMode);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -663,7 +675,6 @@ namespace Tasking
|
||||
|
||||
End:
|
||||
this->SchedulerTicks.store(TimeManager->GetCounter() - SchedTmpTicks);
|
||||
__sync; /* TODO: Is this really needed? */
|
||||
}
|
||||
|
||||
SafeFunction NIF void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
|
||||
|
@ -1,149 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <task.hpp>
|
||||
|
||||
#include <rand.hpp>
|
||||
#include <debug.h>
|
||||
#include <vector>
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
Token Security::CreateToken()
|
||||
{
|
||||
Token ret = 0;
|
||||
Retry:
|
||||
ret = (Token)Random::rand64();
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == ret)
|
||||
goto Retry;
|
||||
|
||||
Tokens.push_back({ret, UnknownTrustLevel, 0, false});
|
||||
debug("Created token %#lx", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Security::TrustToken(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel = TrustLevel;
|
||||
debug("Trusted token %#lx to level %d", token, t.TrustLevel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to trust token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::UntrustToken(Token token)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel = Untrusted;
|
||||
debug("Untrusted token %#lx", token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to untrust token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::AddTrustLevel(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel |= TrustLevel;
|
||||
debug("Added trust level %d to token %#lx", t.TrustLevel, token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to add trust level %d to token %#lx", TrustLevel, token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::RemoveTrustLevel(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto &t in Tokens)
|
||||
{
|
||||
if (t.token == token)
|
||||
{
|
||||
t.TrustLevel &= ~TrustLevel;
|
||||
debug("Removed trust level %d from token %#lx", t.TrustLevel, token);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
warn("Failed to remove trust level %d from token %#lx", TrustLevel, token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::DestroyToken(Token token)
|
||||
{
|
||||
fixme("DestroyToken->true");
|
||||
UNUSED(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Security::IsTokenTrusted(Token token, TTL TrustLevel)
|
||||
{
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
{
|
||||
if (t.TrustLevel == TrustLevel)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
warn("Failed to check trust level of token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Security::IsTokenTrusted(Token token, int TrustLevel)
|
||||
{
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
{
|
||||
if (t.TrustLevel & TrustLevel)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
warn("Failed to check trust level of token %#lx", token);
|
||||
return false;
|
||||
}
|
||||
|
||||
int Security::GetTokenTrustLevel(Token token)
|
||||
{
|
||||
foreach (auto t in Tokens)
|
||||
if (t.token == token)
|
||||
return t.TrustLevel;
|
||||
|
||||
warn("Failed to get trust level of token %#lx", token);
|
||||
return UnknownTrustLevel;
|
||||
}
|
||||
|
||||
Security::Security() {}
|
||||
Security::~Security() { Tokens.clear(); }
|
||||
}
|
1074
Tasking/Task.cpp
1074
Tasking/Task.cpp
File diff suppressed because it is too large
Load Diff
460
Tasking/Thread.cpp
Normal file
460
Tasking/Thread.cpp
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <task.hpp>
|
||||
|
||||
#include <dumper.hpp>
|
||||
#include <convert.h>
|
||||
#include <lock.hpp>
|
||||
#include <printf.h>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#if defined(a64)
|
||||
#include "../Architecture/amd64/cpu/apic.hpp"
|
||||
#include "../Architecture/amd64/cpu/gdt.hpp"
|
||||
#elif defined(a32)
|
||||
#include "../Architecture/i386/cpu/apic.hpp"
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
// #define DEBUG_TASKING 1
|
||||
|
||||
#ifdef DEBUG_TASKING
|
||||
#define tskdbg(m, ...) \
|
||||
debug(m, ##__VA_ARGS__); \
|
||||
__sync
|
||||
#else
|
||||
#define tskdbg(m, ...)
|
||||
#endif
|
||||
|
||||
void ThreadDoExit()
|
||||
{
|
||||
CPUData *CPUData = GetCurrentCPU();
|
||||
Tasking::TCB *CurrentThread = CPUData->CurrentThread.load();
|
||||
CurrentThread->Status = Tasking::TaskStatus::Terminated;
|
||||
|
||||
debug("\"%s\"(%d) exited with code: %#lx",
|
||||
CurrentThread->Name,
|
||||
CurrentThread->ID,
|
||||
CurrentThread->ExitCode);
|
||||
CPU::Halt(true);
|
||||
}
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
void TCB::Rename(const char *name)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
assert(strlen(name) > 0);
|
||||
|
||||
trace("Renaming thread %s to %s", this->Name, name);
|
||||
if (this->Name)
|
||||
delete[] this->Name;
|
||||
this->Name = new char[strlen(name) + 1];
|
||||
strcpy((char *)this->Name, name);
|
||||
}
|
||||
|
||||
void TCB::SetPriority(TaskPriority priority)
|
||||
{
|
||||
assert(priority >= _PriorityMin);
|
||||
// assert(priority <= _PriorityMax);
|
||||
|
||||
trace("Setting priority of thread %s to %d",
|
||||
this->Name, priority);
|
||||
|
||||
Info.Priority = priority;
|
||||
}
|
||||
|
||||
void TCB::SetCritical(bool Critical)
|
||||
{
|
||||
trace("Setting criticality of thread %s to %s",
|
||||
this->Name, Critical ? "true" : "false");
|
||||
|
||||
Security.IsCritical = Critical;
|
||||
}
|
||||
|
||||
void TCB::SetDebugMode(bool Enable)
|
||||
{
|
||||
trace("Setting debug mode of thread %s to %s",
|
||||
this->Name, Enable ? "true" : "false");
|
||||
|
||||
Security.IsDebugEnabled = Enable;
|
||||
}
|
||||
|
||||
void TCB::SetKernelDebugMode(bool Enable)
|
||||
{
|
||||
trace("Setting kernel debug mode of thread %s to %s",
|
||||
this->Name, Enable ? "true" : "false");
|
||||
|
||||
Security.IsKernelDebugEnabled = Enable;
|
||||
}
|
||||
|
||||
void TCB::SYSV_ABI_Call(uintptr_t Arg1, uintptr_t Arg2,
|
||||
uintptr_t Arg3, uintptr_t Arg4,
|
||||
uintptr_t Arg5, uintptr_t Arg6,
|
||||
void *Function)
|
||||
{
|
||||
#if defined(a64)
|
||||
this->Registers.rdi = Arg1;
|
||||
this->Registers.rsi = Arg2;
|
||||
this->Registers.rdx = Arg3;
|
||||
this->Registers.rcx = Arg4;
|
||||
this->Registers.r8 = Arg5;
|
||||
this->Registers.r9 = Arg6;
|
||||
if (Function != nullptr)
|
||||
this->Registers.rip = (uint64_t)Function;
|
||||
#else
|
||||
#warning "SYSV ABI not implemented for this architecture"
|
||||
#endif
|
||||
}
|
||||
|
||||
__no_sanitize("undefined")
|
||||
TCB::TCB(Task *ctx, PCB *Parent, IP EntryPoint,
|
||||
const char **argv, const char **envp,
|
||||
const std::vector<AuxiliaryVector> &auxv,
|
||||
TaskArchitecture Architecture,
|
||||
TaskCompatibility Compatibility,
|
||||
bool ThreadNotReady)
|
||||
{
|
||||
assert(ctx != nullptr);
|
||||
assert(Architecture >= _ArchitectureMin);
|
||||
assert(Architecture <= _ArchitectureMax);
|
||||
assert(Compatibility >= _CompatibilityMin);
|
||||
assert(Compatibility <= _CompatibilityMax);
|
||||
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
this->Parent = ctx->GetCurrentProcess();
|
||||
assert(this->Parent != nullptr);
|
||||
}
|
||||
else
|
||||
this->Parent = Parent;
|
||||
|
||||
this->ctx = ctx;
|
||||
this->ID = ctx->NextTID++;
|
||||
|
||||
if (this->Name)
|
||||
delete[] this->Name;
|
||||
this->Name = new char[strlen(this->Parent->Name) + 1];
|
||||
strcpy((char *)this->Name, this->Parent->Name);
|
||||
|
||||
this->EntryPoint = EntryPoint;
|
||||
this->ExitCode = KILL_CRASH;
|
||||
this->Info.Architecture = Architecture;
|
||||
this->Info.Compatibility = Compatibility;
|
||||
this->Security.ExecutionMode =
|
||||
this->Parent->Security.ExecutionMode;
|
||||
if (ThreadNotReady)
|
||||
this->Status = TaskStatus::Zombie;
|
||||
else
|
||||
this->Status = TaskStatus::Ready;
|
||||
this->Memory = new Memory::MemMgr(this->Parent->PageTable,
|
||||
this->Parent->memDirectory);
|
||||
std::size_t FXPgs = TO_PAGES(sizeof(CPU::x64::FXState) + 1);
|
||||
this->FPU = (CPU::x64::FXState *)this->Memory->RequestPages(FXPgs);
|
||||
memset(this->FPU, 0, sizeof(CPU::x64::FXState));
|
||||
|
||||
// TODO: Is really a good idea to use the FPU in kernel mode?
|
||||
this->FPU->mxcsr = 0b0001111110000000;
|
||||
this->FPU->mxcsrmask = 0b1111111110111111;
|
||||
this->FPU->fcw = 0b0000001100111111;
|
||||
|
||||
// CPU::x64::fxrstor(this->FPU);
|
||||
// uint16_t FCW = 0b1100111111;
|
||||
// asmv("fldcw %0"
|
||||
// :
|
||||
// : "m"(FCW)
|
||||
// : "memory");
|
||||
// uint32_t MXCSR = 0b1111110000000;
|
||||
// asmv("ldmxcsr %0"
|
||||
// :
|
||||
// : "m"(MXCSR)
|
||||
// : "memory");
|
||||
// CPU::x64::fxsave(this->FPU);
|
||||
|
||||
#if defined(a64)
|
||||
this->Registers.rip = EntryPoint;
|
||||
#elif defined(a32)
|
||||
this->Registers.eip = EntryPoint;
|
||||
#elif defined(aa64)
|
||||
this->Registers.pc = EntryPoint;
|
||||
#endif
|
||||
|
||||
switch (this->Parent->Security.ExecutionMode)
|
||||
{
|
||||
case TaskExecutionMode::System:
|
||||
fixme("System mode not supported.");
|
||||
[[fallthrough]];
|
||||
case TaskExecutionMode::Kernel:
|
||||
{
|
||||
this->Security.IsCritical = true;
|
||||
this->Stack = new Memory::StackGuard(false,
|
||||
this->Parent->PageTable);
|
||||
|
||||
#if defined(a64)
|
||||
this->ShadowGSBase =
|
||||
CPU::x64::rdmsr(CPU::x64::MSRID::MSR_SHADOW_GS_BASE);
|
||||
this->GSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_GS_BASE);
|
||||
this->FSBase = CPU::x64::rdmsr(CPU::x64::MSRID::MSR_FS_BASE);
|
||||
this->Registers.cs = GDT_KERNEL_CODE;
|
||||
this->Registers.ss = GDT_KERNEL_DATA;
|
||||
this->Registers.rflags.AlwaysOne = 1;
|
||||
this->Registers.rflags.IF = 1;
|
||||
this->Registers.rflags.ID = 1;
|
||||
this->Registers.rsp = ((uintptr_t)this->Stack->GetStackTop());
|
||||
POKE(uintptr_t, this->Registers.rsp) = (uintptr_t)ThreadDoExit;
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case TaskExecutionMode::User:
|
||||
{
|
||||
this->Stack = new Memory::StackGuard(true,
|
||||
this->Parent->PageTable);
|
||||
|
||||
gsTCB *gsT = (gsTCB *)this->Memory->RequestPages(TO_PAGES(sizeof(gsTCB)));
|
||||
|
||||
gsT->SyscallStack =
|
||||
(uintptr_t)this->Memory->RequestPages(TO_PAGES(STACK_SIZE)) +
|
||||
STACK_SIZE - 0x10;
|
||||
|
||||
gsT->TempStack = 0x0;
|
||||
gsT->t = this;
|
||||
#if defined(a64)
|
||||
this->ShadowGSBase = (uintptr_t)gsT;
|
||||
this->GSBase = 0;
|
||||
this->FSBase = 0;
|
||||
this->Registers.cs = GDT_USER_CODE;
|
||||
this->Registers.ss = GDT_USER_DATA;
|
||||
this->Registers.rflags.AlwaysOne = 1;
|
||||
this->Registers.rflags.IF = 1;
|
||||
this->Registers.rflags.ID = 1;
|
||||
/* We need to leave the libc's crt
|
||||
to make a syscall when the Thread
|
||||
is exited or we are going to get
|
||||
GPF or PF exception. */
|
||||
|
||||
#pragma region
|
||||
size_t ArgvSize = 0;
|
||||
if (argv)
|
||||
while (argv[ArgvSize] != nullptr)
|
||||
ArgvSize++;
|
||||
|
||||
size_t EnvpSize = 0;
|
||||
if (envp)
|
||||
while (envp[EnvpSize] != nullptr)
|
||||
EnvpSize++;
|
||||
|
||||
debug("ArgvSize: %d", ArgvSize);
|
||||
debug("EnvpSize: %d", EnvpSize);
|
||||
|
||||
/* https://articles.manugarg.com/aboutelfauxiliaryvectors.html */
|
||||
/* https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf#figure.3.9 */
|
||||
// rsp is the top of the stack
|
||||
char *Stack = (char *)this->Stack->GetStackPhysicalTop();
|
||||
// Temporary stack pointer for strings
|
||||
char *StackStrings = (char *)Stack;
|
||||
char *StackStringsVirtual = (char *)this->Stack->GetStackTop();
|
||||
|
||||
// Store string pointers for later
|
||||
uintptr_t *ArgvStrings = nullptr;
|
||||
uintptr_t *EnvpStrings = nullptr;
|
||||
if (ArgvSize > 0)
|
||||
ArgvStrings = new uintptr_t[ArgvSize];
|
||||
if (EnvpSize > 0)
|
||||
EnvpStrings = new uintptr_t[EnvpSize];
|
||||
|
||||
for (size_t i = 0; i < ArgvSize; i++)
|
||||
{
|
||||
// Subtract the length of the string and the null terminator
|
||||
StackStrings -= strlen(argv[i]) + 1;
|
||||
StackStringsVirtual -= strlen(argv[i]) + 1;
|
||||
// Store the pointer to the string
|
||||
ArgvStrings[i] = (uintptr_t)StackStringsVirtual;
|
||||
// Copy the string to the stack
|
||||
strcpy(StackStrings, argv[i]);
|
||||
debug("argv[%d]: %s", i, argv[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < EnvpSize; i++)
|
||||
{
|
||||
// Subtract the length of the string and the null terminator
|
||||
StackStrings -= strlen(envp[i]) + 1;
|
||||
StackStringsVirtual -= strlen(envp[i]) + 1;
|
||||
// Store the pointer to the string
|
||||
EnvpStrings[i] = (uintptr_t)StackStringsVirtual;
|
||||
// Copy the string to the stack
|
||||
strcpy(StackStrings, envp[i]);
|
||||
debug("envp[%d]: %s", i, envp[i]);
|
||||
}
|
||||
|
||||
// Align the stack to 16 bytes
|
||||
StackStrings -= (uintptr_t)StackStrings & 0xF;
|
||||
// Set "Stack" to the new stack pointer
|
||||
Stack = (char *)StackStrings;
|
||||
// If argv and envp sizes are odd then we need to align the stack
|
||||
Stack -= (ArgvSize + EnvpSize) % 2;
|
||||
|
||||
// We need 8 bit pointers for the stack from here
|
||||
uintptr_t *Stack64 = (uintptr_t *)Stack;
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
|
||||
// auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator
|
||||
std::vector<AuxiliaryVector> auxv_array = auxv;
|
||||
if (auxv_array.size() == 0)
|
||||
auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
|
||||
|
||||
// Store auxillary vector
|
||||
foreach (AuxiliaryVector var in auxv_array)
|
||||
{
|
||||
// Subtract the size of the auxillary vector
|
||||
Stack64 -= sizeof(Elf64_auxv_t) / sizeof(uintptr_t);
|
||||
// Store the auxillary vector
|
||||
POKE(Elf64_auxv_t, Stack64) = var.archaux;
|
||||
// TODO: Store strings to the stack
|
||||
}
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
|
||||
// Store EnvpStrings[] to the stack
|
||||
Stack64 -= EnvpSize; // (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize)
|
||||
for (size_t i = 0; i < EnvpSize; i++)
|
||||
{
|
||||
*(Stack64 + i) = (uintptr_t)EnvpStrings[i];
|
||||
debug("EnvpStrings[%d]: %#lx",
|
||||
i, EnvpStrings[i]);
|
||||
}
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
|
||||
// Store ArgvStrings[] to the stack
|
||||
Stack64 -= ArgvSize; // (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize)
|
||||
for (size_t i = 0; i < ArgvSize; i++)
|
||||
{
|
||||
*(Stack64 + i) = (uintptr_t)ArgvStrings[i];
|
||||
debug("ArgvStrings[%d]: %#lx",
|
||||
i, ArgvStrings[i]);
|
||||
}
|
||||
|
||||
// Store the argc
|
||||
Stack64--;
|
||||
*Stack64 = ArgvSize;
|
||||
|
||||
// Set "Stack" to the new stack pointer
|
||||
Stack = (char *)Stack64;
|
||||
|
||||
/* We need the virtual address but because we are in the kernel we can't use the process page table.
|
||||
So we modify the physical address and store how much we need to subtract to get the virtual address for RSP. */
|
||||
uintptr_t SubtractStack = (uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)Stack;
|
||||
debug("SubtractStack: %#lx", SubtractStack);
|
||||
|
||||
// Set the stack pointer to the new stack
|
||||
this->Registers.rsp = ((uintptr_t)this->Stack->GetStackTop() - SubtractStack);
|
||||
|
||||
if (ArgvSize > 0)
|
||||
delete[] ArgvStrings;
|
||||
if (EnvpSize > 0)
|
||||
delete[] EnvpStrings;
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpData("Stack Data", (void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack), SubtractStack);
|
||||
#endif
|
||||
|
||||
this->Registers.rdi = (uintptr_t)ArgvSize; // argc
|
||||
this->Registers.rsi = (uintptr_t)(this->Registers.rsp + 8); // argv
|
||||
this->Registers.rcx = (uintptr_t)EnvpSize; // envc
|
||||
this->Registers.rdx = (uintptr_t)(this->Registers.rsp + 8 + (8 * ArgvSize) + 8); // envp
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
#ifdef DEBUG_TASKING
|
||||
DumpData(this->Name, this->Stack, STACK_SIZE);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
this->Info.SpawnTime = TimeManager->GetCounter();
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef a64
|
||||
debug("Thread EntryPoint: %#lx => RIP: %#lx",
|
||||
this->EntryPoint, this->Registers.rip);
|
||||
if (this->Parent->Security.ExecutionMode == TaskExecutionMode::User)
|
||||
debug("Thread stack region is %#lx-%#lx (U) and rsp is %#lx",
|
||||
this->Stack->GetStackBottom(), this->Stack->GetStackTop(),
|
||||
this->Registers.rsp);
|
||||
else
|
||||
debug("Thread stack region is %#lx-%#lx (K) and rsp is %#lx",
|
||||
this->Stack->GetStackBottom(), this->Stack->GetStackTop(),
|
||||
this->Registers.rsp);
|
||||
#elif defined(a32)
|
||||
debug("Thread EntryPoint: %#lx => RIP: %#lx",
|
||||
this->EntryPoint, this->Registers.eip);
|
||||
if (Parent->Security.ExecutionMode == TaskExecutionMode::User)
|
||||
debug("Thread stack region is %#lx-%#lx (U) and rsp is %#lx",
|
||||
this->Stack->GetStackBottom(), this->Stack->GetStackTop(),
|
||||
this->Registers.esp);
|
||||
else
|
||||
debug("Thread stack region is %#lx-%#lx (K) and rsp is %#lx",
|
||||
this->Stack->GetStackBottom(), this->Stack->GetStackTop(),
|
||||
this->Registers.esp);
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
debug("Created thread \"%s\"(%d) in process \"%s\"(%d)",
|
||||
this->Name, this->ID, this->Parent->Name,
|
||||
this->Parent->ID);
|
||||
#endif
|
||||
|
||||
this->Parent->Threads.push_back(this);
|
||||
|
||||
if (this->Parent->Threads.size() == 1 &&
|
||||
this->Parent->Status == Zombie &&
|
||||
ThreadNotReady == false)
|
||||
{
|
||||
this->Parent->Status = Ready;
|
||||
}
|
||||
}
|
||||
|
||||
TCB::~TCB()
|
||||
{
|
||||
std::vector<Tasking::TCB *> &Threads = this->Parent->Threads;
|
||||
Threads.erase(std::find(Threads.begin(),
|
||||
Threads.end(),
|
||||
this));
|
||||
|
||||
delete[] this->Name;
|
||||
delete this->Stack;
|
||||
delete this->Memory;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user