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 *
|
capability *
|
||||||
cap_table::find_without_retain(j6_handle_t id)
|
cap_table::find_without_retain(j6_handle_t id)
|
||||||
{
|
{
|
||||||
|
util::scoped_lock lock {m_lock};
|
||||||
return m_caps.find(id);
|
return m_caps.find(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,9 +60,10 @@ process::exit(int32_t code)
|
|||||||
|
|
||||||
util::scoped_lock lock {m_threads_lock};
|
util::scoped_lock lock {m_threads_lock};
|
||||||
for (auto *thread : m_threads) {
|
for (auto *thread : m_threads) {
|
||||||
if (thread != ¤t)
|
if (thread != ¤t) {
|
||||||
thread->exit();
|
thread->exit();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
if (¤t.parent() == this)
|
if (¤t.parent() == this)
|
||||||
@@ -82,6 +83,7 @@ process::create_thread(uintptr_t rsp3, uint8_t priority)
|
|||||||
|
|
||||||
thread *th = new thread(*this, priority);
|
thread *th = new thread(*this, priority);
|
||||||
kassert(th, "Failed to create thread!");
|
kassert(th, "Failed to create thread!");
|
||||||
|
th->handle_retain();
|
||||||
|
|
||||||
if (rsp3)
|
if (rsp3)
|
||||||
th->tcb()->rsp3 = rsp3;
|
th->tcb()->rsp3 = rsp3;
|
||||||
@@ -91,23 +93,25 @@ process::create_thread(uintptr_t rsp3, uint8_t priority)
|
|||||||
return th;
|
return th;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
process::thread_exited(thread *th)
|
process::thread_exited(thread *th)
|
||||||
{
|
{
|
||||||
util::scoped_lock lock {m_threads_lock};
|
|
||||||
|
|
||||||
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
kassert(&th->m_parent == this, "Process got thread_exited for non-child!");
|
||||||
|
|
||||||
|
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);
|
m_threads.remove_swap(th);
|
||||||
remove_handle(th->self_handle());
|
|
||||||
delete th;
|
|
||||||
|
|
||||||
// TODO: delete the thread's stack VMA
|
// TODO: delete the thread's stack VMA
|
||||||
if (m_threads.empty() && m_state != state::exited) {
|
if (m_threads.empty()) {
|
||||||
|
lock.release();
|
||||||
exit(-1);
|
exit(-1);
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
th->handle_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -75,11 +75,7 @@ public:
|
|||||||
|
|
||||||
/// Inform the process of an exited thread
|
/// Inform the process of an exited thread
|
||||||
/// \args th The thread which has exited
|
/// \args th The thread which has exited
|
||||||
/// \returns True if this thread ending has ended the process
|
void thread_exited(thread *th);
|
||||||
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; }
|
|
||||||
|
|
||||||
/// Get the process object that owns kernel threads and the
|
/// Get the process object that owns kernel threads and the
|
||||||
/// kernel address space
|
/// kernel address space
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
|||||||
m_wake_value {0},
|
m_wake_value {0},
|
||||||
m_wake_timeout {0}
|
m_wake_timeout {0}
|
||||||
{
|
{
|
||||||
|
parent.handle_retain();
|
||||||
parent.space().initialize_tcb(m_tcb);
|
parent.space().initialize_tcb(m_tcb);
|
||||||
m_tcb.priority = pri;
|
m_tcb.priority = pri;
|
||||||
m_tcb.thread = this;
|
m_tcb.thread = this;
|
||||||
@@ -37,6 +38,7 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
|
|||||||
thread::~thread()
|
thread::~thread()
|
||||||
{
|
{
|
||||||
g_kernel_stacks.return_section(m_tcb.kernel_stack);
|
g_kernel_stacks.return_section(m_tcb.kernel_stack);
|
||||||
|
m_parent.handle_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread & thread::current() { return *current_cpu().thread; }
|
thread & thread::current() { return *current_cpu().thread; }
|
||||||
@@ -99,6 +101,7 @@ thread::exit()
|
|||||||
{
|
{
|
||||||
m_wake_timeout = 0;
|
m_wake_timeout = 0;
|
||||||
set_state(state::exited);
|
set_state(state::exited);
|
||||||
|
m_parent.thread_exited(this);
|
||||||
m_join_queue.clear();
|
m_join_queue.clear();
|
||||||
block();
|
block();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,11 +170,6 @@ public:
|
|||||||
/// \arg rsp The existing stack for the idle thread
|
/// \arg rsp The existing stack for the idle thread
|
||||||
static thread * create_idle_thread(process &kernel, uintptr_t rsp);
|
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:
|
private:
|
||||||
thread() = delete;
|
thread() = delete;
|
||||||
thread(const thread &other) = delete;
|
thread(const thread &other) = delete;
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ scheduler::add_thread(TCB *t)
|
|||||||
run_queue &queue = m_run_queues[cpu->index];
|
run_queue &queue = m_run_queues[cpu->index];
|
||||||
util::scoped_lock lock {queue.lock};
|
util::scoped_lock lock {queue.lock};
|
||||||
|
|
||||||
|
obj::thread *th = t->thread;
|
||||||
|
th->handle_retain();
|
||||||
|
|
||||||
t->cpu = cpu;
|
t->cpu = cpu;
|
||||||
t->time_left = quantum(t->priority);
|
t->time_left = quantum(t->priority);
|
||||||
queue.blocked.push_back(static_cast<tcb_node*>(t));
|
queue.blocked.push_back(static_cast<tcb_node*>(t));
|
||||||
@@ -147,12 +150,7 @@ scheduler::prune(run_queue &queue, uint64_t now)
|
|||||||
if (current) continue;
|
if (current) continue;
|
||||||
|
|
||||||
queue.blocked.remove(remove);
|
queue.blocked.remove(remove);
|
||||||
process &p = th->parent();
|
th->handle_release();
|
||||||
|
|
||||||
// thread_exited deletes the thread, and returns true if the process
|
|
||||||
// should also now be deleted
|
|
||||||
if(!current && p.thread_exited(th))
|
|
||||||
delete &p;
|
|
||||||
} else {
|
} else {
|
||||||
queue.blocked.remove(remove);
|
queue.blocked.remove(remove);
|
||||||
log::spam(logs::sched, "Prune: readying unblocked thread %llx", th->koid());
|
log::spam(logs::sched, "Prune: readying unblocked thread %llx", th->koid());
|
||||||
|
|||||||
Reference in New Issue
Block a user