summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kern/thread.c6
-rw-r--r--kern/thread.h23
-rw-r--r--kern/thread_i.h5
3 files changed, 32 insertions, 2 deletions
diff --git a/kern/thread.c b/kern/thread.c
index eb6f11a5..1631d9a5 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -1593,6 +1593,7 @@ thread_bootstrap_common(unsigned int cpu)
/* Initialize only what's needed during bootstrap */
booter = &thread_booters[cpu];
+ booter->nr_refs = 0; /* Make sure booters aren't destroyed */
booter->flags = 0;
booter->preempt = 1;
cpumap_fill(&booter->cpumap);
@@ -1699,6 +1700,7 @@ thread_init(struct thread *thread, void *stack, const struct thread_attr *attr,
cpumap = (attr->cpumap == NULL) ? &caller->cpumap : attr->cpumap;
assert(attr->policy < ARRAY_SIZE(thread_policy_table));
+ thread->nr_refs = 1;
thread->flags = 0;
thread->runq = NULL;
thread_set_wchan(thread, thread, "init");
@@ -1763,7 +1765,7 @@ thread_unlock_runq(struct thread_runq *runq, unsigned long flags)
spinlock_unlock_intr_restore(&runq->lock, flags);
}
-static void
+void
thread_destroy(struct thread *thread)
{
struct thread_runq *runq;
@@ -1796,7 +1798,7 @@ thread_join_common(struct thread *thread)
mutex_unlock(&thread->join_lock);
- thread_destroy(thread);
+ thread_unref(thread);
}
static void
diff --git a/kern/thread.h b/kern/thread.h
index 723497db..21be2ab7 100644
--- a/kern/thread.h
+++ b/kern/thread.h
@@ -36,6 +36,7 @@
#include <kern/assert.h>
#include <kern/cpumap.h>
#include <kern/macros.h>
+#include <machine/atomic.h>
#include <machine/tcb.h>
/*
@@ -260,6 +261,28 @@ void thread_tick_intr(void);
void thread_setscheduler(struct thread *thread, unsigned char policy,
unsigned short priority);
+static inline void
+thread_ref(struct thread *thread)
+{
+ unsigned long nr_refs;
+
+ nr_refs = atomic_fetchadd_ulong(&thread->nr_refs, 1);
+ assert(nr_refs != (unsigned long)-1);
+}
+
+static inline void
+thread_unref(struct thread *thread)
+{
+ unsigned long nr_refs;
+
+ nr_refs = atomic_fetchadd_ulong(&thread->nr_refs, -1);
+ assert(nr_refs != 0);
+
+ if (nr_refs == 1) {
+ thread_destroy(thread);
+ }
+}
+
static inline const void *
thread_wchan_addr(const struct thread *thread)
{
diff --git a/kern/thread_i.h b/kern/thread_i.h
index b3d09a05..a062773d 100644
--- a/kern/thread_i.h
+++ b/kern/thread_i.h
@@ -80,6 +80,9 @@ struct thread_fs_data {
struct thread {
struct tcb tcb;
+ /* Reference counter, must be changed atomically */
+ unsigned long nr_refs;
+
/* Flags must be changed atomically */
unsigned long flags;
@@ -130,6 +133,8 @@ struct thread {
#define THREAD_ATTR_DETACHED 0x1
+void thread_destroy(struct thread *thread);
+
/*
* Flag access functions.
*/