Files
jsix_import/src/kernel/objects/process.cpp
Justin C. Miller 194776d226 [kernel] Remove status code from thread exit
The status code from thread exit had too many issues, (eg, how does it
relate to process exit code? what happens when different threads exit
with different exit codes?) and not enough value, so I'm getting rid of
it.
2022-10-20 21:49:40 -07:00

159 lines
3.3 KiB
C++

#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}
{
m_self_handle = g_cap_table.create(this, process::self_caps);
add_handle(m_self_handle);
}
// 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)
{
// TODO: make this thread-safe
m_state = state::exited;
m_return_code = code;
for (auto *thread : m_threads) {
thread->exit();
}
if (this == current_cpu().process)
scheduler::get().schedule();
}
void
process::update()
{
kassert(m_threads.count() > 0, "process::update with zero threads!");
size_t i = 0;
while (i < m_threads.count()) {
thread *th = m_threads[i];
if (th->has_state(thread::state::exited)) {
m_threads.remove_swap_at(i);
continue;
}
i++;
}
if (m_threads.count() == 0)
exit(-1);
}
thread *
process::create_thread(uintptr_t rsp3, uint8_t priority)
{
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)
{
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.count() == 0) {
exit(-1);
return true;
}
return false;
}
void
process::add_handle(j6_handle_t handle)
{
m_handles.add(handle);
}
bool
process::remove_handle(j6_handle_t id)
{
return m_handles.remove(id);
}
bool
process::has_handle(j6_handle_t id)
{
return m_handles.contains(id);
}
size_t
process::list_handles(j6_handle_descriptor *handles, size_t len)
{
size_t count = 0;
for (j6_handle_t handle : m_handles) {
capability *cap = g_cap_table.find(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