diff options
-rw-r--r-- | kern/thread.c | 6 | ||||
-rw-r--r-- | kern/thread.h | 23 | ||||
-rw-r--r-- | kern/thread_i.h | 5 |
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. */ |