From de41bae84285c9cfafdb8f650782cddb1251e9b6 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 29 May 2024 18:09:46 -0300 Subject: [PATCH] options: handle EINTR and EAGAIN properly on sys_futex_wait on a few places --- options/internal/generic/threads.cpp | 3 ++- options/internal/include/mlibc/lock.hpp | 3 ++- options/posix/generic/pthread-stubs.cpp | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/options/internal/generic/threads.cpp b/options/internal/generic/threads.cpp index 3c1e70ed93..1ef07a4d32 100644 --- a/options/internal/generic/threads.cpp +++ b/options/internal/generic/threads.cpp @@ -157,7 +157,8 @@ int thread_mutex_lock(struct __mlibc_mutex *mutex) { // If the wait returns EAGAIN, that means that the mutex_waiters_bit was just unset by // some other thread. In this case, we should loop back around. - if (e && e != EAGAIN) + // Also do so in case of a signal being caught. + if (e && e != EAGAIN && e != EINTR) mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; // Opportunistically try to take the lock after we wake up. diff --git a/options/internal/include/mlibc/lock.hpp b/options/internal/include/mlibc/lock.hpp index aa05079ed1..8bff987477 100644 --- a/options/internal/include/mlibc/lock.hpp +++ b/options/internal/include/mlibc/lock.hpp @@ -50,7 +50,8 @@ struct FutexLockImpl { // If the wait returns EAGAIN, that means that the waitersBit was just unset by // some other thread. In this case, we should loop back around. - if (e && e != EAGAIN) + // Also loop around in case of a signal interrupting the wait + if (e && e != EAGAIN && e != EINTR) mlibc::panicLogger() << "sys_futex_wait() failed with error code " << e << frg::endlog; // Opportunistically try to take the lock after we wake up. diff --git a/options/posix/generic/pthread-stubs.cpp b/options/posix/generic/pthread-stubs.cpp index 775989b542..87ffed11f7 100644 --- a/options/posix/generic/pthread-stubs.cpp +++ b/options/posix/generic/pthread-stubs.cpp @@ -844,7 +844,10 @@ int pthread_once(pthread_once_t *once, void (*function) (void)) { }else{ // a different thread is currently running the initializer. __ensure(expected == onceLocked); - if(int e = mlibc::sys_futex_wait((int *)&once->__mlibc_done, onceLocked, nullptr); e) + // if the wait gets interrupted by a signal, check again. + // EAGAIN will also be a retry, as it means the other thread completed + // and changed the __mlibc_done variable to signal it before we actually went to sleep. + if(int e = mlibc::sys_futex_wait((int *)&once->__mlibc_done, onceLocked, nullptr); e && e != EINTR && e != EAGAIN) __ensure(!"sys_futex_wait() failed"); expected = __atomic_load_n(&once->__mlibc_done, __ATOMIC_ACQUIRE); }