2 Commits

Author SHA1 Message Date
Red Bear OS 26595f1624 Tier 2: robust mutex cleanup in thread exit path
exit_current_thread() now calls mark_robust_mutexes_dead(this) before
thread teardown, ensuring robust mutexes held by exiting threads are
properly marked as dead and ownership transferred to waiters.
2026-07-02 21:40:50 +03:00
Red Bear OS 9774052fd1 Fix non-robust mutex ENOTRECOVERABLE false positive
For non-robust mutexes, never check mutex_owner_id_is_live or return
ENOTRECOVERABLE when the owner appears dead. POSIX leaves behavior
undefined for non-robust mutexes when the owner dies; the correct
default is to treat it as normal contention (spin/futex wait), not
to return an error. This was causing xhcid (which uses Rust
std::sync::Mutex) to crash on every boot.

Also add stdint.h to sched.h sys_includes for cpu_set_t uint64_t.
2026-07-02 16:39:27 +03:00
3 changed files with 6 additions and 15 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
# - "[SS|TSP] The <sched.h> header shall define the time_t type as described in <sys/types.h>."
# - "The <sched.h> header shall define the timespec structure as described in <time.h>."
# - "Inclusion of the <sched.h> header may make visible all symbols from the <time.h> header."
sys_includes = ["sys/types.h"]
sys_includes = ["sys/types.h", "stdint.h"]
include_guard = "_RELIBC_SCHED_H"
after_includes = """
#include <bits/timespec.h> // for timespec
+3
View File
@@ -317,6 +317,9 @@ pub unsafe fn exit_current_thread(retval: Retval) -> ! {
unsafe { header::tls::run_all_destructors() };
let this = current_thread().expect("failed to obtain current thread when exiting");
crate::sync::pthread_mutex::mark_robust_mutexes_dead(this);
let stack_base = this.stack_base;
let stack_size = this.stack_size;
+2 -14
View File
@@ -136,11 +136,7 @@ impl RlctMutex {
Err(thread) => {
let owner = thread & INDEX_MASK;
if !crate::pthread::mutex_owner_id_is_live(owner) {
if !self.robust {
return Err(Errno(ENOTRECOVERABLE));
}
if self.robust && !crate::pthread::mutex_owner_id_is_live(owner) {
let new_value = (thread & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
match self.inner.compare_exchange(
thread,
@@ -234,15 +230,7 @@ impl RlctMutex {
return Err(Errno(EDEADLK));
}
if current & FUTEX_OWNER_DIED != 0 && owner == 0 {
return Err(Errno(ENOTRECOVERABLE));
}
if current & FUTEX_OWNER_DIED != 0 || (owner != 0 && !crate::pthread::mutex_owner_id_is_live(owner)) {
if !self.robust {
return Err(Errno(ENOTRECOVERABLE));
}
if self.robust && (current & FUTEX_OWNER_DIED != 0 || (owner != 0 && !crate::pthread::mutex_owner_id_is_live(owner))) {
let new_value = (current & WAITING_BIT) | FUTEX_OWNER_DIED | this_thread;
match self.inner.compare_exchange(
current,