Files
RedBear-OS/local/patches/relibc/absorbed/P3-semaphore-fixes.patch
T
vasilito 5851974b20 feat: build system transition to release fork + archive hardening
Release fork infrastructure:
- REDBEAR_RELEASE=0.1.1 with offline enforcement (fetch/distclean/unfetch blocked)
- 195 BLAKE3-verified source archives in standard format
- Atomic provisioning via provision-release.sh (staging + .complete sentry)
- 5-phase improvement plan: restore format auto-detection, source tree
  validation (validate-source-trees.py), archive-map.json, REPO_BINARY fallback

Archive normalization:
- Removed 87 duplicate/unversioned archives from shared pool
- Regenerated all archives in consistent format with source/ + recipe.toml
- BLAKE3SUMS and manifest.json generated from stable tarball set

Patch management:
- verify-patches.sh: pre-sync dry-run report (OK/REVERSED/CONFLICT)
- 121 upstream-absorbed patches moved to absorbed/ directories
- 43 active patches verified clean against rebased sources
- Stress test: base updated to upstream HEAD, relibc reset and patched

Compilation fixes:
- relibc: Vec imports in redox-rt (proc.rs, lib.rs, sys.rs)
- relibc: unsafe from_raw_parts in mod.rs (2024 edition)
- fetch.rs: rev comparison handles short/full hash prefixes
- kibi recipe: corrected rev mismatch

New scripts: restore-sources.sh, provision-release.sh, verify-sources-archived.sh,
check-upstream-releases.sh, validate-source-trees.py, verify-patches.sh,
repair-archive-format.sh, generate-manifest.py

Documentation: AGENTS.md, README.md, local/AGENTS.md updated for release fork model
2026-05-02 01:41:17 +01:00

436 lines
12 KiB
Diff

diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs
--- a/src/sync/semaphore.rs
+++ b/src/sync/semaphore.rs
@@ -2,8 +2,10 @@
//TODO: improve implementation
use crate::{
+ error::{Errno, Result},
header::{
bits_timespec::timespec,
+ errno::{EINVAL, ETIMEDOUT},
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec_realtime_to_monotonic},
},
platform::types::{c_uint, clockid_t},
@@ -30,12 +32,12 @@
crate::sync::futex_wake(&self.count, i32::MAX);
}
- pub fn try_wait(&self) -> u32 {
+ pub fn try_wait(&self) -> bool {
loop {
let value = self.count.load(Ordering::SeqCst);
if value == 0 {
- return 0;
+ return false;
}
match self.count.compare_exchange_weak(
@@ -45,20 +47,16 @@
Ordering::SeqCst,
) {
Ok(_) => {
- // Acquired
- return value;
+ return true;
}
Err(_) => (),
}
- // Try again (as long as value > 0)
}
}
- pub fn wait(&self, timeout_opt: Option<&timespec>, clock_id: clockid_t) -> Result<(), ()> {
+ pub fn wait(&self, timeout_opt: Option<&timespec>, clock_id: clockid_t) -> Result<()> {
loop {
- let value = self.try_wait();
-
- if value == 0 {
+ if self.try_wait() {
return Ok(());
}
@@ -68,17 +66,20 @@
CLOCK_MONOTONIC => timeout.clone(),
CLOCK_REALTIME => match timespec_realtime_to_monotonic(timeout.clone()) {
Ok(relative) => relative,
- Err(_) => return Err(()),
+ Err(_) => return Err(Errno(EINVAL)),
},
- _ => return Err(()),
+ _ => return Err(Errno(EINVAL)),
};
- crate::sync::futex_wait(&self.count, value, Some(&relative));
+ match crate::sync::futex_wait(&self.count, 0, Some(&relative)) {
+ crate::sync::FutexWaitResult::TimedOut => return Err(Errno(ETIMEDOUT)),
+ crate::sync::FutexWaitResult::Waited | crate::sync::FutexWaitResult::Stale => {}
+ }
} else {
- // Use futex to wait for the next change, without a timeout
- crate::sync::futex_wait(&self.count, value, None);
+ crate::sync::futex_wait(&self.count, 0, None);
}
}
}
+
pub fn value(&self) -> c_uint {
self.count.load(Ordering::SeqCst)
}
diff --git a/src/header/semaphore/mod.rs b/src/header/semaphore/mod.rs
--- a/src/header/semaphore/mod.rs
+++ b/src/header/semaphore/mod.rs
@@ -3,12 +3,20 @@
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
use crate::{
+ error::{Errno, ResultExt},
header::{
bits_timespec::timespec,
+ errno::{EAGAIN, EINVAL},
+ fcntl::{O_CREAT, O_EXCL, O_RDWR},
+ sys_mman::{MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE, mmap, munmap, shm_open, shm_unlink},
+ sys_stat::stat,
time::{CLOCK_MONOTONIC, CLOCK_REALTIME},
+ unistd::close,
},
- platform::types::{c_char, c_int, c_long, c_uint, clockid_t},
+ out::Out,
+ platform::{ERRNO, Pal, Sys, types::{c_char, c_int, c_long, c_uint, clockid_t, mode_t, c_void}},
};
+use core::{mem, ptr};
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
// TODO: Statically verify size and align
@@ -20,10 +28,90 @@
}
pub type RlctSempahore = crate::sync::Semaphore;
+#[repr(C)]
+struct NamedSemaphore {
+ sem: RlctSempahore,
+}
+
+const SEM_FAILED_PTR: *mut sem_t = usize::MAX as *mut sem_t;
+
+unsafe fn map_named_semaphore(
+ name: *const c_char,
+ oflag: c_int,
+ mode: mode_t,
+ value: c_uint,
+) -> Result<*mut sem_t, Errno> {
+ if name.is_null() {
+ return Err(Errno(EINVAL));
+ }
+
+ let mut shm_flags = O_RDWR;
+ if oflag & O_CREAT == O_CREAT {
+ shm_flags |= O_CREAT;
+ }
+ if oflag & O_EXCL == O_EXCL {
+ shm_flags |= O_EXCL;
+ }
+
+ let fd = unsafe { shm_open(name, shm_flags, mode) };
+ if fd < 0 {
+ return Err(Errno(ERRNO.get()));
+ }
+
+ let mut st = stat::default();
+ if let Err(err) = Sys::fstat(fd, Out::from_mut(&mut st)) {
+ let _ = close(fd);
+ return Err(err);
+ }
+
+ let size = mem::size_of::<NamedSemaphore>() as i64;
+ let created = st.st_size == 0;
+ if created {
+ if let Err(err) = Sys::ftruncate(fd, size) {
+ let _ = close(fd);
+ return Err(err);
+ }
+ } else if st.st_size < size {
+ let _ = close(fd);
+ return Err(Errno(EINVAL));
+ }
+
+ let mapped = unsafe {
+ mmap(
+ ptr::null_mut(),
+ size as usize,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0,
+ )
+ };
+ let _ = close(fd);
+ if mapped == MAP_FAILED {
+ return Err(Errno(ERRNO.get()));
+ }
+
+ let named = mapped.cast::<NamedSemaphore>();
+ if created {
+ unsafe {
+ named.write(NamedSemaphore {
+ sem: RlctSempahore::new(value),
+ });
+ }
+ }
+
+ Ok(named.cast())
+}
+
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_close.html>.
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
- todo!("named semaphores")
+ if sem.is_null() || sem == SEM_FAILED_PTR {
+ ERRNO.set(EINVAL);
+ return -1;
+ }
+
+ unsafe { munmap(sem.cast::<c_void>(), mem::size_of::<NamedSemaphore>()) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_destroy.html>.
@@ -51,12 +139,25 @@
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_open.html>.
// TODO: va_list
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_open(
name: *const c_char,
- oflag: c_int, /* (va_list) value: c_uint */
+ oflag: c_int,
+ mut args: ...,
) -> *mut sem_t {
- todo!("named semaphores")
+ let (mode, value) = if oflag & O_CREAT == O_CREAT {
+ (unsafe { args.arg::<mode_t>() }, unsafe { args.arg::<c_uint>() })
+ } else {
+ (0o600 as mode_t, 0)
+ };
+
+ match unsafe { map_named_semaphore(name, oflag, mode, value) } {
+ Ok(sem) => sem,
+ Err(Errno(errno)) => {
+ ERRNO.set(errno);
+ SEM_FAILED_PTR
+ }
+ }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_post.html>.
@@ -70,23 +171,27 @@
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_trywait.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
- unsafe { get(sem) }.try_wait();
-
- 0
+ if unsafe { get(sem) }.try_wait() {
+ 0
+ } else {
+ crate::platform::ERRNO.set(EAGAIN);
+ -1
+ }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_unlink.html>.
-// #[unsafe(no_mangle)]
+#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
- todo!("named semaphores")
+ unsafe { shm_unlink(name) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_trywait.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int {
- if let Ok(()) = unsafe { get(sem) }.wait(None, CLOCK_MONOTONIC) {}; // TODO handle error
-
- 0
+ unsafe { get(sem) }
+ .wait(None, CLOCK_MONOTONIC)
+ .map(|()| 0)
+ .or_minus_one_errno()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_clockwait.html>.
@@ -96,18 +201,19 @@
clock_id: clockid_t,
abstime: *const timespec,
) -> c_int {
- if let Ok(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), clock_id) {}; // TODO handle error
-
- 0
+ unsafe { get(sem) }
+ .wait(Some(&unsafe { (*abstime).clone() }), clock_id)
+ .map(|()| 0)
+ .or_minus_one_errno()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_timedwait.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sem_timedwait(sem: *mut sem_t, abstime: *const timespec) -> c_int {
- if let Ok(()) = unsafe { get(sem) }.wait(Some(&unsafe { (*abstime).clone() }), CLOCK_REALTIME) {
- }; // TODO handle error
-
- 0
+ unsafe { get(sem) }
+ .wait(Some(&unsafe { (*abstime).clone() }), CLOCK_REALTIME)
+ .map(|()| 0)
+ .or_minus_one_errno()
}
unsafe fn get<'any>(sem: *mut sem_t) -> &'any RlctSempahore {
diff --git a/src/header/semaphore/cbindgen.toml b/src/header/semaphore/cbindgen.toml
--- a/src/header/semaphore/cbindgen.toml
+++ b/src/header/semaphore/cbindgen.toml
@@ -2,6 +2,9 @@
include_guard = "_RELIBC_SEMAPHORE_H"
after_includes = """
#include <bits/timespec.h> // for timespec
+"""
+trailer = """
+#define SEM_FAILED ((sem_t *) -1)
"""
language = "C"
style = "Type"
diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk
--- a/tests/Makefile.tests.mk
+++ b/tests/Makefile.tests.mk
@@ -312,6 +312,8 @@
grp/getgrgid_r \
grp/getgrnam_r \
grp/gr_iter \
+ semaphore/named \
+ semaphore/unnamed \
waitid \
waitpid \
waitpid_multiple \
diff --git a/tests/semaphore/unnamed.c b/tests/semaphore/unnamed.c
new file mode 100644
--- /dev/null
+++ b/tests/semaphore/unnamed.c
@@ -0,0 +1,57 @@
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <unistd.h>
+
+static sem_t sem;
+
+static void *post_after_delay(void *arg)
+{
+ (void)arg;
+ usleep(50000);
+ assert(sem_post(&sem) == 0);
+ return NULL;
+}
+
+static long elapsed_ns(const struct timespec *start, const struct timespec *end)
+{
+ return (end->tv_sec - start->tv_sec) * 1000000000L + (end->tv_nsec - start->tv_nsec);
+}
+
+int main(void)
+{
+ assert(sem_init(&sem, 0, 0) == 0);
+
+ errno = 0;
+ assert(sem_trywait(&sem) == -1);
+ assert(errno == EAGAIN);
+
+ struct timespec deadline;
+ assert(clock_gettime(CLOCK_REALTIME, &deadline) == 0);
+ deadline.tv_nsec += 20000000L;
+ if (deadline.tv_nsec >= 1000000000L) {
+ deadline.tv_sec += 1;
+ deadline.tv_nsec -= 1000000000L;
+ }
+
+ errno = 0;
+ assert(sem_timedwait(&sem, &deadline) == -1);
+ assert(errno == ETIMEDOUT);
+
+ pthread_t thread;
+ assert(pthread_create(&thread, NULL, post_after_delay, NULL) == 0);
+
+ struct timespec start;
+ struct timespec end;
+ assert(clock_gettime(CLOCK_MONOTONIC, &start) == 0);
+ assert(sem_wait(&sem) == 0);
+ assert(clock_gettime(CLOCK_MONOTONIC, &end) == 0);
+ assert(elapsed_ns(&start, &end) >= 20000000L);
+
+ assert(pthread_join(thread, NULL) == 0);
+ assert(sem_destroy(&sem) == 0);
+
+ return 0;
+}
diff --git a/tests/semaphore/named.c b/tests/semaphore/named.c
new file mode 100644
--- /dev/null
+++ b/tests/semaphore/named.c
@@ -0,0 +1,54 @@
+#include <assert.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+static sem_t *first;
+static sem_t *second;
+
+static void *post_after_delay(void *arg)
+{
+ (void)arg;
+ usleep(50000);
+ assert(sem_post(second) == 0);
+ return NULL;
+}
+
+static long elapsed_ns(const struct timespec *start, const struct timespec *end)
+{
+ return (end->tv_sec - start->tv_sec) * 1000000000L + (end->tv_nsec - start->tv_nsec);
+}
+
+int main(void)
+{
+ char name[64];
+ snprintf(name, sizeof(name), "/relibc_named_sem_%ld", (long)getpid());
+
+ sem_unlink(name);
+
+ first = sem_open(name, O_CREAT | O_EXCL, 0600, 0);
+ assert(first != SEM_FAILED);
+ second = sem_open(name, 0);
+ assert(second != SEM_FAILED);
+
+ pthread_t thread;
+ assert(pthread_create(&thread, NULL, post_after_delay, NULL) == 0);
+
+ struct timespec start;
+ struct timespec end;
+ assert(clock_gettime(CLOCK_MONOTONIC, &start) == 0);
+ assert(sem_wait(first) == 0);
+ assert(clock_gettime(CLOCK_MONOTONIC, &end) == 0);
+ assert(elapsed_ns(&start, &end) >= 20000000L);
+
+ assert(pthread_join(thread, NULL) == 0);
+ assert(sem_close(second) == 0);
+ assert(sem_close(first) == 0);
+ assert(sem_unlink(name) == 0);
+
+ return 0;
+}