From c10167e23d0d15ab5e281f612e2829e7dc6313c5 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Fri, 10 Aug 2001 23:43:30 +0000 Subject: [PATCH] fixed bug in semaphore code where it wouldn't work right, period. Wonder why the bug wasn't found before? git-svn-id: svn+ssh://newos.org/var/svn/newos/newos@229 c25cc9d1-44fa-0310-b259-ad778cb1d433 --- include/kernel/thread.h | 4 +- kernel/sem.c | 118 +++++++++++++++++++++++++++--------------------- kernel/thread.c | 4 +- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/include/kernel/thread.h b/include/kernel/thread.h index baa9c63..3373a79 100644 --- a/include/kernel/thread.h +++ b/include/kernel/thread.h @@ -1,4 +1,4 @@ -/* +/* ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ @@ -67,7 +67,6 @@ struct thread { int pending_signals; bool in_kernel; int sem_count; - sem_id blocked_sem_id; int sem_deleted_retcode; void *args; struct proc *proc; @@ -103,6 +102,7 @@ void thread_snooze(time_t time); int thread_init(kernel_args *ka); void thread_exit(int retcode); struct thread *thread_get_current_thread(); +struct thread *thread_get_thread_struct(thread_id id); thread_id thread_get_current_thread_id(); int thread_wait_on_thread(thread_id id, int *retcode); int proc_wait_on_proc(proc_id id, int *retcode); diff --git a/kernel/sem.c b/kernel/sem.c index c0c428e..5cc887d 100644 --- a/kernel/sem.c +++ b/kernel/sem.c @@ -1,4 +1,4 @@ -/* +/* ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -31,10 +32,16 @@ static int sem_spinlock = 0; // used in functions that may put a bunch of threads in the run q at once #define READY_THREAD_CACHE_SIZE 16 +struct sem_timeout_args { + thread_id blocked_thread; + sem_id blocked_sem_id; + int sem_count; +}; + void dump_sem_list(int argc, char **argv) { int i; - + for(i=0; i= 0) { dprintf("0x%x\tid: 0x%x\t\tname: '%s'\n", &sems[i], sems[i].id, sems[i].name); @@ -62,8 +69,8 @@ static void dump_sem_info(int argc, char **argv) // if the argument looks like a hex number, treat it as such if(strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') { unsigned long num = atoul(argv[1]); - - if(num > KERNEL_BASE && num <= (KERNEL_BASE + (KERNEL_SIZE - 1))) { + + if(num > KERNEL_BASE && num <= (KERNEL_BASE + (KERNEL_SIZE - 1))) { // XXX semi-hack _dump_sem_info((struct sem_entry *)num); return; @@ -77,7 +84,7 @@ static void dump_sem_info(int argc, char **argv) return; } } - + // walk through the sem list, trying to match name for(i=0; istate = THREAD_STATE_READY; t->sem_deleted_retcode = return_code; - t->blocked_sem_id = 0; t->sem_count = 0; ready_threads[ready_threads_count++] = t; released_threads++; - + if(ready_threads_count == READY_THREAD_CACHE_SIZE) { - // put a batch of em in the runq at once + // put a batch of em in the runq at once GRAB_THREAD_LOCK(); for(; ready_threads_count > 0; ready_threads_count--) thread_enqueue_run_q(ready_threads[ready_threads_count - 1]); @@ -236,7 +242,7 @@ int sem_delete_etc(sem_id id, int return_code) sems[slot].id = -1; old_name = sems[slot].name; sems[slot].name = NULL; - + RELEASE_SEM_LOCK(sems[slot]); if(old_name != temp_sem_name) @@ -249,37 +255,45 @@ int sem_delete_etc(sem_id id, int return_code) } int_restore_interrupts(state); - + return err; } // Called from a timer handler. Wakes up a semaphore static int sem_timeout(void *data) { - struct thread *t = (struct thread *)data; - int slot = t->blocked_sem_id % MAX_SEMS; + struct sem_timeout_args *args = (struct sem_timeout_args *)data; + struct thread *t; + int slot; int state; - + + t = thread_get_thread_struct(args->blocked_thread); + if(t == NULL) + return INT_NO_RESCHEDULE; + slot = args->blocked_sem_id % MAX_SEMS; + state = int_disable_interrupts(); GRAB_SEM_LOCK(sems[slot]); - + // dprintf("sem_timeout: called on 0x%x sem %d, tid %d\n", to, to->sem_id, to->thread_id); - - if(sems[slot].id != t->blocked_sem_id) { + + if(sems[slot].id != args->blocked_sem_id) { // this thread was not waiting on this semaphore panic("sem_timeout: thid %d was trying to wait on sem %d which doesn't exist!\n", - t->id, t->blocked_sem_id); + args->blocked_thread, args->blocked_sem_id); } - + t = thread_dequeue_id(&sems[slot].q, t->id); if(t != NULL) { - sems[slot].count += t->sem_count; + sems[slot].count += args->sem_count; t->state = THREAD_STATE_READY; GRAB_THREAD_LOCK(); thread_enqueue_run_q(t); RELEASE_THREAD_LOCK(); } + // XXX handle possibly releasing more threads here + RELEASE_SEM_LOCK(sems[slot]); int_restore_interrupts(state); @@ -296,19 +310,19 @@ int sem_acquire_etc(sem_id id, int count, int flags, time_t timeout, int *delete int slot = id % MAX_SEMS; int state; int err = 0; - + if(sems_active == false) return -1; - + if(id < 0) return -1; if(count <= 0) return -1; - + state = int_disable_interrupts(); GRAB_SEM_LOCK(sems[slot]); - + if(sems[slot].id != id) { dprintf("sem_acquire_etc: invalid sem_id %d\n", id); err = -1; @@ -320,23 +334,26 @@ int sem_acquire_etc(sem_id id, int count, int flags, time_t timeout, int *delete err = -1; goto err; } - + if((sems[slot].count -= count) < 0) { // we need to block struct thread *t = thread_get_current_thread(); struct timer_event timer; // stick it on the heap, since we may be blocking here - + struct sem_timeout_args args; + t->next_state = THREAD_STATE_WAITING; - t->sem_count = count; - t->blocked_sem_id = id; + t->sem_count = min(-sems[slot].count, count); // store the count we need to restore upon release t->sem_deleted_retcode = 0; thread_enqueue(t, &sems[slot].q); - + if((flags & SEM_FLAG_TIMEOUT) != 0) { // dprintf("sem_acquire_etc: setting timeout sem for %d %d usecs, semid %d, tid %d\n", // timeout, sem_id, t->id); // set up an event to go off, with the thread struct as the data - timer_setup_timer(&sem_timeout, (void *)t, &timer); + args.blocked_sem_id = id; + args.blocked_thread = t->id; + args.sem_count = count; + timer_setup_timer(&sem_timeout, &args, &timer); timer_set_event(timeout, TIMER_MODE_ONESHOT, &timer); } @@ -353,7 +370,7 @@ int sem_acquire_etc(sem_id id, int count, int flags, time_t timeout, int *delete int_restore_interrupts(state); if(deleted_retcode != NULL) *deleted_retcode = t->sem_deleted_retcode; - return 0; + return 0; } err: @@ -376,16 +393,16 @@ int sem_release_etc(sem_id id, int count, int flags) int err = 0; struct thread *ready_threads[READY_THREAD_CACHE_SIZE]; int ready_threads_count = 0; - + if(sems_active == false) return -1; if(id < 0) - return -1; - + return -1; + if(count <= 0) return -1; - + state = int_disable_interrupts(); GRAB_SEM_LOCK(sems[slot]); @@ -399,7 +416,7 @@ int sem_release_etc(sem_id id, int count, int flags) int delta = count; if(sems[slot].count < 0) { struct thread *t = thread_lookat_queue(&sems[slot].q); - + delta = min(count, t->sem_count); t->sem_count -= delta; if(t->sem_count <= 0) { @@ -409,19 +426,18 @@ int sem_release_etc(sem_id id, int count, int flags) ready_threads[ready_threads_count++] = t; released_threads++; t->sem_count = 0; - t->blocked_sem_id = -1; t->sem_deleted_retcode = 0; } } if(ready_threads_count == READY_THREAD_CACHE_SIZE) { - // put a batch of em in the runq a once + // put a batch of em in the runq a once GRAB_THREAD_LOCK(); for(; ready_threads_count > 0; ready_threads_count--) thread_enqueue_run_q(ready_threads[ready_threads_count - 1]); RELEASE_THREAD_LOCK(); // ready_threads_count is back to 0 } - + sems[slot].count += delta; count -= delta; } @@ -437,7 +453,7 @@ int sem_release_etc(sem_id id, int count, int flags) thread_resched(); } RELEASE_THREAD_LOCK(); - goto outnolock; + goto outnolock; } err: diff --git a/kernel/thread.c b/kernel/thread.c index 2772a11..cf4688e 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -75,7 +75,6 @@ static struct thread_queue dead_q; static int _rand(); static void thread_entry(void); -static struct thread *thread_get_thread_struct(thread_id id); static struct thread *thread_get_thread_struct_locked(thread_id id); static struct proc *proc_get_proc_struct(proc_id id); static struct proc *proc_get_proc_struct_locked(proc_id id); @@ -472,7 +471,6 @@ static void _dump_thread_info(struct thread *t) dprintf("state: %s\n", state_to_text(t->state)); dprintf("next_state: %s\n", state_to_text(t->next_state)); dprintf("sem_count: 0x%x\n", t->sem_count); - dprintf("blocked_sem: 0x%x\n", t->blocked_sem_id); dprintf("proc: 0x%x\n", t->proc); dprintf("kernel_stack_region_id: 0x%x\n", t->kernel_stack_region_id); dprintf("kernel_stack_base: 0x%x\n", t->kernel_stack_base); @@ -999,7 +997,7 @@ struct thread *thread_get_current_thread() return CURR_THREAD; } -static struct thread *thread_get_thread_struct(thread_id id) +struct thread *thread_get_thread_struct(thread_id id) { struct thread *t; int state; -- 2.11.4.GIT