summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-02-08 21:58:38 +0100
committerRichard Braun <rbraun@sceen.net>2017-02-08 21:58:38 +0100
commite69a4c4c3ca62d816bb4542792bcc741a7360af2 (patch)
tree19516cdd779a8a759e26db3cbde4bc4103946dbc
parent05f3b97ee07e6af26613dfbfe57619a700aa349a (diff)
kern/thread: add wait channels
-rw-r--r--kern/mutex_i.h2
-rw-r--r--kern/sref.c2
-rw-r--r--kern/task.c18
-rw-r--r--kern/thread.c24
-rw-r--r--kern/thread.h19
-rw-r--r--kern/thread_i.h2
-rw-r--r--kern/work.c4
7 files changed, 62 insertions, 9 deletions
diff --git a/kern/mutex_i.h b/kern/mutex_i.h
index aaaf7cad..5e78a4da 100644
--- a/kern/mutex_i.h
+++ b/kern/mutex_i.h
@@ -77,7 +77,7 @@ mutex_wait(struct mutex *mutex, struct mutex_waiter *waiter)
unsigned int state;
do {
- thread_sleep(&mutex->lock);
+ thread_sleep(&mutex->lock, mutex, "mutex");
state = mutex_tryacquire_slow(mutex);
} while (state != MUTEX_UNLOCKED);
diff --git a/kern/sref.c b/kern/sref.c
index e1368c30..9bffbe9a 100644
--- a/kern/sref.c
+++ b/kern/sref.c
@@ -803,7 +803,7 @@ sref_manage(void *arg)
cpu_intr_save(&flags);
while (!sref_cache_is_dirty(cache)) {
- thread_sleep(NULL);
+ thread_sleep(NULL, cache, "sref");
}
cpu_intr_restore(flags);
diff --git a/kern/task.c b/kern/task.c
index e415cb65..f4586eed 100644
--- a/kern/task.c
+++ b/kern/task.c
@@ -29,6 +29,12 @@
#include <vm/vm_kmem.h>
#include <vm/vm_map.h>
+#ifdef __LP64__
+#define TASK_INFO_ADDR_FMT "%016lx"
+#else /* __LP64__ */
+#define TASK_INFO_ADDR_FMT "%08lx"
+#endif /* __LP64__ */
+
/*
* Kernel task and storage.
*/
@@ -138,9 +144,15 @@ task_info(struct task *task)
printk("task: name: %s, threads:\n", task->name);
list_for_each_entry(&task->threads, thread, task_node) {
- printk("task: %s: %p %c %.2s:%02hu %s\n", task->name, thread,
- thread_state_to_chr(thread), thread_schedclass_to_str(thread),
- thread_priority(thread), thread->name);
+ printk("task: " TASK_INFO_ADDR_FMT " %c %8s:" TASK_INFO_ADDR_FMT
+ " %.2s:%02hu %s\n",
+ (unsigned long)thread,
+ thread_state_to_chr(thread),
+ thread_wchan_desc(thread),
+ (unsigned long)thread_wchan_addr(thread),
+ thread_schedclass_to_str(thread),
+ thread_priority(thread),
+ thread->name);
}
spinlock_unlock(&task->lock);
diff --git a/kern/thread.c b/kern/thread.c
index 9c3a01be..239bbcfb 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -338,6 +338,20 @@ struct thread_zombie {
struct thread *thread;
};
+static void
+thread_set_wchan(struct thread *thread, const void *wchan_addr,
+ const char *wchan_desc)
+{
+ thread->wchan_addr = wchan_addr;
+ thread->wchan_desc = wchan_desc;
+}
+
+static void
+thread_clear_wchan(struct thread *thread)
+{
+ thread_set_wchan(thread, NULL, NULL);
+}
+
static const struct thread_sched_ops *
thread_get_sched_ops(const struct thread *thread)
{
@@ -551,6 +565,7 @@ thread_runq_wakeup_balancer(struct thread_runq *runq)
return;
}
+ thread_clear_wchan(runq->balancer);
runq->balancer->state = THREAD_RUNNING;
thread_runq_wakeup(runq, runq->balancer);
}
@@ -1680,6 +1695,7 @@ thread_init(struct thread *thread, void *stack, const struct thread_attr *attr,
thread->flags = 0;
thread->runq = NULL;
+ thread_set_wchan(thread, thread, "init");
thread->state = THREAD_SLEEPING;
thread->preempt = THREAD_SUSPEND_PREEMPT_LEVEL;
thread->pinned = 0;
@@ -1862,6 +1878,7 @@ thread_balance(void *arg)
for (;;) {
runq->idle_balance_ticks = THREAD_IDLE_BALANCE_TICKS;
+ thread_set_wchan(self, runq, "runq");
self->state = THREAD_SLEEPING;
runq = thread_runq_schedule(runq);
assert(runq == arg);
@@ -1992,6 +2009,7 @@ thread_setup_idler(struct thread_runq *runq)
cpumap_destroy(cpumap);
/* An idler thread needs special tuning */
+ thread_clear_wchan(idler);
idler->state = THREAD_RUNNING;
idler->runq = runq;
runq->idler = idler;
@@ -2129,7 +2147,8 @@ thread_join(struct thread *thread)
}
void
-thread_sleep(struct spinlock *interlock)
+thread_sleep(struct spinlock *interlock, const void *wchan_addr,
+ const char *wchan_desc)
{
struct thread_runq *runq;
struct thread *thread;
@@ -2146,6 +2165,7 @@ thread_sleep(struct spinlock *interlock)
spinlock_unlock(interlock);
}
+ thread_set_wchan(thread, wchan_addr, wchan_desc);
thread->state = THREAD_SLEEPING;
runq = thread_runq_schedule(runq);
@@ -2173,6 +2193,7 @@ thread_wakeup(struct thread *thread)
*/
if (thread->runq == NULL) {
assert(thread->state != THREAD_RUNNING);
+ thread_clear_wchan(thread);
thread->state = THREAD_RUNNING;
} else {
/*
@@ -2192,6 +2213,7 @@ thread_wakeup(struct thread *thread)
return;
}
+ thread_clear_wchan(thread);
thread->state = THREAD_RUNNING;
thread_unlock_runq(runq, flags);
}
diff --git a/kern/thread.h b/kern/thread.h
index 074963de..c5405d7f 100644
--- a/kern/thread.h
+++ b/kern/thread.h
@@ -192,12 +192,17 @@ void thread_join(struct thread *thread);
* In any case, the preemption nesting level must strictly be one when calling
* this function.
*
+ * The wait channel describes the reason why the thread is sleeping. The
+ * address should refer to a relevant synchronization object, normally
+ * containing the interlock, but not necessarily.
+ *
* This is a low level thread control primitive that should only be called by
* higher thread synchronization functions.
*
* Implies a memory barrier.
*/
-void thread_sleep(struct spinlock *interlock);
+void thread_sleep(struct spinlock *interlock, const void *wchan_addr,
+ const char *wchan_desc);
/*
* Schedule a thread for execution on a processor.
@@ -242,6 +247,18 @@ void thread_tick_intr(void);
void thread_setscheduler(struct thread *thread, unsigned char policy,
unsigned short priority);
+static inline const void *
+thread_wchan_addr(const struct thread *thread)
+{
+ return thread->wchan_addr;
+}
+
+static inline const char *
+thread_wchan_desc(const struct thread *thread)
+{
+ return thread->wchan_desc;
+}
+
/*
* Return a character representation of the state of a thread.
*/
diff --git a/kern/thread_i.h b/kern/thread_i.h
index d004298f..eeee417c 100644
--- a/kern/thread_i.h
+++ b/kern/thread_i.h
@@ -94,6 +94,8 @@ struct thread {
/* Sleep/wakeup synchronization members */
struct thread_runq *runq;
+ const void *wchan_addr;
+ const char *wchan_desc;
unsigned short state;
/* Thread-local members */
diff --git a/kern/work.c b/kern/work.c
index 6c798fbb..3ba6d2b2 100644
--- a/kern/work.c
+++ b/kern/work.c
@@ -315,7 +315,7 @@ work_process(void *arg)
pool->nr_available_threads++;
do {
- thread_sleep(lock);
+ thread_sleep(lock, pool, "work_spr");
} while (pool->manager != NULL);
list_remove(&self->node);
@@ -351,7 +351,7 @@ work_process(void *arg)
pool->manager = self;
do {
- thread_sleep(lock);
+ thread_sleep(lock, pool, "work_mgr");
} while (work_pool_nr_works(pool) == 0);
pool->manager = NULL;