mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-10 23:09:18 +00:00
Update kernel
This commit is contained in:
277
tasking/ipc.cpp
277
tasking/ipc.cpp
@ -1,277 +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 <ipc.hpp>
|
||||
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
#include "../ipc.h"
|
||||
|
||||
namespace InterProcessCommunication
|
||||
{
|
||||
void IPC::Fork(IPC *Parent)
|
||||
{
|
||||
std::vector<IPCHandle *> ParentHandles = Parent->GetHandles();
|
||||
|
||||
foreach (auto Hnd in ParentHandles)
|
||||
{
|
||||
debug("Forking IPC with ID %d", Hnd->ID);
|
||||
IPCHandle *NewHnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1));
|
||||
memcpy(NewHnd, Hnd, sizeof(IPCHandle));
|
||||
NewHnd->Node = fs->Create(Hnd->Node->Name, vfs::NodeType::FILE, IPCNode);
|
||||
Handles.push_back(NewHnd);
|
||||
}
|
||||
}
|
||||
|
||||
IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16])
|
||||
{
|
||||
UNUSED(Type);
|
||||
SmartLock(this->IPCLock);
|
||||
IPCHandle *Hnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1));
|
||||
|
||||
Hnd->ID = NextID++;
|
||||
Hnd->Node = fs->Create(UniqueToken, vfs::NodeType::FILE, IPCNode);
|
||||
Hnd->Buffer = nullptr;
|
||||
Hnd->Length = 0;
|
||||
Hnd->Listening = false;
|
||||
|
||||
Handles.push_back(Hnd);
|
||||
debug("Created IPC with ID %d", Hnd->ID);
|
||||
return Hnd;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Destroy(IPCID ID)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
forItr(itr, Handles)
|
||||
{
|
||||
if ((*itr)->ID == ID)
|
||||
{
|
||||
fs->Delete((*itr)->Node);
|
||||
vma->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;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Allocate(IPCID ID, long Size)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
if (Size < 0)
|
||||
return IPCError;
|
||||
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
if (Hnd->Buffer != nullptr || Hnd->Length != 0)
|
||||
return IPCAlreadyAllocated;
|
||||
|
||||
Hnd->Buffer = (uint8_t *)vma->RequestPages(TO_PAGES(Size + 1));
|
||||
Hnd->Length = Size;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Deallocate(IPCID ID)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
if (Hnd->Buffer == nullptr || Hnd->Length == 0)
|
||||
return IPCNotAllocated;
|
||||
|
||||
vma->FreePages(Hnd->Buffer, TO_PAGES(Hnd->Length + 1));
|
||||
Hnd->Buffer = nullptr;
|
||||
Hnd->Length = 0;
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Read(IPCID ID, void *Buffer, long Size)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
if (Size < 0)
|
||||
return IPCError;
|
||||
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
if (Hnd->Listening)
|
||||
{
|
||||
debug("IPC %d is listening", ID);
|
||||
return IPCNotListening;
|
||||
}
|
||||
if (Hnd->Length < Size)
|
||||
{
|
||||
debug("IPC %d is too small", ID);
|
||||
return IPCError;
|
||||
}
|
||||
debug("IPC %d reading %d bytes", ID, Size);
|
||||
memcpy(Buffer, Hnd->Buffer, Size);
|
||||
debug("IPC read %d bytes", Size);
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
debug("IPC %d not found", ID);
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Write(IPCID ID, void *Buffer, long Size)
|
||||
{
|
||||
SmartLock(this->IPCLock);
|
||||
if (Size < 0)
|
||||
{
|
||||
debug("IPC %d is too small", ID);
|
||||
return IPCError;
|
||||
}
|
||||
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
if (!Hnd->Listening)
|
||||
{
|
||||
debug("IPC %d is NOT listening", ID);
|
||||
return IPCNotListening;
|
||||
}
|
||||
if (Hnd->Length < Size)
|
||||
{
|
||||
debug("IPC %d is too small", ID);
|
||||
return IPCError;
|
||||
}
|
||||
debug("IPC %d writing %d bytes", ID, Size);
|
||||
memcpy(Hnd->Buffer, Buffer, Size);
|
||||
Hnd->Listening = false;
|
||||
debug("IPC %d wrote %d bytes and now is %s", ID, Size, Hnd->Listening ? "listening" : "ready");
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
debug("IPC %d not found", ID);
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Listen(IPCID ID, bool Listen)
|
||||
{
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
Hnd->Listening = Listen;
|
||||
debug("IPC %d is now set to %s", ID, Listen ? "listening" : "ready");
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
debug("IPC %d not found", ID);
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCErrorCode IPC::Wait(IPCID ID)
|
||||
{
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (Hnd->ID == ID)
|
||||
{
|
||||
if (!CPU::Interrupts())
|
||||
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->Yield();
|
||||
debug("IPC %d is ready", ID);
|
||||
return IPCSuccess;
|
||||
}
|
||||
}
|
||||
debug("IPC %d not found", ID);
|
||||
return IPCIDNotFound;
|
||||
}
|
||||
|
||||
IPCHandle *IPC::SearchByToken(char UniqueToken[16])
|
||||
{
|
||||
foreach (auto Hnd in Handles)
|
||||
{
|
||||
if (strcmp(Hnd->Node->Name, UniqueToken) == 0)
|
||||
{
|
||||
debug("Found IPC with token %s", UniqueToken);
|
||||
return Hnd;
|
||||
}
|
||||
}
|
||||
debug("Failed to find IPC with token %s", UniqueToken);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int IPC::HandleSyscall(long Command, long Type, int ID, int Flags, void *Buffer, size_t Size)
|
||||
{
|
||||
switch (Command)
|
||||
{
|
||||
case IPC_CREATE:
|
||||
{
|
||||
char UniqueToken[16];
|
||||
if (Buffer != nullptr)
|
||||
strcpy(UniqueToken, (char *)Buffer);
|
||||
else
|
||||
snprintf(UniqueToken, 16, "IPC_%d", ID);
|
||||
IPCHandle *Hnd = this->Create((IPCType)Type, UniqueToken);
|
||||
this->Allocate(Hnd->ID, Size ? Size : PAGE_SIZE);
|
||||
return Hnd->ID;
|
||||
}
|
||||
case IPC_READ:
|
||||
return this->Read(ID, Buffer, Size);
|
||||
case IPC_WRITE:
|
||||
return TaskManager->GetProcessByID(Flags)->IPC->Write(ID, Buffer, Size);
|
||||
case IPC_DELETE:
|
||||
{
|
||||
this->Deallocate(ID);
|
||||
return this->Destroy(ID);
|
||||
}
|
||||
case IPC_WAIT:
|
||||
return this->Wait(ID);
|
||||
case IPC_LISTEN:
|
||||
return this->Listen(ID, Flags);
|
||||
default:
|
||||
return IPCInvalidCommand;
|
||||
}
|
||||
return IPCError;
|
||||
}
|
||||
|
||||
IPC::IPC(void *Process)
|
||||
{
|
||||
Tasking::PCB *pcb = (Tasking::PCB *)Process;
|
||||
this->Process = Process;
|
||||
this->vma = new Memory::VirtualMemoryArea(pcb->PageTable);
|
||||
IPCNode = fs->Create("ipc", vfs::NodeType::DIRECTORY,
|
||||
pcb->ProcessDirectory);
|
||||
}
|
||||
|
||||
IPC::~IPC()
|
||||
{
|
||||
fs->Delete(IPCNode, true);
|
||||
delete this->vma, this->vma = nullptr;
|
||||
}
|
||||
}
|
@ -44,12 +44,29 @@
|
||||
#define tskdbg(m, ...)
|
||||
#endif
|
||||
|
||||
using namespace InterProcessCommunication;
|
||||
using namespace vfs;
|
||||
using vfs::NodeType;
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
int PCB::SendSignal(int sig)
|
||||
{
|
||||
return this->Signals->SendSignal(sig);
|
||||
}
|
||||
|
||||
void PCB::SetState(TaskState state)
|
||||
{
|
||||
this->State.store(state);
|
||||
if (this->Threads.size() == 1)
|
||||
this->Threads.front()->State.store(state);
|
||||
}
|
||||
|
||||
void PCB::SetExitCode(int code)
|
||||
{
|
||||
this->ExitCode.store(code);
|
||||
if (this->Threads.size() == 1)
|
||||
this->Threads.front()->ExitCode.store(code);
|
||||
}
|
||||
|
||||
void PCB::Rename(const char *name)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
@ -74,6 +91,25 @@ namespace Tasking
|
||||
trace("Setting working directory of process %s to %#lx (%s)",
|
||||
this->Name, node, node->Name);
|
||||
CurrentWorkingDirectory = node;
|
||||
Node *cwd = fs->GetNodeFromPath("cwd", this);
|
||||
if (cwd)
|
||||
delete cwd;
|
||||
cwd = fs->CreateLink("cwd", node->FullPath, this);
|
||||
if (cwd == nullptr)
|
||||
error("Failed to create cwd link");
|
||||
}
|
||||
|
||||
void PCB::SetExe(const char *path)
|
||||
{
|
||||
trace("Setting exe %s to %s",
|
||||
this->Name, path);
|
||||
Executable = fs->GetNodeFromPath(path);
|
||||
Node *exe = fs->GetNodeFromPath("exe", this);
|
||||
if (exe)
|
||||
delete exe;
|
||||
exe = fs->CreateLink("exe", Executable->FullPath, this);
|
||||
if (exe == nullptr)
|
||||
error("Failed to create exe link");
|
||||
}
|
||||
|
||||
size_t PCB::GetSize()
|
||||
@ -92,11 +128,12 @@ namespace Tasking
|
||||
|
||||
PCB::PCB(Task *ctx, PCB *Parent, const char *Name,
|
||||
TaskExecutionMode ExecutionMode, void *Image,
|
||||
bool DoNotCreatePageTable,
|
||||
bool UseKernelPageTable,
|
||||
uint16_t UserID, uint16_t GroupID)
|
||||
: Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY)
|
||||
{
|
||||
debug("+ %#lx", this);
|
||||
|
||||
|
||||
assert(ctx != nullptr);
|
||||
assert(Name != nullptr);
|
||||
assert(strlen(Name) > 0);
|
||||
@ -154,36 +191,25 @@ namespace Tasking
|
||||
assert(false);
|
||||
}
|
||||
|
||||
char ProcFSName[12];
|
||||
sprintf(ProcFSName, "%d", this->ID);
|
||||
this->ProcessDirectory = fs->Create(ProcFSName, DIRECTORY, ProcFS);
|
||||
this->FileDescriptors = new FileDescriptorTable(this);
|
||||
|
||||
/* If create page table */
|
||||
if (DoNotCreatePageTable == false)
|
||||
if (UseKernelPageTable == false)
|
||||
{
|
||||
OwnPageTable = true;
|
||||
|
||||
size_t PTPgs = TO_PAGES(sizeof(Memory::PageTable) + 1);
|
||||
this->PageTable = (Memory::PageTable *)KernelAllocator.RequestPages(PTPgs);
|
||||
memcpy(this->PageTable, KernelPageTable, sizeof(Memory::PageTable));
|
||||
|
||||
this->PageTable = KernelPageTable->Fork();
|
||||
debug("Process %s(%d) has page table at %#lx",
|
||||
this->Name, this->ID, this->PageTable);
|
||||
}
|
||||
else
|
||||
this->PageTable = KernelPageTable;
|
||||
|
||||
this->vma = new Memory::VirtualMemoryArea(this->PageTable);
|
||||
this->ProgramBreak = new Memory::ProgramBreak(this->PageTable, this->vma);
|
||||
this->IPC = new class IPC((void *)this);
|
||||
this->Signals = new Signal(this);
|
||||
|
||||
if (Image)
|
||||
{
|
||||
this->ELFSymbolTable = new SymbolResolver::Symbols((uintptr_t)Image);
|
||||
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
|
||||
}
|
||||
|
||||
if (Parent)
|
||||
Parent->Children.push_back(this);
|
||||
|
||||
debug("Process page table: %#lx", this->PageTable);
|
||||
debug("Created %s process \"%s\"(%d). Parent \"%s\"(%d)",
|
||||
@ -198,9 +224,13 @@ namespace Tasking
|
||||
this->AllocatedMemory += FROM_PAGES(TO_PAGES(sizeof(Memory::PageTable) + 1));
|
||||
this->AllocatedMemory += sizeof(Memory::VirtualMemoryArea);
|
||||
this->AllocatedMemory += sizeof(Memory::ProgramBreak);
|
||||
this->AllocatedMemory += sizeof(class IPC);
|
||||
this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
|
||||
this->AllocatedMemory += sizeof(Signal);
|
||||
|
||||
this->Info.SpawnTime = TimeManager->GetCounter();
|
||||
|
||||
if (Parent)
|
||||
Parent->Children.push_back(this);
|
||||
ctx->ProcessList.push_back(this);
|
||||
}
|
||||
|
||||
@ -221,8 +251,8 @@ namespace Tasking
|
||||
if (this->ELFSymbolTable)
|
||||
delete this->ELFSymbolTable;
|
||||
|
||||
debug("Freeing IPC");
|
||||
delete this->IPC;
|
||||
debug("Freeing signals");
|
||||
delete this->Signals;
|
||||
|
||||
debug("Freeing allocated memory");
|
||||
delete this->ProgramBreak;
|
||||
@ -242,14 +272,31 @@ namespace Tasking
|
||||
|
||||
/* Exit all children processes */
|
||||
foreach (auto pcb in this->Children)
|
||||
{
|
||||
if (pcb == nullptr)
|
||||
{
|
||||
warn("Process is null? Kernel bug");
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Destroying child process \"%s\"(%d)",
|
||||
pcb->Name, pcb->ID);
|
||||
delete pcb;
|
||||
}
|
||||
|
||||
/* Exit all threads */
|
||||
foreach (auto tcb in this->Threads)
|
||||
delete tcb;
|
||||
{
|
||||
if (tcb == nullptr)
|
||||
{
|
||||
warn("Thread is null? Kernel bug");
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Removing /proc/%d", this->ID);
|
||||
fs->Delete(this->ProcessDirectory, true);
|
||||
debug("Destroying thread \"%s\"(%d)",
|
||||
tcb->Name, tcb->ID);
|
||||
delete tcb;
|
||||
}
|
||||
|
||||
/* Free Name */
|
||||
delete[] this->Name;
|
||||
@ -257,11 +304,14 @@ namespace Tasking
|
||||
debug("Removing from parent process");
|
||||
if (this->Parent)
|
||||
{
|
||||
std::vector<Tasking::PCB *> &pChild = this->Parent->Children;
|
||||
std::list<Tasking::PCB *> &pChild = this->Parent->Children;
|
||||
|
||||
pChild.erase(std::find(pChild.begin(),
|
||||
pChild.end(),
|
||||
this));
|
||||
}
|
||||
|
||||
debug("Process \"%s\"(%d) destroyed",
|
||||
this->Name, this->ID);
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,12 @@ extern "C" SafeFunction NIF void TaskingScheduler_OneShot(int TimeSlice)
|
||||
{
|
||||
if (TimeSlice == 0)
|
||||
TimeSlice = Tasking::TaskPriority::Normal;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (DebuggerIsAttached)
|
||||
TimeSlice += 10;
|
||||
#endif
|
||||
|
||||
#if defined(a86)
|
||||
((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice);
|
||||
#elif defined(aa64)
|
||||
@ -348,13 +354,16 @@ namespace Tasking
|
||||
|
||||
if (process->Threads.size() == 1)
|
||||
{
|
||||
process->State.exchange(process->Threads[0]->State.load());
|
||||
process->State.exchange(process->Threads.front()->State.load());
|
||||
continue;
|
||||
}
|
||||
|
||||
bool AllThreadsSleeping = true;
|
||||
foreach (auto thread in process->Threads)
|
||||
{
|
||||
if (thread->State.load() == TaskState::Terminated)
|
||||
continue;
|
||||
|
||||
if (thread->State.load() != TaskState::Sleeping)
|
||||
{
|
||||
AllThreadsSleeping = false;
|
||||
@ -409,6 +418,24 @@ namespace Tasking
|
||||
}
|
||||
}
|
||||
|
||||
SafeFunction NIF void Task::CleanupTerminated()
|
||||
{
|
||||
foreach (auto pcb in ProcessList)
|
||||
{
|
||||
if (pcb->State.load() == TaskState::Terminated)
|
||||
{
|
||||
delete pcb;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (TCB *tcb in pcb->Threads)
|
||||
{
|
||||
if (tcb->State == Terminated)
|
||||
delete tcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
int SuccessSource = 0;
|
||||
int sanity;
|
||||
@ -434,6 +461,7 @@ namespace Tasking
|
||||
"Block",
|
||||
"Wait",
|
||||
|
||||
"Core",
|
||||
"Zombie",
|
||||
"Terminated",
|
||||
};
|
||||
@ -485,11 +513,7 @@ namespace Tasking
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef a64
|
||||
SafeFunction NIF void Task::Schedule(CPU::x64::TrapFrame *Frame)
|
||||
#else
|
||||
SafeFunction NIF void Task::Schedule(CPU::x32::TrapFrame *Frame)
|
||||
#endif
|
||||
SafeFunction NIF void Task::Schedule(CPU::TrapFrame *Frame)
|
||||
{
|
||||
if (unlikely(StopScheduler))
|
||||
{
|
||||
@ -497,43 +521,15 @@ namespace Tasking
|
||||
return;
|
||||
}
|
||||
bool ProcessNotChanged = false;
|
||||
/* Restore kernel page table for safety reasons. */
|
||||
#ifdef a64
|
||||
CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable});
|
||||
#else
|
||||
CPU::x32::writecr3({.raw = (uint32_t)KernelPageTable});
|
||||
#endif
|
||||
/* Restore kernel page table for safety reasons. */
|
||||
if (!SchedulerUpdateTrapFrame)
|
||||
KernelPageTable->Update();
|
||||
uint64_t SchedTmpTicks = TimeManager->GetCounter();
|
||||
this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load()));
|
||||
CPUData *CurrentCPU = GetCurrentCPU();
|
||||
this->LastCore.store(CurrentCPU->ID);
|
||||
schedbg("Scheduler called on CPU %d.", CurrentCPU->ID);
|
||||
|
||||
#ifdef DEBUG_SCHEDULER
|
||||
{
|
||||
schedbg("================================================================");
|
||||
schedbg("State: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term");
|
||||
schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber);
|
||||
size_t ds;
|
||||
asmv("mov %%ds, %0"
|
||||
: "=r"(ds));
|
||||
schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx",
|
||||
CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
|
||||
Frame->ss, Frame->cs, ds);
|
||||
schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx",
|
||||
Frame->r8, Frame->r9, Frame->r10, Frame->r11);
|
||||
schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx",
|
||||
Frame->r12, Frame->r13, Frame->r14, Frame->r15);
|
||||
schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx",
|
||||
Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
|
||||
schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx",
|
||||
Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
|
||||
schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx",
|
||||
Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode);
|
||||
schedbg("================================================================");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) ||
|
||||
InvalidTCB(CurrentCPU->CurrentThread.load())))
|
||||
{
|
||||
@ -563,6 +559,9 @@ namespace Tasking
|
||||
if (CurrentCPU->CurrentThread->State.load() == TaskState::Running)
|
||||
CurrentCPU->CurrentThread->State.store(TaskState::Ready);
|
||||
|
||||
this->CleanupTerminated();
|
||||
schedbg("Passed CleanupTerminated");
|
||||
|
||||
this->UpdateProcessState();
|
||||
schedbg("Passed UpdateProcessState");
|
||||
|
||||
@ -571,8 +570,13 @@ namespace Tasking
|
||||
|
||||
if (this->SchedulerUpdateTrapFrame)
|
||||
{
|
||||
debug("Updating trap frame");
|
||||
this->SchedulerUpdateTrapFrame = false;
|
||||
goto Success;
|
||||
CurrentCPU->CurrentProcess->State.store(TaskState::Running);
|
||||
CurrentCPU->CurrentThread->State.store(TaskState::Running);
|
||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->GetNextAvailableThread(CurrentCPU))
|
||||
@ -637,20 +641,13 @@ namespace Tasking
|
||||
|
||||
*Frame = CurrentCPU->CurrentThread->Registers;
|
||||
|
||||
for (size_t i = 0; i < (sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0])) - 1; i++)
|
||||
CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i];
|
||||
|
||||
#ifdef a64
|
||||
CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip;
|
||||
|
||||
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
|
||||
CPU::x64::fxrstor(&CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||
#else
|
||||
CurrentCPU->CurrentThread->IPHistory[0] = Frame->eip;
|
||||
|
||||
GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop()));
|
||||
CPU::x32::fxrstor(&CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase);
|
||||
@ -658,6 +655,8 @@ namespace Tasking
|
||||
CPU::x32::wrmsr(CPU::x32::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||
#endif
|
||||
|
||||
CurrentCPU->CurrentProcess->Signals->HandleSignal(Frame);
|
||||
|
||||
#ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER
|
||||
OnScreenTaskManagerUpdate();
|
||||
#endif
|
||||
@ -682,7 +681,8 @@ namespace Tasking
|
||||
(&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter();
|
||||
TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority);
|
||||
|
||||
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||
if (CurrentCPU->CurrentThread->Security.IsDebugEnabled &&
|
||||
CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled)
|
||||
{
|
||||
#ifdef a64
|
||||
trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx",
|
||||
@ -722,18 +722,10 @@ namespace Tasking
|
||||
|
||||
End:
|
||||
this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks));
|
||||
#ifdef a64
|
||||
CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
|
||||
#else
|
||||
CPU::x32::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable});
|
||||
#endif
|
||||
CurrentCPU->CurrentProcess->PageTable->Update();
|
||||
}
|
||||
|
||||
#ifdef a64
|
||||
SafeFunction NIF void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
|
||||
#else
|
||||
SafeFunction NIF void Task::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
|
||||
#endif
|
||||
SafeFunction NIF void Task::OnInterruptReceived(CPU::TrapFrame *Frame)
|
||||
{
|
||||
SmartCriticalSection(SchedulerLock);
|
||||
this->Schedule(Frame);
|
||||
@ -759,11 +751,11 @@ namespace Tasking
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::Schedule(CPU::aarch64::TrapFrame *Frame)
|
||||
SafeFunction void Task::Schedule(CPU::TrapFrame *Frame)
|
||||
{
|
||||
fixme("unimplemented");
|
||||
}
|
||||
|
||||
SafeFunction void Task::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) { this->Schedule(Frame); }
|
||||
SafeFunction void Task::OnInterruptReceived(CPU::TrapFrame *Frame) { this->Schedule(Frame); }
|
||||
#endif
|
||||
}
|
||||
|
732
tasking/signal.cpp
Normal file
732
tasking/signal.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
/*
|
||||
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 <signal.hpp>
|
||||
#include <dumper.hpp>
|
||||
#include <task.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(a64)
|
||||
#include "../arch/amd64/cpu/gdt.hpp"
|
||||
#elif defined(a32)
|
||||
#include "../arch/i386/cpu/gdt.hpp"
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *lSigStr[] = {
|
||||
"SIGHUP",
|
||||
"SIGINT",
|
||||
"SIGQUIT",
|
||||
"SIGILL",
|
||||
"SIGTRAP",
|
||||
"SIGABRT",
|
||||
"SIGBUS",
|
||||
"SIGFPE",
|
||||
"SIGKILL",
|
||||
"SIGUSR1",
|
||||
"SIGSEGV",
|
||||
"SIGUSR2",
|
||||
"SIGPIPE",
|
||||
"SIGALRM",
|
||||
"SIGTERM",
|
||||
"SIGSTKFLT",
|
||||
"SIGCHLD",
|
||||
"SIGCONT",
|
||||
"SIGSTOP",
|
||||
"SIGTSTP",
|
||||
"SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGURG",
|
||||
"SIGXCPU",
|
||||
"SIGXFSZ",
|
||||
"SIGVTALRM",
|
||||
"SIGPROF",
|
||||
"SIGWINCH",
|
||||
"SIGPOLL",
|
||||
"SIGPWR",
|
||||
"SIGSYS",
|
||||
"SIGUNUSED",
|
||||
};
|
||||
|
||||
const char *sigStr[] = {
|
||||
"INVALID ",
|
||||
"SIGABRT ",
|
||||
"SIGALRM ",
|
||||
"SIGBUS ",
|
||||
"SIGCHLD ",
|
||||
"SIGCONT ",
|
||||
"SIGFPE ",
|
||||
"SIGHUP ",
|
||||
"SIGILL ",
|
||||
"SIGINT ",
|
||||
"SIGKILL ",
|
||||
"SIGPIPE ",
|
||||
"SIGQUIT ",
|
||||
"SIGSEGV ",
|
||||
"SIGSTOP ",
|
||||
"SIGTERM ",
|
||||
"SIGTSTP ",
|
||||
"SIGTTIN ",
|
||||
"SIGTTOU ",
|
||||
"SIGUSR1 ",
|
||||
"SIGUSR2 ",
|
||||
"SIGPOLL ",
|
||||
"SIGPROF ",
|
||||
"SIGSYS ",
|
||||
"SIGTRAP ",
|
||||
"SIGURG ",
|
||||
"SIGVTALRM",
|
||||
"SIGXCPU ",
|
||||
"SIGXFSZ ",
|
||||
"SIGRSV1 ",
|
||||
"SIGRSV2 ",
|
||||
};
|
||||
|
||||
const char *dispStr[] = {
|
||||
"SIG_TERM",
|
||||
"SIG_IGN ",
|
||||
"SIG_CORE",
|
||||
"SIG_STOP",
|
||||
"SIG_CONT",
|
||||
};
|
||||
#endif
|
||||
|
||||
extern "C" uintptr_t _sig_native_trampoline_start, _sig_native_trampoline_end;
|
||||
extern "C" uintptr_t _sig_linux_trampoline_start, _sig_linux_trampoline_end;
|
||||
|
||||
static const struct
|
||||
{
|
||||
int linuxSignal;
|
||||
int nativeSignal;
|
||||
} signalMapping[] = {
|
||||
{linux_SIGHUP, SIGHUP},
|
||||
{linux_SIGINT, SIGINT},
|
||||
{linux_SIGQUIT, SIGQUIT},
|
||||
{linux_SIGILL, SIGILL},
|
||||
{linux_SIGTRAP, SIGTRAP},
|
||||
{linux_SIGABRT, SIGABRT},
|
||||
{linux_SIGBUS, SIGBUS},
|
||||
{linux_SIGFPE, SIGFPE},
|
||||
{linux_SIGKILL, SIGKILL},
|
||||
{linux_SIGUSR1, SIGUSR1},
|
||||
{linux_SIGSEGV, SIGSEGV},
|
||||
{linux_SIGUSR2, SIGUSR2},
|
||||
{linux_SIGPIPE, SIGPIPE},
|
||||
{linux_SIGALRM, SIGALRM},
|
||||
{linux_SIGTERM, SIGTERM},
|
||||
{linux_SIGSTKFLT, SIGRSV1},
|
||||
{linux_SIGCHLD, SIGCHLD},
|
||||
{linux_SIGCONT, SIGCONT},
|
||||
{linux_SIGSTOP, SIGSTOP},
|
||||
{linux_SIGTSTP, SIGTSTP},
|
||||
{linux_SIGTTIN, SIGTTIN},
|
||||
{linux_SIGTTOU, SIGTTOU},
|
||||
{linux_SIGURG, SIGURG},
|
||||
{linux_SIGXCPU, SIGXCPU},
|
||||
{linux_SIGXFSZ, SIGXFSZ},
|
||||
{linux_SIGVTALRM, SIGVTALRM},
|
||||
{linux_SIGPROF, SIGPROF},
|
||||
{linux_SIGPOLL, SIGPOLL},
|
||||
{linux_SIGPWR, SIGRSV2},
|
||||
{linux_SIGSYS, SIGSYS},
|
||||
{linux_SIGUNUSED, SIGSYS},
|
||||
};
|
||||
|
||||
static_assert(linux_SIGUNUSED == SIGNAL_MAX);
|
||||
|
||||
#define CTLif(x) ConvertToLinuxIfNecessary(x)
|
||||
#define CTNif(x) ConvertToNativeIfNecessary(x)
|
||||
#define CSigTLif(x) ConvertSigsetToLinuxIfNecessary(x)
|
||||
#define CSigTNif(x) ConvertSigsetToNativeIfNecessary(x)
|
||||
|
||||
/* TODO: CTLif & CTNif may need optimization */
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
bool Signal::LinuxSig()
|
||||
{
|
||||
return ((PCB *)ctx)->Info.Compatibility == Linux;
|
||||
}
|
||||
|
||||
int Signal::ConvertToLinuxIfNecessary(int sig)
|
||||
{
|
||||
if (!LinuxSig())
|
||||
{
|
||||
debug("Not linux sig: %d", sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
foreach (auto &mapping in signalMapping)
|
||||
{
|
||||
if (mapping.nativeSignal == sig)
|
||||
{
|
||||
// debug("Converted %d to %d", sig, mapping.linuxSignal);
|
||||
return mapping.linuxSignal;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Signal::ConvertToNativeIfNecessary(int sig)
|
||||
{
|
||||
if (!LinuxSig())
|
||||
{
|
||||
debug("Not native sig: %d", sig);
|
||||
return sig;
|
||||
}
|
||||
|
||||
foreach (auto &mapping in signalMapping)
|
||||
{
|
||||
if (mapping.linuxSignal == sig)
|
||||
{
|
||||
// debug("Converted %d to %d", sig, mapping.nativeSignal);
|
||||
return mapping.nativeSignal;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
sigset_t Signal::ConvertSigsetToLinuxIfNecessary(sigset_t sig)
|
||||
{
|
||||
if (!LinuxSig())
|
||||
{
|
||||
debug("Not linux sigset: %#lx", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sigset_t ret = 0;
|
||||
for (int i = 0; i < SIGNAL_MAX; i++)
|
||||
{
|
||||
if (sig & ToFlag(i))
|
||||
ret |= ToFlag(CTLif(i));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sigset_t Signal::ConvertSigsetToNativeIfNecessary(sigset_t sig)
|
||||
{
|
||||
if (!LinuxSig())
|
||||
{
|
||||
debug("Not native sigset: %#lx", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sigset_t ret = 0;
|
||||
for (int i = 0; i < linux_SIGUNUSED; i++)
|
||||
{
|
||||
if (sig & ToFlag(i))
|
||||
ret |= ToFlag(CTNif(i));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Signal::MakeExitCode(int sig)
|
||||
{
|
||||
if (this->LinuxSig())
|
||||
return 128 + sig;
|
||||
else
|
||||
return 100 + sig;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
int Signal::AddWatcher(Signal *who, int sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
SignalInfo info;
|
||||
info.sig = sig;
|
||||
info.val.sival_ptr = who;
|
||||
|
||||
Watchers.push_back(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::RemoveWatcher(Signal *who, int sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
forItr(itr, Watchers)
|
||||
{
|
||||
if (itr->sig == sig &&
|
||||
itr->val.sival_ptr == who)
|
||||
{
|
||||
Watchers.erase(itr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int Signal::AddSignal(int sig, union sigval val)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
SignalInfo info{.sig = sig, .val = val};
|
||||
SignalQueue.push_back(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::RemoveSignal(int sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
forItr(itr, SignalQueue)
|
||||
{
|
||||
if (itr->sig == sig)
|
||||
{
|
||||
SignalQueue.erase(itr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
bool Signal::HandleSignal(CPU::TrapFrame *tf)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
if (SignalQueue.empty())
|
||||
return false;
|
||||
|
||||
/* We don't want to do this in kernel mode */
|
||||
if (unlikely(tf->cs != GDT_USER_CODE &&
|
||||
tf->cs != GDT_USER_DATA))
|
||||
{
|
||||
// debug("Not user-mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("We have %d signals to handle", SignalQueue.size());
|
||||
|
||||
SignalInfo sigI = SignalQueue.front();
|
||||
SignalQueue.erase(SignalQueue.begin());
|
||||
|
||||
uintptr_t _p_rsp = ((PCB *)ctx)->PageTable->Get(tf->rsp);
|
||||
uint64_t paRsp = _p_rsp;
|
||||
paRsp &= ~0xF; /* Align */
|
||||
paRsp -= 128; /* Red zone */
|
||||
|
||||
/* Calculate the virtual rsp */
|
||||
uintptr_t _v_rsp = tf->rsp;
|
||||
_v_rsp &= ~0xF; /* Align */
|
||||
_v_rsp -= 128; /* Red zone */
|
||||
uint64_t *vRsp = (uint64_t *)(_v_rsp - sizeof(StackInfo));
|
||||
vRsp--; /* Alignment */
|
||||
vRsp--; /* Handler Address */
|
||||
assert(!((uintptr_t)vRsp & 0xF));
|
||||
|
||||
/* Add the stack info */
|
||||
StackInfo si{};
|
||||
CPU::x64::fxsave(&si.fx);
|
||||
si.tf = *tf;
|
||||
si.GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
si.FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||
si.ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE);
|
||||
debug("gs: %#lx fs: %#lx shadow: %#lx",
|
||||
si.GSBase, si.FSBase, si.ShadowGSBase);
|
||||
si.SignalMask = SignalMask.load();
|
||||
si.Compatibility = ((PCB *)ctx)->Info.Compatibility;
|
||||
|
||||
/* Copy the stack info */
|
||||
uint64_t *pRsp = (uint64_t *)(paRsp - sizeof(StackInfo));
|
||||
memcpy(pRsp, &si, sizeof(StackInfo));
|
||||
|
||||
/* Set the handler address */
|
||||
pRsp--; /* Alignment */
|
||||
pRsp--;
|
||||
*pRsp = uint64_t(SignalAction[sigI.sig].__sa_handler.sa_handler);
|
||||
|
||||
assert(!((uintptr_t)pRsp & 0xF));
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpData("Stack Data", (void *)pRsp,
|
||||
paRsp - uint64_t(pRsp));
|
||||
debug("initial stack tf->rsp: %#lx after: %#lx",
|
||||
tf->rsp, uint64_t(vRsp));
|
||||
debug("sig: %d -> %d", sigI.sig, CTLif(sigI.sig));
|
||||
#endif
|
||||
|
||||
tf->rsp = uint64_t(vRsp);
|
||||
tf->rip = uint64_t(TrampAddr);
|
||||
tf->rdi = CTLif(sigI.sig);
|
||||
tf->rsi = uint64_t(sigI.val.sival_ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Signal::RestoreHandleSignal(SyscallsFrame *sf)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
debug("Restoring signal handler");
|
||||
gsTCB *gs = (gsTCB *)CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
uint64_t *sp = (uint64_t *)((PCB *)ctx)->PageTable->Get(gs->TempStack);
|
||||
sp++; /* Alignment */
|
||||
sp++; /* Handler Address */
|
||||
|
||||
assert(!((uintptr_t)sp & 0xF));
|
||||
|
||||
StackInfo *si = (StackInfo *)sp;
|
||||
assert(si != nullptr);
|
||||
|
||||
sf->r15 = si->tf.r15;
|
||||
sf->r14 = si->tf.r14;
|
||||
sf->r13 = si->tf.r13;
|
||||
sf->r12 = si->tf.r12;
|
||||
sf->r11 = si->tf.r11;
|
||||
sf->r10 = si->tf.r10;
|
||||
sf->r9 = si->tf.r9;
|
||||
sf->r8 = si->tf.r8;
|
||||
sf->rbp = si->tf.rbp;
|
||||
sf->rdi = si->tf.rdi;
|
||||
sf->rsi = si->tf.rsi;
|
||||
sf->rdx = si->tf.rdx;
|
||||
sf->rcx = si->tf.rcx;
|
||||
sf->rbx = si->tf.rbx;
|
||||
sf->rax = si->tf.rax;
|
||||
sf->Flags = si->tf.rflags.raw;
|
||||
sf->ReturnAddress = si->tf.rip;
|
||||
gs->TempStack = si->tf.rsp;
|
||||
|
||||
SignalMask.store(si->SignalMask);
|
||||
|
||||
CPU::x64::fxrstor(&si->fx);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, si->ShadowGSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, si->FSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, si->GSBase);
|
||||
debug("gs: %#lx fs: %#lx shadow: %#lx",
|
||||
si->GSBase, si->FSBase, si->ShadowGSBase);
|
||||
|
||||
// ((PCB *)ctx)->GetContext()->Yield();
|
||||
// __builtin_unreachable();
|
||||
/* Return because we will restore at sysretq */
|
||||
}
|
||||
|
||||
sigset_t Signal::Block(sigset_t sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
sig = CSigTNif(sig);
|
||||
sigset_t oldMask = SignalMask.fetch_or(sig);
|
||||
debug("%#lx -> %#lx", oldMask, SignalMask);
|
||||
return CSigTLif(oldMask);
|
||||
}
|
||||
|
||||
sigset_t Signal::Unblock(sigset_t sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
sig = CSigTNif(sig);
|
||||
sigset_t oldMask = SignalMask.fetch_and(~sig);
|
||||
debug("%#lx -> %#lx", oldMask, SignalMask);
|
||||
return CSigTLif(oldMask);
|
||||
}
|
||||
|
||||
sigset_t Signal::SetMask(sigset_t sig)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
sig = CSigTNif(sig);
|
||||
sigset_t oldMask = SignalMask.exchange(sig);
|
||||
debug("%#lx -> %#lx", oldMask, SignalMask);
|
||||
return CSigTLif(oldMask);
|
||||
}
|
||||
|
||||
int Signal::SetAction(int sig, const sigaction act)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0]))
|
||||
return -EINVAL;
|
||||
|
||||
sig = CTNif(sig);
|
||||
|
||||
SignalAction[sig].__sa_handler.sa_handler = act.__sa_handler.sa_handler;
|
||||
SignalAction[sig].sa_mask = act.sa_mask;
|
||||
SignalAction[sig].sa_flags = act.sa_flags;
|
||||
debug("Set action for %s with handler %#lx, mask %#lx and flags %#lx",
|
||||
LinuxSig() ? lSigStr[sig] : sigStr[sig],
|
||||
SignalAction[sig].__sa_handler.sa_handler,
|
||||
SignalAction[sig].sa_mask,
|
||||
SignalAction[sig].sa_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::GetAction(int sig, sigaction *act)
|
||||
{
|
||||
SmartLock(SignalLock);
|
||||
|
||||
if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0]))
|
||||
return -EINVAL;
|
||||
|
||||
sig = CTNif(sig);
|
||||
|
||||
act->__sa_handler.sa_handler = SignalAction[sig].__sa_handler.sa_handler;
|
||||
act->sa_mask = SignalAction[sig].sa_mask;
|
||||
act->sa_flags = SignalAction[sig].sa_flags;
|
||||
debug("Got action for %s with handler %#lx, mask %#lx and flags %#lx",
|
||||
LinuxSig() ? lSigStr[sig] : sigStr[sig],
|
||||
SignalAction[sig].__sa_handler.sa_handler,
|
||||
SignalAction[sig].sa_mask,
|
||||
SignalAction[sig].sa_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::SendSignal(int sig, union sigval val)
|
||||
{
|
||||
PCB *pcb = (PCB *)ctx;
|
||||
sig = CTNif(sig);
|
||||
LastSignal = (Signals)sig;
|
||||
|
||||
debug("Sending signal %s to %s(%d)",
|
||||
sigStr[sig], pcb->Name, pcb->ID);
|
||||
|
||||
if (SignalAction[sig].__sa_handler.sa_handler)
|
||||
{
|
||||
if (pcb->Security.ExecutionMode == Kernel)
|
||||
{
|
||||
info("Kernel processes cannot have signal handlers");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug("sa_handler: %#lx",
|
||||
SignalAction[sig].__sa_handler.sa_handler);
|
||||
debug("Adding signal %s to queue", sigStr[sig]);
|
||||
goto CompleteSignal;
|
||||
}
|
||||
|
||||
debug("Signal disposition: %s", dispStr[sigDisp[sig]]);
|
||||
switch (sigDisp[sig])
|
||||
{
|
||||
case SIG_TERM:
|
||||
{
|
||||
if (unlikely(pcb->Security.IsCritical))
|
||||
{
|
||||
debug("Critical process %s received signal %s(%d): Terminated",
|
||||
pcb->Name, sigStr[sig], sig);
|
||||
// int3;
|
||||
}
|
||||
|
||||
pcb->SetExitCode(MakeExitCode(sig));
|
||||
debug("We have %d watchers", this->Watchers.size());
|
||||
if (this->Watchers.size() > 0)
|
||||
pcb->SetState(Zombie);
|
||||
else
|
||||
pcb->SetState(Terminated);
|
||||
break;
|
||||
}
|
||||
case SIG_IGN:
|
||||
{
|
||||
debug("Ignoring signal %d", sig);
|
||||
return 0;
|
||||
}
|
||||
case SIG_CORE:
|
||||
{
|
||||
fixme("core dump");
|
||||
|
||||
if (unlikely(pcb->Security.IsCritical))
|
||||
{
|
||||
debug("Critical process %s received signal %s(%d): Core dumped",
|
||||
pcb->Name, sigStr[sig], sig);
|
||||
// int3;
|
||||
}
|
||||
|
||||
pcb->SetExitCode(MakeExitCode(sig));
|
||||
debug("We have %d watchers", this->Watchers.size());
|
||||
if (this->Watchers.size() > 0)
|
||||
pcb->SetState(CoreDump);
|
||||
else
|
||||
pcb->SetState(Terminated);
|
||||
break;
|
||||
}
|
||||
case SIG_STOP:
|
||||
{
|
||||
pcb->SetState(Stopped);
|
||||
break;
|
||||
}
|
||||
case SIG_CONT:
|
||||
{
|
||||
pcb->SetState(Ready);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid signal disposition");
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
CompleteSignal:
|
||||
if (pcb->Security.ExecutionMode == Kernel)
|
||||
{
|
||||
debug("Kernel process %s received signal %s(%d)! Ignoring... (with exceptions)",
|
||||
pcb->Name, sigStr[sig], sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(TrampAddr == nullptr))
|
||||
{
|
||||
debug("Trampoline not set up yet");
|
||||
switch (thisThread->Info.Compatibility)
|
||||
{
|
||||
case Native:
|
||||
{
|
||||
debug("%#lx - %#lx",
|
||||
&_sig_native_trampoline_end,
|
||||
&_sig_native_trampoline_start);
|
||||
|
||||
TrampSz = (size_t)&_sig_native_trampoline_end -
|
||||
(size_t)&_sig_native_trampoline_start;
|
||||
TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true);
|
||||
memcpy((void *)TrampAddr,
|
||||
(void *)&_sig_native_trampoline_start,
|
||||
TrampSz);
|
||||
debug("Trampoline at %#lx with size %lld",
|
||||
TrampAddr, TrampSz);
|
||||
break;
|
||||
}
|
||||
case Linux:
|
||||
{
|
||||
debug("%#lx - %#lx",
|
||||
&_sig_linux_trampoline_end,
|
||||
&_sig_linux_trampoline_start);
|
||||
|
||||
TrampSz = (size_t)&_sig_linux_trampoline_end -
|
||||
(size_t)&_sig_linux_trampoline_start;
|
||||
TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true);
|
||||
memcpy((void *)TrampAddr,
|
||||
(void *)&_sig_linux_trampoline_start,
|
||||
TrampSz);
|
||||
debug("Trampoline at %#lx with size %lld",
|
||||
TrampAddr, TrampSz);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
assert(!"Not implemented");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("Signal %s(%d) completed", sigStr[sig], sig);
|
||||
if (sigDisp[sig] != SIG_IGN)
|
||||
{
|
||||
foreach (auto info in Watchers)
|
||||
{
|
||||
Signal *who = (Signal *)info.val.sival_ptr;
|
||||
assert(who != nullptr);
|
||||
debug("Sending SIGCHLD to %s(%d)",
|
||||
((PCB *)who->GetContext())->Name,
|
||||
((PCB *)who->GetContext())->ID);
|
||||
who->SendSignal(SIGCHLD, val);
|
||||
}
|
||||
}
|
||||
|
||||
debug("Adding signal to queue");
|
||||
SignalQueue.push_back({.sig = sig, .val = val});
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::WaitAnySignal()
|
||||
{
|
||||
/* Sleep until a signal that terminated or invokes
|
||||
the signal catch function */
|
||||
|
||||
debug("Waiting for any signal");
|
||||
|
||||
size_t oldSize = SignalQueue.size();
|
||||
Reset:
|
||||
while (SignalQueue.size() == oldSize)
|
||||
TaskManager->Yield();
|
||||
|
||||
if (SignalQueue.size() > oldSize)
|
||||
{
|
||||
debug("Added signal to queue %d > %d",
|
||||
SignalQueue.size(), oldSize);
|
||||
oldSize = SignalQueue.size();
|
||||
goto Reset;
|
||||
}
|
||||
|
||||
debug("Signal received");
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
int Signal::WaitSignal(int sig, union sigval *val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Signal::WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Signal::Signal(void *ctx)
|
||||
{
|
||||
assert(ctx != nullptr);
|
||||
this->ctx = ctx;
|
||||
|
||||
sigDisp[SIG_NULL] = SIG_IGN;
|
||||
sigDisp[SIGABRT] = SIG_CORE;
|
||||
sigDisp[SIGALRM] = SIG_TERM;
|
||||
sigDisp[SIGBUS] = SIG_CORE;
|
||||
sigDisp[SIGCHLD] = SIG_IGN;
|
||||
sigDisp[SIGCONT] = SIG_CONT;
|
||||
sigDisp[SIGFPE] = SIG_CORE;
|
||||
sigDisp[SIGHUP] = SIG_TERM;
|
||||
sigDisp[SIGILL] = SIG_CORE;
|
||||
sigDisp[SIGINT] = SIG_TERM;
|
||||
sigDisp[SIGKILL] = SIG_TERM;
|
||||
sigDisp[SIGPIPE] = SIG_TERM;
|
||||
sigDisp[SIGQUIT] = SIG_TERM;
|
||||
sigDisp[SIGSEGV] = SIG_CORE;
|
||||
sigDisp[SIGSTOP] = SIG_STOP;
|
||||
sigDisp[SIGTERM] = SIG_TERM;
|
||||
sigDisp[SIGTSTP] = SIG_STOP;
|
||||
sigDisp[SIGTTIN] = SIG_STOP;
|
||||
sigDisp[SIGTTOU] = SIG_STOP;
|
||||
sigDisp[SIGUSR1] = SIG_TERM;
|
||||
sigDisp[SIGUSR2] = SIG_TERM;
|
||||
sigDisp[SIGPOLL] = SIG_TERM;
|
||||
sigDisp[SIGPROF] = SIG_TERM;
|
||||
sigDisp[SIGSYS] = SIG_CORE;
|
||||
sigDisp[SIGTRAP] = SIG_CORE;
|
||||
sigDisp[SIGURG] = SIG_IGN;
|
||||
sigDisp[SIGVTALRM] = SIG_TERM;
|
||||
sigDisp[SIGXCPU] = SIG_CORE;
|
||||
sigDisp[SIGXFSZ] = SIG_CORE;
|
||||
|
||||
#ifdef DEBUG
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
{
|
||||
if (LinuxSig())
|
||||
{
|
||||
for (int i = 0; i <= linux_SIGUNUSED; i++)
|
||||
debug("%s: %s",
|
||||
lSigStr[i],
|
||||
dispStr[sigDisp[i]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < SIGNAL_MAX; i++)
|
||||
debug("%s: %s",
|
||||
sigStr[i],
|
||||
dispStr[sigDisp[i]]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Signal::~Signal() {}
|
||||
}
|
170
tasking/task.cpp
170
tasking/task.cpp
@ -103,11 +103,6 @@ namespace Tasking
|
||||
|
||||
SafeFunction bool Task::RemoveThread(TCB *Thread)
|
||||
{
|
||||
if (Thread->KeepInMemory.load() == true)
|
||||
return false;
|
||||
if (Thread->KeepTime > TimeManager->GetCounter())
|
||||
return false;
|
||||
|
||||
debug("Thread \"%s\"(%d) removed from process \"%s\"(%d)",
|
||||
Thread->Name, Thread->ID, Thread->Parent->Name,
|
||||
Thread->Parent->ID);
|
||||
@ -123,11 +118,6 @@ namespace Tasking
|
||||
|
||||
if (Process->State == Terminated)
|
||||
{
|
||||
if (Process->KeepInMemory.load() == true)
|
||||
return false;
|
||||
if (Process->KeepTime > TimeManager->GetCounter())
|
||||
return false;
|
||||
|
||||
delete Process;
|
||||
return true;
|
||||
}
|
||||
@ -201,7 +191,8 @@ namespace Tasking
|
||||
pcb->Name, pcb->ID);
|
||||
|
||||
while (pcb->State != TaskState::Terminated &&
|
||||
pcb->State != TaskState::Zombie)
|
||||
pcb->State != TaskState::Zombie &&
|
||||
pcb->State != TaskState::CoreDump)
|
||||
this->Yield();
|
||||
}
|
||||
|
||||
@ -217,7 +208,8 @@ namespace Tasking
|
||||
tcb->Name, tcb->ID);
|
||||
|
||||
while (tcb->State != TaskState::Terminated &&
|
||||
tcb->State != TaskState::Zombie)
|
||||
tcb->State != TaskState::Zombie &&
|
||||
tcb->State != TaskState::CoreDump)
|
||||
this->Yield();
|
||||
}
|
||||
|
||||
@ -254,14 +246,14 @@ namespace Tasking
|
||||
void Task::Sleep(uint64_t Milliseconds, bool NoSwitch)
|
||||
{
|
||||
TCB *thread = this->GetCurrentThread();
|
||||
PCB *process = this->GetCurrentProcess();
|
||||
PCB *process = thread->Parent;
|
||||
|
||||
thread->State = TaskState::Sleeping;
|
||||
thread->SetState(TaskState::Sleeping);
|
||||
|
||||
{
|
||||
SmartLock(TaskingLock);
|
||||
if (process->Threads.size() == 1)
|
||||
process->State = TaskState::Sleeping;
|
||||
process->SetState(TaskState::Sleeping);
|
||||
|
||||
thread->Info.SleepUntil =
|
||||
TimeManager->CalculateTarget(Milliseconds,
|
||||
@ -281,28 +273,25 @@ namespace Tasking
|
||||
|
||||
void Task::SignalShutdown()
|
||||
{
|
||||
fixme("SignalShutdown()");
|
||||
// TODO: Implement this
|
||||
// This should hang until all processes are terminated
|
||||
}
|
||||
debug("Current process is %s(%d) and thread is %s(%d)",
|
||||
GetCurrentProcess()->Name, GetCurrentProcess()->ID,
|
||||
GetCurrentThread()->Name, GetCurrentThread()->ID);
|
||||
|
||||
void Task::CleanupProcessesThread()
|
||||
{
|
||||
thisThread->Rename("Tasking Cleanup");
|
||||
while (true)
|
||||
foreach (auto pcb in ProcessList)
|
||||
{
|
||||
this->Sleep(2000);
|
||||
{
|
||||
SmartLock(TaskingLock);
|
||||
foreach (auto Process in ProcessList)
|
||||
{
|
||||
if (unlikely(InvalidPCB(Process)))
|
||||
continue;
|
||||
if (pcb->State == TaskState::Terminated ||
|
||||
pcb->State == TaskState::Zombie)
|
||||
continue;
|
||||
|
||||
RemoveProcess(Process);
|
||||
}
|
||||
}
|
||||
if (pcb == GetCurrentProcess())
|
||||
continue;
|
||||
|
||||
debug("Sending SIGTERM to process \"%s\"(%d)",
|
||||
pcb->Name, pcb->ID);
|
||||
pcb->SendSignal(SIGTERM);
|
||||
}
|
||||
|
||||
// TODO: wait for processes to terminate with timeout.
|
||||
}
|
||||
|
||||
__no_sanitize("undefined")
|
||||
@ -325,16 +314,55 @@ namespace Tasking
|
||||
const char *Name,
|
||||
TaskExecutionMode ExecutionMode,
|
||||
void *Image,
|
||||
bool DoNotCreatePageTable,
|
||||
bool UseKernelPageTable,
|
||||
uint16_t UserID,
|
||||
uint16_t GroupID)
|
||||
{
|
||||
SmartLock(TaskingLock);
|
||||
return new PCB(this, Parent, Name, ExecutionMode,
|
||||
Image, DoNotCreatePageTable,
|
||||
Image, UseKernelPageTable,
|
||||
UserID, GroupID);
|
||||
}
|
||||
|
||||
void Task::StartScheduler()
|
||||
{
|
||||
#if defined(a86)
|
||||
if (Interrupts::apicTimer[0])
|
||||
{
|
||||
((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
|
||||
|
||||
/* FIXME: The kernel is not ready for multi-core tasking. */
|
||||
return;
|
||||
|
||||
APIC::InterruptCommandRegister icr{};
|
||||
bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC;
|
||||
|
||||
if (likely(x2APIC))
|
||||
{
|
||||
icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
|
||||
icr.x2.MT = APIC::Fixed;
|
||||
icr.x2.L = APIC::Assert;
|
||||
icr.x2.DES = 0xFFFFFFFF; /* Broadcast IPI to all local APICs. */
|
||||
((APIC::APIC *)Interrupts::apic[0])->ICR(icr);
|
||||
}
|
||||
else
|
||||
{
|
||||
icr.VEC = s_cst(uint8_t, CPU::x86::IRQ16);
|
||||
icr.MT = APIC::Fixed;
|
||||
icr.L = APIC::Assert;
|
||||
|
||||
for (int i = 0; i < SMP::CPUCores; i++)
|
||||
{
|
||||
icr.DES = uint8_t(i);
|
||||
((APIC::APIC *)Interrupts::apic[i])->ICR(icr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
debug("Tasking Started");
|
||||
}
|
||||
|
||||
Task::Task(const IP EntryPoint) : Interrupts::Handler(16) /* IRQ16 */
|
||||
{
|
||||
#if defined(a64)
|
||||
@ -343,8 +371,8 @@ namespace Tasking
|
||||
#elif defined(a32)
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
KPrint("Starting Tasking With Instruction Pointer: %p (\e666666%s\eCCCCCC)",
|
||||
EntryPoint, KernelSymbolTable->GetSymbolFromAddress(EntryPoint));
|
||||
KPrint("Starting tasking instance %#lx with ip: %p (\e666666%s\eCCCCCC)",
|
||||
this, EntryPoint, KernelSymbolTable->GetSymbol(EntryPoint));
|
||||
|
||||
#if defined(a64)
|
||||
TaskArchitecture Arch = TaskArchitecture::x64;
|
||||
@ -354,14 +382,17 @@ namespace Tasking
|
||||
TaskArchitecture Arch = TaskArchitecture::ARM64;
|
||||
#endif
|
||||
|
||||
PCB *kproc = CreateProcess(nullptr, "Kernel", TaskExecutionMode::Kernel);
|
||||
kproc->ELFSymbolTable = KernelSymbolTable;
|
||||
TCB *kthrd = CreateThread(kproc, EntryPoint,
|
||||
KernelProcess = CreateProcess(nullptr, "Kernel",
|
||||
TaskExecutionMode::Kernel,
|
||||
nullptr, true);
|
||||
KernelProcess->PageTable = KernelPageTable;
|
||||
KernelProcess->ELFSymbolTable = KernelSymbolTable;
|
||||
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
|
||||
nullptr, nullptr,
|
||||
std::vector<AuxiliaryVector>(), Arch);
|
||||
kthrd->Rename("Main Thread");
|
||||
debug("Created Kernel Process: %s and Thread: %s",
|
||||
kproc->Name, kthrd->Name);
|
||||
KernelProcess->Name, kthrd->Name);
|
||||
|
||||
bool MONITORSupported = false;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
@ -388,37 +419,25 @@ namespace Tasking
|
||||
CPU::Interrupts(CPU::Enable);
|
||||
}
|
||||
|
||||
IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskExecutionMode::Kernel);
|
||||
IdleProcess = CreateProcess(nullptr, (char *)"Idle",
|
||||
TaskExecutionMode::Kernel,
|
||||
nullptr, true);
|
||||
IdleProcess->ELFSymbolTable = KernelSymbolTable;
|
||||
for (int i = 0; i < SMP::CPUCores; i++)
|
||||
{
|
||||
IdleThread = CreateThread(IdleProcess, IP(IdleProcessLoop));
|
||||
TCB *thd = CreateThread(IdleProcess, IP(IdleProcessLoop));
|
||||
char IdleName[16];
|
||||
sprintf(IdleName, "Idle Thread %d", i);
|
||||
IdleThread->Rename(IdleName);
|
||||
IdleThread->SetPriority(Idle);
|
||||
thd->Rename(IdleName);
|
||||
thd->SetPriority(Idle);
|
||||
for (int j = 0; j < MAX_CPU; j++)
|
||||
IdleThread->Info.Affinity[j] = false;
|
||||
IdleThread->Info.Affinity[i] = true;
|
||||
}
|
||||
debug("Tasking Started");
|
||||
#if defined(a86)
|
||||
if (Interrupts::apicTimer[0])
|
||||
{
|
||||
((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100);
|
||||
thd->Info.Affinity[j] = false;
|
||||
thd->Info.Affinity[i] = true;
|
||||
|
||||
/* FIXME: The kernel is not ready for multi-core tasking. */
|
||||
// for (int i = 1; i < SMP::CPUCores; i++)
|
||||
// {
|
||||
// ((APIC::Timer *)Interrupts::apicTimer[i])->OneShot(CPU::x86::IRQ16, 100);
|
||||
// APIC::InterruptCommandRegisterLow icr;
|
||||
// icr.Vector = CPU::x86::IRQ16;
|
||||
// icr.Level = APIC::APICLevel::Assert;
|
||||
// ((APIC::APIC *)Interrupts::apic[0])->IPI(i, icr);
|
||||
// }
|
||||
if (unlikely(i == 0))
|
||||
IdleThread = thd;
|
||||
}
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
debug("Tasking is ready");
|
||||
}
|
||||
|
||||
Task::~Task()
|
||||
@ -430,8 +449,7 @@ namespace Tasking
|
||||
{
|
||||
foreach (TCB *Thread in Process->Threads)
|
||||
{
|
||||
if (Thread == GetCurrentCPU()->CurrentThread.load() ||
|
||||
Thread == CleanupThread)
|
||||
if (Thread == GetCurrentCPU()->CurrentThread.load())
|
||||
continue;
|
||||
this->KillThread(Thread, KILL_SCHEDULER_DESTRUCTION);
|
||||
}
|
||||
@ -442,20 +460,38 @@ namespace Tasking
|
||||
}
|
||||
}
|
||||
|
||||
debug("Waiting for processes to terminate");
|
||||
uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds);
|
||||
while (ProcessList.size() > 0)
|
||||
{
|
||||
trace("Waiting for %d processes to terminate", ProcessList.size());
|
||||
int NotTerminated = 0;
|
||||
foreach (PCB *Process in ProcessList)
|
||||
{
|
||||
debug("Process %s(%d) is still running (or waiting to be removed status %#lx)",
|
||||
trace("Process %s(%d) is still running (or waiting to be removed state %#lx)",
|
||||
Process->Name, Process->ID, Process->State);
|
||||
|
||||
if (Process->State == TaskState::Terminated)
|
||||
{
|
||||
debug("Process %s(%d) terminated", Process->Name, Process->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
NotTerminated++;
|
||||
}
|
||||
if (NotTerminated == 1)
|
||||
break;
|
||||
|
||||
this->Sleep(1000);
|
||||
debug("Current working process is %s(%d)",
|
||||
GetCurrentProcess()->Name, GetCurrentProcess()->ID);
|
||||
|
||||
if (TimeManager->GetCounter() > timeout)
|
||||
{
|
||||
error("Timeout waiting for processes to terminate");
|
||||
break;
|
||||
}
|
||||
|
||||
TaskingScheduler_OneShot(100);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ void ThreadDoExit()
|
||||
{
|
||||
CPUData *CPUData = GetCurrentCPU();
|
||||
Tasking::TCB *CurrentThread = CPUData->CurrentThread.load();
|
||||
CurrentThread->State = Tasking::TaskState::Terminated;
|
||||
CurrentThread->SetState(Tasking::Terminated);
|
||||
|
||||
debug("\"%s\"(%d) exited with code: %#lx",
|
||||
CurrentThread->Name,
|
||||
@ -62,6 +62,25 @@ void ThreadDoExit()
|
||||
|
||||
namespace Tasking
|
||||
{
|
||||
int TCB::SendSignal(int sig)
|
||||
{
|
||||
return this->Parent->Signals->SendSignal(sig);
|
||||
}
|
||||
|
||||
void TCB::SetState(TaskState state)
|
||||
{
|
||||
this->State.store(state);
|
||||
if (this->Parent->Threads.size() == 1)
|
||||
this->Parent->State.store(state);
|
||||
}
|
||||
|
||||
void TCB::SetExitCode(int code)
|
||||
{
|
||||
this->ExitCode.store(code);
|
||||
if (this->Parent->Threads.size() == 1)
|
||||
this->Parent->ExitCode.store(code);
|
||||
}
|
||||
|
||||
void TCB::Rename(const char *name)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
@ -98,6 +117,9 @@ namespace Tasking
|
||||
this->Name, Critical ? "true" : "false");
|
||||
|
||||
Security.IsCritical = Critical;
|
||||
|
||||
if (this->Parent->Threads.size() == 1)
|
||||
this->Parent->Security.IsCritical = Critical;
|
||||
}
|
||||
|
||||
void TCB::SetDebugMode(bool Enable)
|
||||
@ -106,6 +128,9 @@ namespace Tasking
|
||||
this->Name, Enable ? "true" : "false");
|
||||
|
||||
Security.IsDebugEnabled = Enable;
|
||||
|
||||
if (this->Parent->Threads.size() == 1)
|
||||
this->Parent->Security.IsDebugEnabled = Enable;
|
||||
}
|
||||
|
||||
void TCB::SetKernelDebugMode(bool Enable)
|
||||
@ -114,6 +139,9 @@ namespace Tasking
|
||||
this->Name, Enable ? "true" : "false");
|
||||
|
||||
Security.IsKernelDebugEnabled = Enable;
|
||||
|
||||
if (this->Parent->Threads.size() == 1)
|
||||
this->Parent->Security.IsKernelDebugEnabled = Enable;
|
||||
}
|
||||
|
||||
size_t TCB::GetSize()
|
||||
@ -171,13 +199,13 @@ namespace Tasking
|
||||
|
||||
/* 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
|
||||
/* rsp is the top of the stack */
|
||||
char *Stack = (char *)this->Stack->GetStackPhysicalTop();
|
||||
// Temporary stack pointer for strings
|
||||
/* Temporary stack pointer for strings */
|
||||
char *StackStrings = (char *)Stack;
|
||||
char *StackStringsVirtual = (char *)this->Stack->GetStackTop();
|
||||
|
||||
// Store string pointers for later
|
||||
/* Store string pointers for later */
|
||||
uintptr_t *ArgvStrings = nullptr;
|
||||
uintptr_t *EnvpStrings = nullptr;
|
||||
if (ArgvSize > 0)
|
||||
@ -187,63 +215,66 @@ namespace Tasking
|
||||
|
||||
for (size_t i = 0; i < ArgvSize; i++)
|
||||
{
|
||||
// Subtract the length of the string and the null terminator
|
||||
/* 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
|
||||
/* Store the pointer to the string */
|
||||
ArgvStrings[i] = (uintptr_t)StackStringsVirtual;
|
||||
// Copy the string to the stack
|
||||
/* 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
|
||||
/* 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
|
||||
/* Store the pointer to the string */
|
||||
EnvpStrings[i] = (uintptr_t)StackStringsVirtual;
|
||||
// Copy the string to the stack
|
||||
/* Copy the string to the stack */
|
||||
strcpy(StackStrings, envp[i]);
|
||||
debug("envp[%d]: %s", i, envp[i]);
|
||||
}
|
||||
|
||||
// Align the stack to 16 bytes
|
||||
/* Align the stack to 16 bytes */
|
||||
StackStrings -= (uintptr_t)StackStrings & 0xF;
|
||||
// Set "Stack" to the new stack pointer
|
||||
/* Set "Stack" to the new stack pointer */
|
||||
Stack = (char *)StackStrings;
|
||||
// If argv and envp sizes are odd then we need to align the stack
|
||||
/* If argv and envp sizes are odd then we need to align the stack */
|
||||
Stack -= (ArgvSize + EnvpSize) % 2;
|
||||
debug("odd align: %#lx | %#lx -> %#lx",
|
||||
(ArgvSize + EnvpSize) % 2,
|
||||
StackStrings, Stack);
|
||||
|
||||
// We need 8 bit pointers for the stack from here
|
||||
/* We need 8 bit pointers for the stack from here */
|
||||
uintptr_t *Stack64 = (uintptr_t *)Stack;
|
||||
assert(Stack64 != nullptr);
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
/* Store the null terminator */
|
||||
StackPush(Stack64, uintptr_t, AT_NULL);
|
||||
|
||||
// auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator
|
||||
/* 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
|
||||
/* Store auxillary vector */
|
||||
foreach (AuxiliaryVector av in auxv_array)
|
||||
{
|
||||
// Subtract the size of the auxillary vector
|
||||
/* Subtract the size of the auxillary vector */
|
||||
Stack64 -= sizeof(Elf_auxv_t) / sizeof(uintptr_t);
|
||||
// Store the auxillary vector
|
||||
/* Store the auxillary vector */
|
||||
POKE(Elf_auxv_t, Stack64) = av.archaux;
|
||||
// TODO: Store strings to the stack
|
||||
/* TODO: Store strings to the stack */
|
||||
}
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
/* Store the null terminator */
|
||||
StackPush(Stack64, uintptr_t, AT_NULL);
|
||||
|
||||
// Store EnvpStrings[] to the stack
|
||||
Stack64 -= EnvpSize; // (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize)
|
||||
/* 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];
|
||||
@ -251,12 +282,11 @@ namespace Tasking
|
||||
i, EnvpStrings[i]);
|
||||
}
|
||||
|
||||
// Store the null terminator
|
||||
Stack64--;
|
||||
*Stack64 = AT_NULL;
|
||||
/* Store the null terminator */
|
||||
StackPush(Stack64, uintptr_t, AT_NULL);
|
||||
|
||||
// Store ArgvStrings[] to the stack
|
||||
Stack64 -= ArgvSize; // (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize)
|
||||
/* 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];
|
||||
@ -264,11 +294,10 @@ namespace Tasking
|
||||
i, ArgvStrings[i]);
|
||||
}
|
||||
|
||||
// Store the argc
|
||||
Stack64--;
|
||||
*Stack64 = ArgvSize;
|
||||
/* Store the argc */
|
||||
StackPush(Stack64, uintptr_t, ArgvSize);
|
||||
|
||||
// Set "Stack" to the new stack pointer
|
||||
/* 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.
|
||||
@ -276,8 +305,10 @@ namespace Tasking
|
||||
uintptr_t SubtractStack = (uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)Stack;
|
||||
debug("SubtractStack: %#lx", SubtractStack);
|
||||
|
||||
// Set the stack pointer to the new stack
|
||||
/* Set the stack pointer to the new stack */
|
||||
uintptr_t StackPointerReg = ((uintptr_t)this->Stack->GetStackTop() - SubtractStack);
|
||||
// assert(!(StackPointerReg & 0xF));
|
||||
|
||||
#if defined(a64)
|
||||
this->Registers.rsp = StackPointerReg;
|
||||
#elif defined(a32)
|
||||
@ -292,7 +323,9 @@ namespace Tasking
|
||||
delete[] EnvpStrings;
|
||||
|
||||
#ifdef DEBUG
|
||||
DumpData("Stack Data", (void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack), SubtractStack);
|
||||
DumpData("Stack Data",
|
||||
(void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack),
|
||||
SubtractStack);
|
||||
#endif
|
||||
|
||||
#if defined(a64)
|
||||
@ -327,6 +360,48 @@ namespace Tasking
|
||||
fixme("Not implemented");
|
||||
}
|
||||
|
||||
void TCB::SetupThreadLocalStorage()
|
||||
{
|
||||
if (Parent->TLS.pBase == 0x0)
|
||||
return;
|
||||
this->TLS = Parent->TLS;
|
||||
|
||||
debug("msz: %ld fsz: %ld",
|
||||
this->TLS.Size, this->TLS.fSize);
|
||||
|
||||
// size_t pOffset = this->TLS.vBase - std::tolower(this->TLS.vBase);
|
||||
size_t tlsFullSize = sizeof(uintptr_t) + this->TLS.Size;
|
||||
/* 2 guard pages */
|
||||
size_t tlsPages = 1 + TO_PAGES(tlsFullSize) + 1;
|
||||
|
||||
void *opTLS = this->vma->RequestPages(tlsPages);
|
||||
void *pTLS = (void *)(PAGE_SIZE + uintptr_t(opTLS));
|
||||
this->TLS.pBase = uintptr_t(pTLS);
|
||||
|
||||
memcpy(pTLS, (void *)this->TLS.pBase,
|
||||
this->TLS.Size);
|
||||
|
||||
size_t restBytes = this->TLS.Size - this->TLS.fSize;
|
||||
if (restBytes)
|
||||
{
|
||||
memset((void *)(uintptr_t(pTLS) + this->TLS.Size),
|
||||
0, restBytes);
|
||||
}
|
||||
|
||||
Memory::Virtual vmm(this->Parent->PageTable);
|
||||
/* Map guard pages */
|
||||
vmm.Remap((void *)(uintptr_t(pTLS) - PAGE_SIZE), opTLS, Memory::P);
|
||||
vmm.Remap((void *)(uintptr_t(pTLS) + this->TLS.Size), opTLS, Memory::P);
|
||||
/* Map TLS */
|
||||
vmm.Map(pTLS, pTLS, this->TLS.Size, Memory::RW | Memory::US);
|
||||
|
||||
uintptr_t *pTLSPointer = (uintptr_t *)this->TLS.pBase + this->TLS.Size;
|
||||
*pTLSPointer = this->TLS.pBase + this->TLS.Size;
|
||||
|
||||
this->GSBase = r_cst(uintptr_t, pTLSPointer);
|
||||
this->FSBase = r_cst(uintptr_t, pTLSPointer);
|
||||
}
|
||||
|
||||
TCB::TCB(Task *ctx, PCB *Parent, IP EntryPoint,
|
||||
const char **argv, const char **envp,
|
||||
const std::vector<AuxiliaryVector> &auxv,
|
||||
@ -363,9 +438,9 @@ namespace Tasking
|
||||
this->ExitCode = KILL_CRASH;
|
||||
|
||||
if (ThreadNotReady)
|
||||
this->State = TaskState::Waiting;
|
||||
this->SetState(Waiting);
|
||||
else
|
||||
this->State = TaskState::Ready;
|
||||
this->SetState(Ready);
|
||||
|
||||
this->vma = new Memory::VirtualMemoryArea(this->Parent->PageTable);
|
||||
|
||||
@ -467,11 +542,19 @@ namespace Tasking
|
||||
assert(false);
|
||||
}
|
||||
|
||||
SetupThreadLocalStorage();
|
||||
|
||||
this->Info.Architecture = Architecture;
|
||||
this->Info.Compatibility = Compatibility;
|
||||
this->Security.ExecutionMode =
|
||||
this->Parent->Security.ExecutionMode;
|
||||
|
||||
if (this->Parent->Threads.size() == 0)
|
||||
{
|
||||
this->Parent->Info.Architecture = this->Info.Architecture;
|
||||
this->Parent->Info.Compatibility = this->Info.Compatibility;
|
||||
}
|
||||
|
||||
// TODO: Is really a good idea to use the FPU in kernel mode?
|
||||
this->FPU.mxcsr = 0b0001111110000000;
|
||||
this->FPU.mxcsrmask = 0b1111111110111111;
|
||||
@ -519,7 +602,7 @@ namespace Tasking
|
||||
this->Parent->State == Waiting &&
|
||||
ThreadNotReady == false)
|
||||
{
|
||||
this->Parent->State = Ready;
|
||||
this->Parent->SetState(Ready);
|
||||
debug("Setting process \"%s\"(%d) to ready",
|
||||
this->Parent->Name, this->Parent->ID);
|
||||
}
|
||||
@ -531,7 +614,7 @@ namespace Tasking
|
||||
|
||||
/* Remove us from the process list so we
|
||||
don't get scheduled anymore */
|
||||
std::vector<Tasking::TCB *> &Threads = this->Parent->Threads;
|
||||
std::list<Tasking::TCB *> &Threads = this->Parent->Threads;
|
||||
Threads.erase(std::find(Threads.begin(),
|
||||
Threads.end(),
|
||||
this));
|
||||
@ -544,5 +627,8 @@ namespace Tasking
|
||||
|
||||
/* Free Name */
|
||||
delete[] this->Name;
|
||||
|
||||
debug("Thread \"%s\"(%d) destroyed",
|
||||
this->Name, this->ID);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user