From: falcovorbis <fal...@us...> - 2023-09-23 18:48:22
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via c52cd74ec56837fe9b10119651be3661311458c3 (commit) via 22597655b336a1570d641f9fa739b56cca00a047 (commit) from a8e11c4bcc9c74b2d2ff6069a221106e2465fbda (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit c52cd74ec56837fe9b10119651be3661311458c3 Merge: a8e11c4 2259765 Author: Falco Girgis <gyr...@gm...> Date: Sat Sep 23 13:47:56 2023 -0500 Merge pull request #313 from KallistiOS/once-again Rework once controls, once again. commit 22597655b336a1570d641f9fa739b56cca00a047 Author: Lawrence Sebald <ljs...@us...> Date: Sat Sep 23 09:36:19 2023 -0400 Rework once controls, once again. 1. Make them into a tristate value: not done, in progress, and done. 2. Use a condvar to wake up any threads that try to use the same once control before the first caller's function finishes. 3. Make sure another once control can be used while one's init routine is being run. Even if that is done in another thread that the init routine from the first is waiting on somehow (looking at you libstdc++). ----------------------------------------------------------------------- Summary of changes: kernel/thread/once.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/kernel/thread/once.c b/kernel/thread/once.c index 1d3f29c..b244782 100644 --- a/kernel/thread/once.c +++ b/kernel/thread/once.c @@ -4,39 +4,66 @@ Copyright (C) 2009, 2023 Lawrence Sebald */ -#include <malloc.h> -#include <stdio.h> -#include <assert.h> #include <errno.h> #include <kos/once.h> #include <kos/mutex.h> -#include <arch/irq.h> +#include <kos/cond.h> /* The lock used to make sure multiple threads don't try to run the same routine at the same time. */ -static mutex_t lock = RECURSIVE_MUTEX_INITIALIZER; +static mutex_t lock = MUTEX_INITIALIZER; +static condvar_t cond = COND_INITIALIZER; + +#define ONCE_COMPLETE 1 +#define ONCE_INPROGRESS -1 int kthread_once(kthread_once_t *once_control, void (*init_routine)(void)) { - if(!once_control || *once_control < 0 || *once_control > 1) { + if(!once_control) { errno = EINVAL; return -1; } /* Lock the lock. */ - if(mutex_lock(&lock) == -1) { + if(mutex_lock(&lock)) { return -1; } /* If the function has already been run, unlock the lock and return. */ - if(*once_control) { + if(*once_control == ONCE_COMPLETE) { mutex_unlock(&lock); return 0; } - /* Run the function, set the control, and unlock the lock. */ - *once_control = 1; + /* If the function is in progress in another thread, wait for it to finish. + We share one mutex/condvar across all once controls, so we have to do + this in a loop to prevent spurious wakeups. */ + if(*once_control == ONCE_INPROGRESS) { + while(*once_control == ONCE_INPROGRESS) { + if(cond_wait(&cond, &lock)) { + mutex_unlock(&lock); + return -1; + } + } + + /* We'll only get here once the once control has been set to 1, so + return success. */ + mutex_unlock(&lock); + return 0; + } + + /* Set that we're in progress and unlock the lock (so other once controls + can be used). Once that's done, run the function, re-obtain the lock, + set that the function has been run and wake all threads waiting on this + particular once control. */ + *once_control = ONCE_INPROGRESS; + mutex_unlock(&lock); + init_routine(); + + mutex_lock(&lock); + *once_control = ONCE_COMPLETE; + cond_broadcast(&cond); mutex_unlock(&lock); return 0; hooks/post-receive -- A pseudo Operating System for the Dreamcast. |