use crate::{errno, name, UnwrapOS as _};
use sem_safe::named::{OpenFlags, Semaphore};
use std::io;
#[test]
fn basic() {
let name = &name("basic");
let s1 = Semaphore::open(name, OpenFlags::Create {
exclusive: true,
mode: 0o600,
value: 2,
})
.unwrap_os();
let s2 = Semaphore::open(name, OpenFlags::Create {
exclusive: false,
mode: 0o000, value: 0, })
.unwrap_os();
let s3 = Semaphore::open(name, OpenFlags::AccessOnly).unwrap_os();
s2.sem_ref().wait().unwrap_os();
s3.sem_ref().wait().unwrap_os();
s3.sem_ref().post().unwrap_os();
s2.sem_ref().post().unwrap_os();
s1.sem_ref().post().unwrap_os();
s1.sem_ref().wait().unwrap_os();
s1.sem_ref().wait().unwrap_os();
s1.sem_ref().wait().unwrap_os();
[&s1, &s2, &s3].map(|sem| {
let r = sem.sem_ref().try_wait();
assert!(r.is_err());
assert_eq!(errno(), libc::EAGAIN);
assert_eq!(r.map_errno().unwrap_err().kind(), io::ErrorKind::WouldBlock);
});
Semaphore::unlink(name).unwrap_os();
let r = Semaphore::unlink(name);
assert!(r.is_err());
assert_eq!(errno(), libc::ENOENT);
assert_eq!(r.map_errno().unwrap_err().kind(), io::ErrorKind::NotFound);
drop([s2, s3]);
unsafe { s1.close() }.unwrap_os();
}
#[test]
fn already_exists() {
let name = &name("already_exists");
let create_exclusive = || {
Semaphore::open(name, OpenFlags::Create {
exclusive: true,
mode: 0o600,
value: 0,
})
};
let remove = || Semaphore::unlink(name).unwrap_os();
drop(create_exclusive().unwrap_os());
let r1 = create_exclusive();
assert!(r1.is_err());
assert_eq!(errno(), libc::EEXIST);
assert_eq!(r1.map_errno().unwrap_err().kind(), io::ErrorKind::AlreadyExists);
remove();
assert!(create_exclusive().is_ok());
remove();
}
#[cfg_attr(any(target_os = "freebsd", // This has SEM_VALUE_MAX=INT_MAX but doesn't enforce that.
target_os = "netbsd", target_os = "openbsd"), // These have SEM_VALUE_MAX=UINT_MAX
ignore)]
#[test]
fn excessive_value() {
let r = Semaphore::open(&name("excessive_value"), OpenFlags::Create {
exclusive: true,
mode: 0o600,
value: core::ffi::c_uint::MAX,
});
assert!(r.is_err());
assert_eq!(errno(), libc::EINVAL);
assert_eq!(r.map_errno().unwrap_err().kind(), io::ErrorKind::InvalidInput);
}
#[test]
fn missing() {
let r = Semaphore::open(&name("missing"), OpenFlags::AccessOnly);
assert!(r.is_err());
assert_eq!(errno(), libc::ENOENT);
assert_eq!(r.map_errno().unwrap_err().kind(), io::ErrorKind::NotFound);
}
#[test]
#[allow(clippy::print_stdout, clippy::dbg_macro)]
fn fmt() {
let name = &name("fmt");
let semaphore = Semaphore::open(name, OpenFlags::Create {
exclusive: true,
mode: 0o600,
value: 42,
})
.unwrap_os();
println!("Displayed: {semaphore}");
dbg!(&semaphore);
dbg!(semaphore.sem_ref());
println!("Displayed ref: {}", semaphore.sem_ref());
Semaphore::unlink(name).unwrap_os();
}
#[cfg(feature = "anonymous")]
#[test]
fn anonymous() {
use std::ffi::CStr;
const INIT_UNIQUE: &CStr =
if let Ok(cstr) = CStr::from_bytes_with_nul(b"/yv_dzpRXevTMrIb_QpkSpg\0") {
cstr } else {
panic!() };
let _dos_attack = Semaphore::open(INIT_UNIQUE, OpenFlags::Create {
exclusive: true,
mode: 0o666,
value: 666,
})
.unwrap_os();
let anon = Semaphore::anonymous().unwrap_os();
anon.sem_ref().post().unwrap_os();
anon.sem_ref().wait().unwrap_os();
Semaphore::unlink(INIT_UNIQUE).unwrap_os();
}