mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
For the coming switch to cap/handle ref-counting being the main lifetime determiner of objects, get rid of self handles for threads and processes to avoid circular references. Instead, passing 0 to syscalls expecting a thread or process handle signifies "this process/thread".
169 lines
3.6 KiB
C++
169 lines
3.6 KiB
C++
#include <new>
|
|
|
|
#include <util/no_construct.h>
|
|
|
|
#include "assert.h"
|
|
#include "capabilities.h"
|
|
#include "cpu.h"
|
|
#include "objects/process.h"
|
|
#include "objects/thread.h"
|
|
#include "objects/vm_area.h"
|
|
#include "scheduler.h"
|
|
|
|
|
|
// This object is initialized _before_ global constructors are called,
|
|
// so we don't want it to have a global constructor at all, lest it
|
|
// overwrite the previous initialization.
|
|
static util::no_construct<obj::process> __g_kernel_process_storage;
|
|
obj::process &g_kernel_process = __g_kernel_process_storage.value;
|
|
|
|
|
|
namespace obj {
|
|
|
|
process::process() :
|
|
kobject {kobject::type::process},
|
|
m_state {state::running}
|
|
{
|
|
}
|
|
|
|
// The "kernel process"-only constructor
|
|
process::process(page_table *kpml4) :
|
|
kobject {kobject::type::process},
|
|
m_space {kpml4},
|
|
m_state {state::running}
|
|
{
|
|
}
|
|
|
|
process::~process()
|
|
{
|
|
}
|
|
|
|
process & process::current() { return *current_cpu().process; }
|
|
process & process::kernel_process() { return g_kernel_process; }
|
|
|
|
process *
|
|
process::create_kernel_process(page_table *pml4)
|
|
{
|
|
return new (&g_kernel_process) process {pml4};
|
|
}
|
|
|
|
void
|
|
process::exit(int32_t code)
|
|
{
|
|
if (m_state == state::exited)
|
|
return;
|
|
|
|
m_state = state::exited;
|
|
m_return_code = code;
|
|
|
|
thread ¤t = thread::current();
|
|
|
|
util::scoped_lock lock {m_threads_lock};
|
|
for (auto *thread : m_threads) {
|
|
if (thread != ¤t)
|
|
thread->exit();
|
|
}
|
|
|
|
lock.release();
|
|
if (¤t.parent() == this)
|
|
current.exit();
|
|
}
|
|
|
|
thread *
|
|
process::create_thread(uintptr_t rsp3, uint8_t priority)
|
|
{
|
|
util::scoped_lock lock {m_threads_lock};
|
|
|
|
if (m_state == state::exited)
|
|
return nullptr;
|
|
|
|
if (priority == default_priority)
|
|
priority = scheduler::default_priority;
|
|
|
|
thread *th = new thread(*this, priority);
|
|
kassert(th, "Failed to create thread!");
|
|
|
|
if (rsp3)
|
|
th->tcb()->rsp3 = rsp3;
|
|
|
|
m_threads.append(th);
|
|
scheduler::get().add_thread(th->tcb());
|
|
return th;
|
|
}
|
|
|
|
bool
|
|
process::thread_exited(thread *th)
|
|
{
|
|
util::scoped_lock lock {m_threads_lock};
|
|
|
|
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
|
m_threads.remove_swap(th);
|
|
remove_handle(th->self_handle());
|
|
delete th;
|
|
|
|
// TODO: delete the thread's stack VMA
|
|
if (m_threads.empty() && m_state != state::exited) {
|
|
exit(-1);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
process::add_handle(j6_handle_t handle)
|
|
{
|
|
capability *c = g_cap_table.retain(handle);
|
|
kassert(c, "Trying to add a non-existant handle to a process!");
|
|
|
|
if (c) {
|
|
util::scoped_lock lock {m_handles_lock};
|
|
m_handles.add(handle);
|
|
}
|
|
}
|
|
|
|
bool
|
|
process::remove_handle(j6_handle_t handle)
|
|
{
|
|
util::scoped_lock lock {m_handles_lock};
|
|
bool removed = m_handles.remove(handle);
|
|
lock.release();
|
|
|
|
if (removed)
|
|
g_cap_table.release(handle);
|
|
|
|
return removed;
|
|
}
|
|
|
|
bool
|
|
process::has_handle(j6_handle_t handle)
|
|
{
|
|
util::scoped_lock lock {m_handles_lock};
|
|
return m_handles.contains(handle);
|
|
}
|
|
|
|
size_t
|
|
process::list_handles(j6_handle_descriptor *handles, size_t len)
|
|
{
|
|
util::scoped_lock lock {m_handles_lock};
|
|
|
|
size_t count = 0;
|
|
for (j6_handle_t handle : m_handles) {
|
|
|
|
capability *cap = g_cap_table.find_without_retain(handle);
|
|
kassert(cap, "Found process handle that wasn't in the cap table");
|
|
if (!cap) continue;
|
|
|
|
j6_handle_descriptor &desc = handles[count];
|
|
desc.handle = handle;
|
|
desc.caps = cap->caps;
|
|
desc.type = static_cast<j6_object_type>(cap->type);
|
|
|
|
if (++count == len) break;
|
|
}
|
|
|
|
return m_handles.count();
|
|
}
|
|
|
|
} // namespace obj
|