From b81343de354f3de86a8e51054b81a94a41ec0710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 9 Jul 2025 16:45:25 +0200 Subject: [PATCH 1/3] Fix `` grouping in documentation --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7bdbd30..613e4ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ //! ``` //! //! # Handling SIGTERM and SIGHUP -//! Handling of `SIGTERM and SIGHUP` can be enabled with `termination` feature. If this is enabled, +//! Handling of `SIGTERM` and `SIGHUP` can be enabled with `termination` feature. If this is enabled, //! the handler specified by `set_handler()` will be executed for `SIGINT`, `SIGTERM` and `SIGHUP`. //! From 93eeee872e654f67dc8249b331f2949b047d4a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 9 Jul 2025 17:13:07 +0200 Subject: [PATCH 2/3] Implement unix with sem_*(3) instead of pipes Using pipes works, but is unnecessarily thick for a one-shot application like this, and leaves 2 largely-useless pipe fds in the process permanently sem_post(3) is explicitly allowed to be used in signal handlers, this is practically the target application of POSIX semaphores readme_example/glibc before: 3735433 rt_sigaction(SIGBUS, {sa_handler=0x56412e4350e0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f57bb5dd050}, NULL, 8) = 0 3735433 pipe2([3, 4], O_CLOEXEC) = 0 3735433 fcntl(4, F_SETFL, O_RDONLY|O_NONBLOCK) = 0 3735433 rt_sigaction(SIGINT, {sa_handler=0x56412e40b410, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f57bb5dd050}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 3735433 rt_sigaction(SIGRT_1, {sa_handler=0x7f57bb627720, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f57bb5dd050}, NULL, 8) = 0 3735433 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 3735433 mmap(NULL, 2101248, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f57bb39d000 3735433 mprotect(0x7f57bb39e000, 2097152, PROT_READ|PROT_WRITE) = 0 3735433 rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0 3735433 clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f57bb59d990, parent_tid=0x7f57bb59d990, exit_signal=0, stack=0x7f57bb39d000, stack_size=0x1fff00, tls=0x7f57bb59d6c0} => {parent_tid=[3735438]}, 88) = 3735438 3735438 rseq(0x7f57bb59dfe0, 0x20, 0, 0x53053053 3735433 rt_sigprocmask(SIG_SETMASK, [], 3735438 <... rseq resumed>) = 0 3735433 <... rt_sigprocmask resumed>NULL, 8) = 0 3735438 set_robust_list(0x7f57bb59d9a0, 24) = 0 3735433 write(1, "Waiting for Ctrl-C...\n", 22 3735438 rt_sigprocmask(SIG_SETMASK, [], 3735433 <... write resumed>) = 22 3735438 <... rt_sigprocmask resumed>NULL, 8) = 0 3735438 mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0 3735433 futex(0x56415f72c028, FUTEX_WAIT_BITSET_PRIVATE, 4294967295, NULL, FUTEX_BITSET_MATCH_ANY 3735438 <... mmap resumed>) = 0x7f57b339d000 3735438 munmap(0x7f57b339d000, 12988416) = 0 3735438 munmap(0x7f57b8000000, 54120448) = 0 3735438 mprotect(0x7f57b4000000, 135168, PROT_READ|PROT_WRITE) = 0 3735438 sched_getaffinity(3735438, 32, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]) = 8 3735438 sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0 3735438 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f57bb7b5000 3735438 mprotect(0x7f57bb7b5000, 4096, PROT_NONE) = 0 3735438 sigaltstack({ss_sp=0x7f57bb7b6000, ss_flags=0, ss_size=8192}, NULL) = 0 3735438 prctl(PR_SET_NAME, "ctrl-c") = 0 3735438 read(3, 3735433 <... futex resumed>) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) 3735433 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} --- 3735433 write(4, "\0", 1) = 1 3735438 <... read resumed>"\0", 1) = 1 3735433 rt_sigreturn({mask=[]} 3735438 futex(0x56415f72c028, FUTEX_WAKE_PRIVATE, 1 3735433 <... rt_sigreturn resumed>) = 202 3735438 <... futex resumed>) = 0 3735433 futex(0x56415f72c028, FUTEX_WAIT_BITSET_PRIVATE, 4294967295, NULL, FUTEX_BITSET_MATCH_ANY 3735438 read(3, 3735433 <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable) 3735433 write(1, "Got it! Exiting...\n", 19) = 19 3735433 sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0 3735433 munmap(0x7f57bb7b8000, 12288) = 0 3735433 exit_group(0) = ? 3735438 <... read resumed> ) = ? 3735438 +++ exited with 0 +++ 3735433 +++ exited with 0 +++ After: 3864619 rt_sigaction(SIGBUS, {sa_handler=0x55d614829ed0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f8750f22050}, NULL, 8) = 0 3864619 rt_sigaction(SIGINT, {sa_handler=0x55d6148008c0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f8750f22050}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 3864619 rt_sigaction(SIGRT_1, {sa_handler=0x7f8750f6c720, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f8750f22050}, NULL, 8) = 0 3864619 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 3864619 mmap(NULL, 2101248, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f8750ce2000 3864619 mprotect(0x7f8750ce3000, 2097152, PROT_READ|PROT_WRITE) = 0 3864619 rt_sigprocmask(SIG_BLOCK, ~[], [], 8) = 0 3864619 clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x7f8750ee2990, parent_tid=0x7f8750ee2990, exit_signal=0, stack=0x7f8750ce2000, stack_size=0x1fff00, tls=0x7f8750ee26c0} => {parent_tid=[3864624]}, 88) = 3864624 3864624 rseq(0x7f8750ee2fe0, 0x20, 0, 0x53053053 3864619 rt_sigprocmask(SIG_SETMASK, [], 3864624 <... rseq resumed>) = 0 3864619 <... rt_sigprocmask resumed>NULL, 8) = 0 3864624 set_robust_list(0x7f8750ee29a0, 24) = 0 3864619 write(1, "Waiting for Ctrl-C...\n", 22 3864624 rt_sigprocmask(SIG_SETMASK, [], 3864619 <... write resumed>) = 22 3864624 <... rt_sigprocmask resumed>NULL, 8) = 0 3864624 mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0 3864619 futex(0x55d64f9de028, FUTEX_WAIT_BITSET_PRIVATE, 4294967295, NULL, FUTEX_BITSET_MATCH_ANY 3864624 <... mmap resumed>) = 0x7f8748ce2000 3864624 munmap(0x7f8748ce2000, 53600256) = 0 3864624 munmap(0x7f8750000000, 13508608) = 0 3864624 mprotect(0x7f874c000000, 135168, PROT_READ|PROT_WRITE) = 0 3864624 sched_getaffinity(3864624, 32, [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]) = 8 3864624 sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0 3864624 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f87510fa000 3864624 mprotect(0x7f87510fa000, 4096, PROT_NONE) = 0 3864624 sigaltstack({ss_sp=0x7f87510fb000, ss_flags=0, ss_size=8192}, NULL) = 0 3864624 prctl(PR_SET_NAME, "ctrl-c") = 0 3864624 futex(0x55d614867988, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY 3864619 <... futex resumed>) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) 3864619 --- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} --- 3864619 futex(0x55d614867988, FUTEX_WAKE_PRIVATE, 1 3864624 <... futex resumed>) = 0 3864619 <... futex resumed>) = 1 3864624 futex(0x55d64f9de028, FUTEX_WAKE_PRIVATE, 1 3864619 rt_sigreturn({mask=[]} 3864624 <... futex resumed>) = 0 3864624 futex(0x55d614867988, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY 3864619 <... rt_sigreturn resumed>) = 202 3864619 futex(0x55d64f9de028, FUTEX_WAIT_BITSET_PRIVATE, 4294967295, NULL, FUTEX_BITSET_MATCH_ANY) = -1 EAGAIN (Resource temporarily unavailable) 3864619 write(1, "Got it! Exiting...\n", 19) = 19 3864619 sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0 3864619 munmap(0x7f87510fd000, 12288) = 0 3864619 exit_group(0) = ? 3864624 <... futex resumed>) = ? 3864624 +++ exited with 0 +++ 3864619 +++ exited with 0 +++ --- Cargo.toml | 2 +- src/platform/unix/mod.rs | 103 ++++++--------------------------------- 2 files changed, 15 insertions(+), 90 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1b317e..2ae8670 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ readme = "README.md" rust-version = "1.69.0" [target.'cfg(unix)'.dependencies] -nix = { version = "0.30", default-features = false, features = ["fs", "signal"]} +nix = { version = "0.30", default-features = false, features = ["signal"]} [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Security", "Win32_System_Console"] } diff --git a/src/platform/unix/mod.rs b/src/platform/unix/mod.rs index 1948564..8808e25 100644 --- a/src/platform/unix/mod.rs +++ b/src/platform/unix/mod.rs @@ -8,12 +8,9 @@ // according to those terms. use crate::error::Error as CtrlcError; -use nix::unistd; -use std::os::fd::BorrowedFd; -use std::os::fd::IntoRawFd; -use std::os::unix::io::RawFd; -static mut PIPE: (RawFd, RawFd) = (-1, -1); +static mut SEMAPHORE: nix::libc::sem_t = unsafe { std::mem::zeroed() }; +const SEM_THREAD_SHARED: nix::libc::c_int = 0; /// Platform specific error type pub type Error = nix::Error; @@ -22,51 +19,12 @@ pub type Error = nix::Error; pub type Signal = nix::sys::signal::Signal; extern "C" fn os_handler(_: nix::libc::c_int) { - // Assuming this always succeeds. Can't really handle errors in any meaningful way. unsafe { - let fd = BorrowedFd::borrow_raw(PIPE.1); - let _ = unistd::write(fd, &[0u8]); + // No errors apply. EOVERFLOW is hypothetically possible but it's equivalent to a success for our oneshot use-case. + let _ = nix::libc::sem_post(&raw mut SEMAPHORE); } } -// pipe2(2) is not available on macOS, iOS, AIX, Haiku, etc., so we need to use pipe(2) and fcntl(2) -#[inline] -#[cfg(any( - target_vendor = "apple", - target_os = "haiku", - target_os = "aix", - target_os = "nto", -))] -fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> { - use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag}; - - let pipe = unistd::pipe()?; - - if flags.contains(OFlag::O_CLOEXEC) { - fcntl(&pipe.0, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?; - fcntl(&pipe.1, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?; - } - - if flags.contains(OFlag::O_NONBLOCK) { - fcntl(&pipe.0, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; - fcntl(&pipe.1, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; - } - - Ok((pipe.0.into_raw_fd(), pipe.1.into_raw_fd())) -} - -#[inline] -#[cfg(not(any( - target_vendor = "apple", - target_os = "haiku", - target_os = "aix", - target_os = "nto", -)))] -fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> { - let pipe = unistd::pipe2(flags)?; - Ok((pipe.0.into_raw_fd(), pipe.1.into_raw_fd())) -} - /// Register os signal handler. /// /// Must be called before calling [`block_ctrl_c()`](fn.block_ctrl_c.html) @@ -77,26 +35,9 @@ fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> { /// #[inline] pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { - use nix::fcntl; use nix::sys::signal; - PIPE = pipe2(fcntl::OFlag::O_CLOEXEC)?; - - let close_pipe = |e: nix::Error| -> Error { - // Try to close the pipes. close() should not fail, - // but if it does, there isn't much we can do - let _ = unistd::close(PIPE.1); - let _ = unistd::close(PIPE.0); - e - }; - - // Make sure we never block on write in the os handler. - if let Err(e) = fcntl::fcntl( - BorrowedFd::borrow_raw(PIPE.1), - fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_NONBLOCK), - ) { - return Err(close_pipe(e)); - } + nix::libc::sem_init(&raw mut SEMAPHORE, SEM_THREAD_SHARED, 0); let handler = signal::SigHandler::Handler(os_handler); #[cfg(not(target_os = "nto"))] @@ -110,13 +51,10 @@ pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { let new_action = signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty()); - let sigint_old = match signal::sigaction(signal::Signal::SIGINT, &new_action) { - Ok(old) => old, - Err(e) => return Err(close_pipe(e)), - }; + let sigint_old = signal::sigaction(signal::Signal::SIGINT, &new_action)?; if !overwrite && sigint_old.handler() != signal::SigHandler::SigDfl { signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap(); - return Err(close_pipe(nix::Error::EEXIST)); + return Err(nix::Error::EEXIST); } #[cfg(feature = "termination")] @@ -125,27 +63,27 @@ pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { Ok(old) => old, Err(e) => { signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap(); - return Err(close_pipe(e)); + return Err(e); } }; if !overwrite && sigterm_old.handler() != signal::SigHandler::SigDfl { signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap(); signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap(); - return Err(close_pipe(nix::Error::EEXIST)); + return Err(nix::Error::EEXIST); } let sighup_old = match signal::sigaction(signal::Signal::SIGHUP, &new_action) { Ok(old) => old, Err(e) => { signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap(); signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap(); - return Err(close_pipe(e)); + return Err(e); } }; if !overwrite && sighup_old.handler() != signal::SigHandler::SigDfl { signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap(); signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap(); signal::sigaction(signal::Signal::SIGHUP, &sighup_old).unwrap(); - return Err(close_pipe(nix::Error::EEXIST)); + return Err(nix::Error::EEXIST); } } @@ -157,24 +95,11 @@ pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { /// Must be called after calling [`init_os_handler()`](fn.init_os_handler.html). /// /// # Errors -/// Will return an error if a system error occurred. +/// None. /// #[inline] pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> { - use std::io; - let mut buf = [0u8]; - - // TODO: Can we safely convert the pipe fd into a std::io::Read - // with std::os::unix::io::FromRawFd, this would handle EINTR - // and everything for us. - loop { - match unistd::read(BorrowedFd::borrow_raw(PIPE.0), &mut buf[..]) { - Ok(1) => break, - Ok(_) => return Err(CtrlcError::System(io::ErrorKind::UnexpectedEof.into())), - Err(nix::errno::Errno::EINTR) => {} - Err(e) => return Err(e.into()), - } - } - + // The only realistic error is EINTR, which is restartable. + while nix::libc::sem_wait(&raw mut SEMAPHORE) == -1 {} Ok(()) } From 430f24481aa7c56358e2e89117531773473b21b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 9 Jul 2025 17:34:08 +0200 Subject: [PATCH 3/3] Use dispatch semaphores on apple, where POSIX semaphores are explicitly and officially broken --- Cargo.toml | 3 +++ src/platform/unix/mod.rs | 47 ++++++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2ae8670..8fffdc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,9 @@ rust-version = "1.69.0" [target.'cfg(unix)'.dependencies] nix = { version = "0.30", default-features = false, features = ["signal"]} +[target.'cfg(target_vendor = "apple")'.dependencies] +dispatch = "0.2" + [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Security", "Win32_System_Console"] } diff --git a/src/platform/unix/mod.rs b/src/platform/unix/mod.rs index 8808e25..cdd32f6 100644 --- a/src/platform/unix/mod.rs +++ b/src/platform/unix/mod.rs @@ -9,8 +9,43 @@ use crate::error::Error as CtrlcError; -static mut SEMAPHORE: nix::libc::sem_t = unsafe { std::mem::zeroed() }; -const SEM_THREAD_SHARED: nix::libc::c_int = 0; +#[cfg(not(target_vendor = "apple"))] +#[allow(static_mut_refs)] // rust-version = "1.69.0" +mod implementation { + static mut SEMAPHORE: nix::libc::sem_t = unsafe { std::mem::zeroed() }; + const SEM_THREAD_SHARED: nix::libc::c_int = 0; + + pub unsafe fn sem_init() { + nix::libc::sem_init(&mut SEMAPHORE as *mut _, SEM_THREAD_SHARED, 0); + } + + pub unsafe fn sem_post() { + // No errors apply. EOVERFLOW is hypothetically possible but it's equivalent to a success for our oneshot use-case. + let _ = nix::libc::sem_post(&mut SEMAPHORE as *mut _); + } + + pub unsafe fn sem_wait_forever() { + // The only realistic error is EINTR, which is restartable. + while nix::libc::sem_wait(&mut SEMAPHORE as *mut _) == -1 {} + } +} + +#[cfg(target_vendor = "apple")] +mod implementation { + static mut SEMAPHORE: dispatch::ffi::dispatch_semaphore_t = std::ptr::null_mut(); + + pub unsafe fn sem_init() { + SEMAPHORE = dispatch::ffi::dispatch_semaphore_create(0); + } + + pub unsafe fn sem_post() { + dispatch::ffi::dispatch_semaphore_signal(SEMAPHORE); + } + + pub unsafe fn sem_wait_forever() { + dispatch::ffi::dispatch_semaphore_wait(SEMAPHORE, dispatch::ffi::DISPATCH_TIME_FOREVER); + } +} /// Platform specific error type pub type Error = nix::Error; @@ -20,8 +55,7 @@ pub type Signal = nix::sys::signal::Signal; extern "C" fn os_handler(_: nix::libc::c_int) { unsafe { - // No errors apply. EOVERFLOW is hypothetically possible but it's equivalent to a success for our oneshot use-case. - let _ = nix::libc::sem_post(&raw mut SEMAPHORE); + implementation::sem_post(); } } @@ -37,7 +71,7 @@ extern "C" fn os_handler(_: nix::libc::c_int) { pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { use nix::sys::signal; - nix::libc::sem_init(&raw mut SEMAPHORE, SEM_THREAD_SHARED, 0); + implementation::sem_init(); let handler = signal::SigHandler::Handler(os_handler); #[cfg(not(target_os = "nto"))] @@ -99,7 +133,6 @@ pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> { /// #[inline] pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> { - // The only realistic error is EINTR, which is restartable. - while nix::libc::sem_wait(&raw mut SEMAPHORE) == -1 {} + implementation::sem_wait_forever(); Ok(()) }