sched: track wait queue ownership

This commit is contained in:
Microindole 2026-05-12 23:30:32 +08:00
parent b92453788b
commit 5f3472f651
No known key found for this signature in database
GPG Key ID: 22FB34CD2133ACA1
4 changed files with 46 additions and 22 deletions

View File

@ -67,6 +67,7 @@ struct wait_queue {
* @wake_tick: Timer tick deadline for sleeping threads. * @wake_tick: Timer tick deadline for sleeping threads.
* @next: Run queue link owned by the scheduler. * @next: Run queue link owned by the scheduler.
* @wait_next: Wait queue link owned by wait queue code. * @wait_next: Wait queue link owned by wait queue code.
* @wait_queue: Wait queue currently owning @wait_next, or NULL.
* @name: Diagnostic thread name. * @name: Diagnostic thread name.
* *
* This structure is public only as an early-stage compromise. Long term, most * This structure is public only as an early-stage compromise. Long term, most
@ -84,6 +85,7 @@ struct thread {
uint64_t wake_tick; uint64_t wake_tick;
struct thread *next; struct thread *next;
struct thread *wait_next; struct thread *wait_next;
struct wait_queue *wait_queue;
char name[32]; char name[32];
}; };

View File

@ -86,6 +86,7 @@ struct thread *kernel_thread_create(
thread->wake_tick = 0; thread->wake_tick = 0;
thread->next = 0; thread->next = 0;
thread->wait_next = 0; thread->wait_next = 0;
thread->wait_queue = 0;
copy_thread_name(thread->name, sizeof(thread->name), name); copy_thread_name(thread->name, sizeof(thread->name), name);
spin_lock_irqsave(&scheduler_lock, &flags); spin_lock_irqsave(&scheduler_lock, &flags);
@ -98,6 +99,10 @@ struct thread *kernel_thread_create(
static void release_thread(struct thread *thread) static void release_thread(struct thread *thread)
{ {
if (thread->wait_queue != 0) {
panic("reaping thread still on wait queue");
}
early_log_puts("thread reaped "); early_log_puts("thread reaped ");
early_log_puts(thread->name); early_log_puts(thread->name);
early_log_puts("\n"); early_log_puts("\n");

View File

@ -18,7 +18,12 @@ void wait_queue_init(struct wait_queue *queue)
static void wait_queue_enqueue_locked( static void wait_queue_enqueue_locked(
struct wait_queue *queue, struct thread *thread) struct wait_queue *queue, struct thread *thread)
{ {
if (thread->wait_queue != 0) {
panic("thread already queued on wait queue");
}
thread->wait_next = 0; thread->wait_next = 0;
thread->wait_queue = queue;
if (queue->tail != 0) { if (queue->tail != 0) {
queue->tail->wait_next = thread; queue->tail->wait_next = thread;
@ -29,14 +34,36 @@ static void wait_queue_enqueue_locked(
queue->tail = thread; queue->tail = thread;
} }
static void wait_queue_remove_locked( static struct thread *wait_queue_remove_head_locked(struct wait_queue *queue)
{
struct thread *thread = queue->head;
if (thread == 0) {
return 0;
}
queue->head = thread->wait_next;
if (queue->head == 0) {
queue->tail = 0;
}
thread->wait_next = 0;
thread->wait_queue = 0;
return thread;
}
static int wait_queue_remove_locked(
struct wait_queue *queue, struct thread *target) struct wait_queue *queue, struct thread *target)
{ {
struct thread *prev = 0; struct thread *prev = 0;
struct thread *thread; struct thread *thread;
if (queue == 0 || target == 0) { if (queue == 0 || target == 0) {
return; return 0;
}
if (target->wait_queue != queue) {
return 0;
} }
for (thread = queue->head; thread != 0; thread = thread->wait_next) { for (thread = queue->head; thread != 0; thread = thread->wait_next) {
@ -52,11 +79,14 @@ static void wait_queue_remove_locked(
} }
thread->wait_next = 0; thread->wait_next = 0;
return; thread->wait_queue = 0;
return 1;
} }
prev = thread; prev = thread;
} }
panic("wait queue membership is inconsistent");
} }
static void wait_queue_mark_ready_locked(struct thread *thread) static void wait_queue_mark_ready_locked(struct thread *thread)
@ -178,18 +208,7 @@ void wait_queue_wake_one(struct wait_queue *queue)
} }
spin_lock_irqsave(&queue->lock, &flags); spin_lock_irqsave(&queue->lock, &flags);
if (queue->head == 0) { thread = wait_queue_remove_head_locked(queue);
spin_unlock_irqrestore(&queue->lock, flags);
return;
}
thread = queue->head;
queue->head = thread->wait_next;
if (queue->head == 0) {
queue->tail = 0;
}
thread->wait_next = 0;
wait_queue_mark_ready_locked(thread); wait_queue_mark_ready_locked(thread);
spin_unlock_irqrestore(&queue->lock, flags); spin_unlock_irqrestore(&queue->lock, flags);
} }
@ -205,13 +224,7 @@ void wait_queue_wake_all(struct wait_queue *queue)
spin_lock_irqsave(&queue->lock, &flags); spin_lock_irqsave(&queue->lock, &flags);
while (queue->head != 0) { while (queue->head != 0) {
thread = queue->head; thread = wait_queue_remove_head_locked(queue);
queue->head = thread->wait_next;
if (queue->head == 0) {
queue->tail = 0;
}
thread->wait_next = 0;
wait_queue_mark_ready_locked(thread); wait_queue_mark_ready_locked(thread);
} }
spin_unlock_irqrestore(&queue->lock, flags); spin_unlock_irqrestore(&queue->lock, flags);

View File

@ -72,6 +72,10 @@ void sched_selftest(void)
panic("kernel thread selftest state failed"); panic("kernel thread selftest state failed");
} }
if (first->wait_queue != 0 || second->wait_queue != 0) {
panic("kernel thread selftest wait queue ownership failed");
}
if ((first->stack_top & (STACK_ALIGNMENT - 1)) != 0 || if ((first->stack_top & (STACK_ALIGNMENT - 1)) != 0 ||
(second->stack_top & (STACK_ALIGNMENT - 1)) != 0) { (second->stack_top & (STACK_ALIGNMENT - 1)) != 0) {
panic("kernel thread selftest stack alignment failed"); panic("kernel thread selftest stack alignment failed");