diff --git a/kernel/Makefile b/kernel/Makefile index 81e83fba..eb55ffe4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -89,8 +89,8 @@ dispmsg.o \ dtable.o \ elf.o \ fcache.o \ -fsfunc.o \ fs/full.o \ +fsfunc.o \ fs/kram.o \ fs/null.o \ fs/user.o \ @@ -122,6 +122,7 @@ pci.o \ pipe.o \ poll.o \ process.o \ +ptable.o \ refcount.o \ registers.o \ resource.o \ diff --git a/kernel/include/sortix/kernel/process.h b/kernel/include/sortix/kernel/process.h index 7ce7a086..4737e0fd 100644 --- a/kernel/include/sortix/kernel/process.h +++ b/kernel/include/sortix/kernel/process.h @@ -50,6 +50,7 @@ class Process; class Descriptor; class DescriptorTable; class MountTable; +class ProcessTable; struct ProcessSegment; struct ProcessTimer; struct ioctx_struct; @@ -68,9 +69,6 @@ public: public: static void Init(); -private: - static pid_t AllocatePID(); - public: char* string_table; size_t string_table_length; @@ -97,6 +95,9 @@ private: Ref mtable; Ref dtable; +public: + Ref ptable; + public: kthread_mutex_t resource_limits_lock; struct rlimit resource_limits[RLIMIT_NUM_DECLARED]; @@ -110,8 +111,9 @@ public: public: void BootstrapTables(Ref dtable, Ref mtable); void BootstrapDirectories(Ref root); - Ref GetMTable(); Ref GetDTable(); + Ref GetMTable(); + Ref GetPTable(); Ref GetRoot(); Ref GetCWD(); Ref GetDescriptor(int fd); @@ -201,13 +203,6 @@ public: public: void ResetForExecute(); -public: - static Process* Get(pid_t pid); - -private: - static bool Put(Process* process); - static void Remove(Process* process); - }; Process* CurrentProcess(); diff --git a/kernel/include/sortix/kernel/ptable.h b/kernel/include/sortix/kernel/ptable.h new file mode 100644 index 00000000..14edab3a --- /dev/null +++ b/kernel/include/sortix/kernel/ptable.h @@ -0,0 +1,63 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix. + + Sortix 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. + + Sortix 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 + Sortix. If not, see . + + sortix/kernel/ptable.h + Process table. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_KERNEl_PTABLE_H +#define INCLUDE_SORTIX_KERNEl_PTABLE_H + +#include + +#include +#include + +namespace Sortix { + +class Process; + +struct ptable_entry +{ + pid_t pid; + Process* process; +}; + +class ProcessTable : public Refcountable +{ +public: + ProcessTable(); + virtual ~ProcessTable(); + Process* Get(pid_t pid); + pid_t Allocate(Process* process); + void Free(pid_t pid); + +private: + kthread_mutex_t ptablelock; + pid_t next_pid; + struct ptable_entry* entries; + size_t entries_used; + size_t entries_length; + +}; + +} // namespace Sortix + +#endif diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index bd58beb9..2d1eedff 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -435,10 +436,16 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) DisplayMessage::Init(); // Now that the base system has been loaded, it's time to go threaded. First - // we create an object that represents this thread. + // we create an object that represents this process. + Ref ptable(new ProcessTable()); + if ( !ptable ) + Panic("Could not allocate the process table"); Process* system = new Process; if ( !system ) Panic("Could not allocate the system process"); + if ( (system->pid = (system->ptable = ptable)->Allocate(system)) < 0 ) + Panic("Could not allocate the system process a pid"); + ptable.Reset(); system->addrspace = Memory::GetAddressSpace(); system->group = system; system->groupprev = NULL; @@ -658,7 +665,10 @@ static void BootThread(void* /*user*/) if ( !initaddrspace ) { Panic("Could not create init's address space"); } Process* init = new Process; - if ( !init ) { Panic("Could not allocate init process"); } + if ( !init ) + Panic("Could not allocate init process"); + if ( (init->pid = (init->ptable = CurrentProcess()->ptable)->Allocate(init)) < 0 ) + Panic("Could not allocate init a pid"); init->group = init; init->groupprev = NULL; init->groupnext = NULL; diff --git a/kernel/logterminal.cpp b/kernel/logterminal.cpp index 39927e81..7ca70022 100644 --- a/kernel/logterminal.cpp +++ b/kernel/logterminal.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,7 @@ int LogTerminal::tcgetwinsize(ioctx_t* ctx, struct winsize* ws) int LogTerminal::tcsetpgrp(ioctx_t* /*ctx*/, pid_t pgid) { ScopedLock lock(&termlock); - Process* process = Process::Get(pgid); + Process* process = CurrentProcess()->GetPTable()->Get(pgid); if ( !pgid || !process ) return errno = ESRCH, -1; kthread_mutex_lock(&process->groupchildlock); @@ -187,7 +188,7 @@ void LogTerminal::ProcessKeystroke(int kbkey) { while ( linebuffer.CanBackspace() ) linebuffer.Backspace(); - if ( Process* process = Process::Get(foreground_pgid) ) + if ( Process* process = CurrentProcess()->GetPTable()->Get(foreground_pgid) ) process->DeliverGroupSignal(SIGINT); return; } diff --git a/kernel/process.cpp b/kernel/process.cpp index 607ba79b..861c3e61 100644 --- a/kernel/process.cpp +++ b/kernel/process.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -81,7 +82,7 @@ Process::Process() symbol_table_length = 0; program_image_path = NULL; addrspace = 0; - pid = AllocatePID(); + pid = 0; nicelock = KTHREAD_MUTEX_INITIALIZER; nice = 0; @@ -160,7 +161,6 @@ Process::Process() // child_system_clock initialized in member constructor. Time::InitializeProcessClocks(this); alarm_timer.Attach(Time::GetClock(CLOCK_MONOTONIC)); - Put(this); } Process::~Process() @@ -179,7 +179,9 @@ Process::~Process() assert(!cwd); assert(!root); - Remove(this); + assert(ptable); + ptable->Free(pid); + ptable.Reset(); } void Process::BootstrapTables(Ref dtable, Ref mtable) @@ -588,6 +590,13 @@ Ref Process::GetDTable() return dtable; } +Ref Process::GetPTable() +{ + ScopedLock lock(&ptrlock); + assert(ptable); + return ptable; +} + Ref Process::GetRoot() { ScopedLock lock(&ptrlock); @@ -634,6 +643,12 @@ Process* Process::Fork() if ( !clone ) return NULL; + if ( (clone->pid = (clone->ptable = ptable)->Allocate(clone)) < 0 ) + { + delete clone; + return NULL; + } + struct segment* clone_segments = NULL; // Fork the segment list. @@ -1299,7 +1314,7 @@ static pid_t sys_getppid() static pid_t sys_getpgid(pid_t pid) { - Process* process = !pid ? CurrentProcess() : Process::Get(pid); + Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid); if ( !process ) return errno = ESRCH, -1; @@ -1324,10 +1339,10 @@ static int sys_setpgid(pid_t pid, pid_t pgid) // group. This probably unlikely, but correctness over all! // Find the processes in question. - Process* process = !pid ? CurrentProcess() : Process::Get(pid); + Process* process = !pid ? CurrentProcess() : CurrentProcess()->GetPTable()->Get(pid); if ( !process ) return errno = ESRCH, -1; - Process* group = !pgid ? process : Process::Get(pgid); + Process* group = !pgid ? process : CurrentProcess()->GetPTable()->Get(pgid); if ( !group ) return errno = ESRCH, -1; @@ -1372,60 +1387,6 @@ static int sys_setpgid(pid_t pid, pid_t pgid) return 0; } -pid_t nextpidtoallocate; -kthread_mutex_t pidalloclock; - -pid_t Process::AllocatePID() -{ - ScopedLock lock(&pidalloclock); - return nextpidtoallocate++; -} - -int ProcessCompare(Process* a, Process* b) -{ - if ( a->pid < b->pid ) - return -1; - if ( a->pid > b->pid ) - return 1; - return 0; -} - -int ProcessPIDCompare(Process* a, pid_t pid) -{ - if ( a->pid < pid ) - return -1; - if ( a->pid > pid ) - return 1; - return 0; -} - -SortedList* pidlist; - -Process* Process::Get(pid_t pid) -{ - ScopedLock lock(&pidalloclock); - size_t index = pidlist->Search(ProcessPIDCompare, pid); - if ( index == SIZE_MAX ) - return NULL; - - return pidlist->Get(index); -} - -bool Process::Put(Process* process) -{ - ScopedLock lock(&pidalloclock); - return pidlist->Add(process); -} - -void Process::Remove(Process* process) -{ - ScopedLock lock(&pidalloclock); - size_t index = pidlist->Search(process); - assert(index != SIZE_MAX); - - pidlist->Remove(index); -} - static void* sys_sbrk(intptr_t increment) { Process* process = CurrentProcess(); @@ -1516,13 +1477,6 @@ void Process::Init() Syscall::Register(SYSCALL_TFORK, (void*) sys_tfork); Syscall::Register(SYSCALL_UMASK, (void*) sys_umask); Syscall::Register(SYSCALL_WAITPID, (void*) sys_waitpid); - - pidalloclock = KTHREAD_MUTEX_INITIALIZER; - nextpidtoallocate = 0; - - pidlist = new SortedList(ProcessCompare); - if ( !pidlist ) - Panic("could not allocate pidlist\n"); } } // namespace Sortix diff --git a/kernel/ptable.cpp b/kernel/ptable.cpp new file mode 100644 index 00000000..de729405 --- /dev/null +++ b/kernel/ptable.cpp @@ -0,0 +1,99 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014. + + This file is part of Sortix. + + Sortix 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. + + Sortix 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 + Sortix. If not, see . + + ptable.cpp + Process table. + +*******************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +// TODO: Process memory ownership needs to be reference counted. +// TODO: There is no proper way to iterate all the existing processes. +// TODO: This implementation is rather run-time inefficient. +// TODO: The Free method potentially leaks memory as the ptable is never shrunk. +// TODO: The next_pid counter could potentially overflow. + +namespace Sortix { + +ProcessTable::ProcessTable() +{ + ptablelock = KTHREAD_MUTEX_INITIALIZER; + next_pid = 0; + entries = NULL; + entries_used = 0; + entries_length = 0; +} + +ProcessTable::~ProcessTable() +{ + delete[] entries; +} + +Process* ProcessTable::Get(pid_t pid) +{ + ScopedLock lock(&ptablelock); + for ( size_t i = 0; i < entries_used; i++ ) + if ( entries[i].pid == pid ) + return entries[i].process; + return errno = ESRCH, (Process*) NULL; +} + +pid_t ProcessTable::Allocate(Process* process) +{ + ScopedLock lock(&ptablelock); + if ( entries_used == entries_length ) + { + size_t new_length = entries_length ? 2 * entries_length : 64; + struct ptable_entry* new_entries = new struct ptable_entry[new_length]; + if ( !new_entries ) + return -1; + memcpy(new_entries, entries, sizeof(struct ptable_entry) * entries_length); + delete[] entries; + entries = new_entries; + entries_length = new_length; + } + + struct ptable_entry* entry = &entries[entries_used++]; + entry->process = process; + return entry->pid = next_pid++; +} + +void ProcessTable::Free(pid_t pid) +{ + ScopedLock lock(&ptablelock); + for ( size_t i = 0; i < entries_used; i++ ) + { + if ( entries[i].pid != pid ) + continue; + entries[i] = entries[--entries_used]; + return; + } + assert(false); +} + +} // namespace Sortix diff --git a/kernel/resource.cpp b/kernel/resource.cpp index 08865936..666908e2 100644 --- a/kernel/resource.cpp +++ b/kernel/resource.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "resource.h" @@ -45,7 +46,7 @@ static int GetProcessPriority(pid_t who) return errno = EINVAL, -1; // TODO: If who isn't the current process, then it could self-destruct at // any time while we use it; there is no safe way to do this yet. - Process* process = who ? Process::Get(who) : CurrentProcess(); + Process* process = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcess(); if ( !process ) return errno = ESRCH, -1; ScopedLock lock(&process->nicelock); @@ -58,7 +59,7 @@ static int SetProcessPriority(pid_t who, int prio) return errno = EINVAL, -1; // TODO: If who isn't the current process, then it could self-destruct at // any time while we use it; there is no safe way to do this yet. - Process* process = who ? Process::Get(who) : CurrentProcess(); + Process* process = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcess(); if ( !process ) return errno = ESRCH, -1; ScopedLock lock(&process->nicelock); @@ -81,7 +82,7 @@ static int GetProcessGroupPriority(pid_t who) return errno = EINVAL, -1; // TODO: If who isn't the current process, then it could self-destruct at // any time while we use it; there is no safe way to do this yet. - Process* group = who ? Process::Get(who) : CurrentProcessGroup(); + Process* group = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcessGroup(); if ( !group ) return errno = ESRCH, -1; int lowest = INT_MAX; @@ -101,7 +102,7 @@ static int SetProcessGroupPriority(pid_t who, int prio) return errno = EINVAL, -1; // TODO: If who isn't the current process, then it could self-destruct at // any time while we use it; there is no safe way to do this yet. - Process* group = who ? Process::Get(who) : CurrentProcessGroup(); + Process* group = who ? CurrentProcess()->GetPTable()->Get(who) : CurrentProcessGroup(); if ( !group ) return errno = ESRCH, -1; ScopedLock group_parent_lock(&group->groupparentlock); @@ -161,7 +162,7 @@ int sys_prlimit(pid_t pid, return errno = EINVAL, -1; // TODO: If pid isn't the current process, then it could self-destruct at // any time while we use it; there is no safe way to do this yet. - Process* process = pid ? Process::Get(pid) : CurrentProcess(); + Process* process = pid ? CurrentProcess()->GetPTable()->Get(pid) : CurrentProcess(); if ( !process ) return errno = ESRCH, -1; ScopedLock lock(&process->resource_limits_lock); diff --git a/kernel/signal.cpp b/kernel/signal.cpp index 9482571d..01f0b527 100644 --- a/kernel/signal.cpp +++ b/kernel/signal.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -277,7 +278,7 @@ static int sys_kill(pid_t pid, int signum) bool process_group = pid < 0 ? (pid = -pid, true) : false; // TODO: Race condition: The process could be deleted while we use it. - Process* process = Process::Get(pid); + Process* process = CurrentProcess()->GetPTable()->Get(pid); if ( !process ) return errno = ESRCH, -1;