From 6c4f56723c24bbf2f21c5a29f81b30917f9144e1 Mon Sep 17 00:00:00 2001 From: Ruize Tang <1466040111@qq.com> Date: Mon, 11 Nov 2024 20:41:56 +0800 Subject: [PATCH] Fix futex lost wakeup --- kernel/src/process/posix_thread/futex.rs | 9 +- test/apps/pthread/pthread_signal_test.c | 109 +++++++++++++++++++++++ 2 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 test/apps/pthread/pthread_signal_test.c diff --git a/kernel/src/process/posix_thread/futex.rs b/kernel/src/process/posix_thread/futex.rs index 26af862c..c44e9beb 100644 --- a/kernel/src/process/posix_thread/futex.rs +++ b/kernel/src/process/posix_thread/futex.rs @@ -253,7 +253,9 @@ impl FutexBucket { } let item = item_cursor.remove().unwrap(); - item.wake(); + if !item.wake() { + continue; + } count += 1; } @@ -323,8 +325,9 @@ impl FutexItem { (futex_item, waiter) } - pub fn wake(&self) { - self.waker.wake_up(); + #[must_use] + pub fn wake(&self) -> bool { + self.waker.wake_up() } pub fn match_up(&self, another: &Self) -> bool { diff --git a/test/apps/pthread/pthread_signal_test.c b/test/apps/pthread/pthread_signal_test.c new file mode 100644 index 00000000..c84c4206 --- /dev/null +++ b/test/apps/pthread/pthread_signal_test.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MPL-2.0 +// A regression test for the futex lost wakeup bug fixed in https://github.com/asterinas/asterinas/pull/1642 + +#include +#include +#include +#include +#include +#include + +pthread_mutex_t mutex; +atomic_int sync_flag = ATOMIC_VAR_INIT(0); // Atomic flag for synchronization + +// Signal handler for SIGUSR1 +void signal_handler(int signum) +{ + atomic_store(&sync_flag, 2); +} + +// Thread function that tries to lock the mutex and waits if it is locked +void *thread_function(void *arg) +{ + printf("Thread: Trying to lock mutex...\n"); + + // Set the atomic flag to signal the main thread + atomic_store(&sync_flag, 1); + + // Try to lock the mutex + pthread_mutex_lock(&mutex); + printf("Thread: Got the mutex!\n"); + + printf("Thread: Exiting.\n"); + pthread_mutex_unlock(&mutex); + + // Set the atomic flag to signal the main thread + atomic_store(&sync_flag, 3); + return NULL; +} + +int main() +{ + pthread_t thread; + + // Initialize mutex + if (pthread_mutex_init(&mutex, NULL) != 0) { + perror("Mutex initialization failed"); + return -1; + } + + // Set up signal handler for SIGUSR1 + struct sigaction sa; + sa.sa_handler = signal_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL) == -1) { + perror("sigaction failed"); + return -1; + } + + // Main thread locks the mutex + pthread_mutex_lock(&mutex); + printf("Main thread: Mutex locked.\n"); + + // Create the second thread + if (pthread_create(&thread, NULL, thread_function, NULL) != 0) { + perror("Thread creation failed"); + return -1; + } + + // Detach the thread to allow it to run independently + if (pthread_detach(thread) != 0) { + perror("Thread detachment failed"); + return -1; + } + + // Wait for the second thread to prepare + while (atomic_load(&sync_flag) != 1) { + } + sleep(1); + + // Send signal to the second thread + pthread_kill(thread, SIGUSR1); + printf("Main thread: Signal sent to the thread.\n"); + + // Wait for the second thread to process signal + while (atomic_load(&sync_flag) != 2) { + } + sleep(1); + + // Unlock the mutex + pthread_mutex_unlock(&mutex); + printf("Main thread: Mutex unlocked.\n"); + + // Wait for the second thread to exit + int count = 3; + while (atomic_load(&sync_flag) != 3 && count--) { + sleep(1); + } + if (atomic_load(&sync_flag) != 3) { + printf("ERROR: Thread does not exit after timeout.\n"); + exit(EXIT_FAILURE); + } + + // Destroy mutex + pthread_mutex_destroy(&mutex); + + printf("All tests passed.\n"); + return 0; +}