From: ljsebald <ljs...@us...> - 2023-09-24 04:10:40
|
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 0b93371d65163e8fb9e5a1902d5ec45be3e0df0f (commit) from c52cd74ec56837fe9b10119651be3661311458c3 (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 0b93371d65163e8fb9e5a1902d5ec45be3e0df0f Author: Falco Girgis <gyr...@gm...> Date: Sat Sep 23 23:10:02 2023 -0500 Extended once_test to repro/verify deadlock issue (#312) - C++11's "std::async()" exposed an issue with the current implementation of kthread_once: it deadlocks when two separate threads attempt to use kthread_once on separate functions concurrently - I've extended the "once_test" to reproduce the issue with the kernel-level C API - The updated test simply spawns and joins another thread from within a "kthread_once" call, which also makes a "kthread_once" call ----------------------------------------------------------------------- Summary of changes: .../dreamcast/basic/threading/once/once_test.c | 61 ++++++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/examples/dreamcast/basic/threading/once/once_test.c b/examples/dreamcast/basic/threading/once/once_test.c index 3029894..451e550 100644 --- a/examples/dreamcast/basic/threading/once/once_test.c +++ b/examples/dreamcast/basic/threading/once/once_test.c @@ -11,6 +11,9 @@ the function. */ #include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> #include <kos/thread.h> #include <kos/once.h> @@ -22,18 +25,38 @@ #define UNUSED __attribute__((unused)) #define THD_COUNT 600 -kthread_once_t once = KTHREAD_ONCE_INIT; -spinlock_t lock = SPINLOCK_INITIALIZER; -int counter = 0; +static kthread_once_t once = KTHREAD_ONCE_INIT; +static spinlock_t lock = SPINLOCK_INITIALIZER; +static int counter = 0; -void once_func(void) { +static void inner_once_func(void) { spinlock_lock(&lock); ++counter; spinlock_unlock(&lock); } -void *thd_func(void *param UNUSED) { - kthread_t *cur = thd_get_current(); +static void *inner_thd_func(void *param UNUSED) { + static kthread_once_t inner_once = KTHREAD_ONCE_INIT; + const kthread_t *cur = thd_get_current(); + + printf("Thd %d: Attempting to call inner kthread_once\n", cur->tid); + kthread_once(&inner_once, &inner_once_func); + printf("Thd %d: inner kthread_once returned\n", cur->tid); + + return NULL; +} + +static void once_func(void) { + const kthread_t *cur = thd_get_current(); + + printf("Thd %d: Spawning subthread\n", cur->tid); + kthread_t *subthd = thd_create(0, &inner_thd_func, NULL); + thd_join(subthd, NULL); + printf("Thd %d: Joined subthread\n", cur->tid); +} + +static void *thd_func(void *param UNUSED) { + const kthread_t *cur = thd_get_current(); printf("Thd %d: Attempting to call kthread_once\n", cur->tid); kthread_once(&once, &once_func); @@ -44,7 +67,7 @@ void *thd_func(void *param UNUSED) { KOS_INIT_FLAGS(INIT_DEFAULT); int main(int argc, char *argv[]) { - int i; + int i, retval, success = 1; kthread_t *thds[THD_COUNT]; cont_btn_callback(0, CONT_START | CONT_A | CONT_B | CONT_X | CONT_Y, @@ -57,16 +80,32 @@ int main(int argc, char *argv[]) { for(i = 0; i < THD_COUNT; ++i) { thds[i] = thd_create(0, &thd_func, NULL); + + if(!thds[i]) { + fprintf(stderr, "Failed to spawn thread[%d]: %s\n", + i, strerror(errno)); + success = 0; + } } printf("Waiting for the threads to finish\n"); for(i = 0; i < THD_COUNT; ++i) { - thd_join(thds[i], NULL); + if((retval = thd_join(thds[i], NULL) < 0)) { + fprintf(stderr, "Failed to join thread[%d]: %d\n", + i, retval); + success = 0; + } } - printf("Final counter value: %d (expected 1)\n", counter); - printf("Test finished\n"); + printf("Final counter value: %d (expected 1)\n\n", counter); - return 0; + if(success && counter == 1) { + printf("***** ONCE_TEST PASSED *****\n"); + return EXIT_SUCCESS; + } + else { + fprintf(stderr, "***** ONCE_TEST FAILED *****\n"); + return EXIT_FAILURE; + } } hooks/post-receive -- A pseudo Operating System for the Dreamcast. |