Refactor process id allocation and accounting.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-03-19 23:34:09 +01:00
parent 25e07a9083
commit 400eb2238f
9 changed files with 214 additions and 89 deletions

View File

@ -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 \

View File

@ -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<MountTable> mtable;
Ref<DescriptorTable> dtable;
public:
Ref<ProcessTable> ptable;
public:
kthread_mutex_t resource_limits_lock;
struct rlimit resource_limits[RLIMIT_NUM_DECLARED];
@ -110,8 +111,9 @@ public:
public:
void BootstrapTables(Ref<DescriptorTable> dtable, Ref<MountTable> mtable);
void BootstrapDirectories(Ref<Descriptor> root);
Ref<MountTable> GetMTable();
Ref<DescriptorTable> GetDTable();
Ref<MountTable> GetMTable();
Ref<ProcessTable> GetPTable();
Ref<Descriptor> GetRoot();
Ref<Descriptor> GetCWD();
Ref<Descriptor> 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();

View File

@ -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 <http://www.gnu.org/licenses/>.
sortix/kernel/ptable.h
Process table.
*******************************************************************************/
#ifndef INCLUDE_SORTIX_KERNEl_PTABLE_H
#define INCLUDE_SORTIX_KERNEl_PTABLE_H
#include <sys/types.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/refcount.h>
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

View File

@ -53,6 +53,7 @@
#include <sortix/kernel/panic.h>
#include <sortix/kernel/pci.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/signal.h>
@ -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<ProcessTable> 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;

View File

@ -46,6 +46,7 @@
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/poll.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h>
@ -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;
}

View File

@ -53,6 +53,7 @@
#include <sortix/kernel/memorymanagement.h>
#include <sortix/kernel/mtable.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/scheduler.h>
#include <sortix/kernel/sortedlist.h>
@ -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<DescriptorTable> dtable, Ref<MountTable> mtable)
@ -588,6 +590,13 @@ Ref<DescriptorTable> Process::GetDTable()
return dtable;
}
Ref<ProcessTable> Process::GetPTable()
{
ScopedLock lock(&ptrlock);
assert(ptable);
return ptable;
}
Ref<Descriptor> 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<Process*>* 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<Process*>(ProcessCompare);
if ( !pidlist )
Panic("could not allocate pidlist\n");
}
} // namespace Sortix

99
kernel/ptable.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
ptable.cpp
Process table.
*******************************************************************************/
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/refcount.h>
// 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

View File

@ -32,6 +32,7 @@
#include <sortix/kernel/copy.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/syscall.h>
#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);

View File

@ -40,6 +40,7 @@
#include <sortix/kernel/interrupt.h>
#include <sortix/kernel/kernel.h>
#include <sortix/kernel/process.h>
#include <sortix/kernel/ptable.h>
#include <sortix/kernel/signal.h>
#include <sortix/kernel/syscall.h>
#include <sortix/kernel/thread.h>
@ -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;