mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[kernel] Delete processes & threads only via refcounts
Previously processes and threads would be deleted by the scheduler. Now, only delete them based on refcounts - this allows joining an already-exited thread, for instance.
This commit is contained in:
@@ -68,6 +68,7 @@ cap_table::derive(j6_handle_t base, j6_cap_t caps)
|
||||
capability *
|
||||
cap_table::find_without_retain(j6_handle_t id)
|
||||
{
|
||||
util::scoped_lock lock {m_lock};
|
||||
return m_caps.find(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,9 @@ process::exit(int32_t code)
|
||||
|
||||
util::scoped_lock lock {m_threads_lock};
|
||||
for (auto *thread : m_threads) {
|
||||
if (thread != ¤t)
|
||||
if (thread != ¤t) {
|
||||
thread->exit();
|
||||
}
|
||||
}
|
||||
|
||||
lock.release();
|
||||
@@ -82,6 +83,7 @@ process::create_thread(uintptr_t rsp3, uint8_t priority)
|
||||
|
||||
thread *th = new thread(*this, priority);
|
||||
kassert(th, "Failed to create thread!");
|
||||
th->handle_retain();
|
||||
|
||||
if (rsp3)
|
||||
th->tcb()->rsp3 = rsp3;
|
||||
@@ -91,23 +93,25 @@ process::create_thread(uintptr_t rsp3, uint8_t priority)
|
||||
return th;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
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;
|
||||
if (m_state != state::exited) {
|
||||
// if we're already going away, just release
|
||||
// the thread's handle and skip all this
|
||||
util::scoped_lock lock {m_threads_lock};
|
||||
m_threads.remove_swap(th);
|
||||
|
||||
// TODO: delete the thread's stack VMA
|
||||
if (m_threads.empty()) {
|
||||
lock.release();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
th->handle_release();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -75,11 +75,7 @@ public:
|
||||
|
||||
/// Inform the process of an exited thread
|
||||
/// \args th The thread which has exited
|
||||
/// \returns True if this thread ending has ended the process
|
||||
bool thread_exited(thread *th);
|
||||
|
||||
/// Get the handle for this process to refer to itself
|
||||
inline j6_handle_t self_handle() const { return m_self_handle; }
|
||||
void thread_exited(thread *th);
|
||||
|
||||
/// Get the process object that owns kernel threads and the
|
||||
/// kernel address space
|
||||
|
||||
@@ -22,6 +22,7 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
||||
m_wake_value {0},
|
||||
m_wake_timeout {0}
|
||||
{
|
||||
parent.handle_retain();
|
||||
parent.space().initialize_tcb(m_tcb);
|
||||
m_tcb.priority = pri;
|
||||
m_tcb.thread = this;
|
||||
@@ -37,6 +38,7 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
||||
thread::~thread()
|
||||
{
|
||||
g_kernel_stacks.return_section(m_tcb.kernel_stack);
|
||||
m_parent.handle_release();
|
||||
}
|
||||
|
||||
thread & thread::current() { return *current_cpu().thread; }
|
||||
@@ -99,6 +101,7 @@ thread::exit()
|
||||
{
|
||||
m_wake_timeout = 0;
|
||||
set_state(state::exited);
|
||||
m_parent.thread_exited(this);
|
||||
m_join_queue.clear();
|
||||
block();
|
||||
}
|
||||
|
||||
@@ -170,11 +170,6 @@ public:
|
||||
/// \arg rsp The existing stack for the idle thread
|
||||
static thread * create_idle_thread(process &kernel, uintptr_t rsp);
|
||||
|
||||
protected:
|
||||
/// Don't delete a thread on no handles, the scheduler takes
|
||||
/// care of that.
|
||||
virtual void on_no_handles() override {}
|
||||
|
||||
private:
|
||||
thread() = delete;
|
||||
thread(const thread &other) = delete;
|
||||
|
||||
@@ -111,6 +111,9 @@ scheduler::add_thread(TCB *t)
|
||||
run_queue &queue = m_run_queues[cpu->index];
|
||||
util::scoped_lock lock {queue.lock};
|
||||
|
||||
obj::thread *th = t->thread;
|
||||
th->handle_retain();
|
||||
|
||||
t->cpu = cpu;
|
||||
t->time_left = quantum(t->priority);
|
||||
queue.blocked.push_back(static_cast<tcb_node*>(t));
|
||||
@@ -147,12 +150,7 @@ scheduler::prune(run_queue &queue, uint64_t now)
|
||||
if (current) continue;
|
||||
|
||||
queue.blocked.remove(remove);
|
||||
process &p = th->parent();
|
||||
|
||||
// thread_exited deletes the thread, and returns true if the process
|
||||
// should also now be deleted
|
||||
if(!current && p.thread_exited(th))
|
||||
delete &p;
|
||||
th->handle_release();
|
||||
} else {
|
||||
queue.blocked.remove(remove);
|
||||
log::spam(logs::sched, "Prune: readying unblocked thread %llx", th->koid());
|
||||
|
||||
Reference in New Issue
Block a user