Use futex again for semaphore

This commit is contained in:
Jeremy Soller
2022-12-01 14:05:12 -07:00
parent 9b04c2e5d3
commit da4d277f12
+33 -24
View File
@@ -13,7 +13,6 @@ pub struct Semaphore {
lock: AtomicLock,
}
//TODO: fix to use futex again
impl Semaphore {
pub const fn new(value: c_int) -> Self {
Self {
@@ -23,33 +22,27 @@ impl Semaphore {
pub fn post(&self, count: c_int) {
self.lock.fetch_add(count, Ordering::SeqCst);
}
pub fn try_wait(&self) -> Result<(), ()> {
let mut value = self.lock.load(Ordering::SeqCst);
if value > 0 {
match self.lock.compare_exchange(
value,
value - 1,
Ordering::SeqCst,
Ordering::SeqCst
) {
Ok(_) => Ok(()),
Err(_) => Err(())
}
} else {
Err(())
}
self.lock.notify_all();
}
pub fn wait(&self, timeout_opt: Option<&timespec>) -> Result<(), ()> {
loop {
match self.try_wait() {
Ok(()) => {
return Ok(());
let value = self.lock.load(Ordering::SeqCst);
if value > 0 {
match self.lock.compare_exchange(
value,
value - 1,
Ordering::SeqCst,
Ordering::SeqCst
) {
Ok(_) => {
// Acquired
return Ok(());
}
Err(_) => ()
}
Err(()) => ()
// Try again (as long as value > 0)
continue;
}
if let Some(timeout) = timeout_opt {
let mut time = timespec::default();
@@ -57,10 +50,26 @@ impl Semaphore {
if (time.tv_sec > timeout.tv_sec) ||
(time.tv_sec == timeout.tv_sec && time.tv_nsec >= timeout.tv_nsec)
{
//Timeout happened, return error
return Err(())
} else {
// Use futex to wait for the next change, with a relative timeout
let mut relative = timespec {
tv_sec: timeout.tv_sec,
tv_nsec: timeout.tv_nsec,
};
while relative.tv_nsec < time.tv_nsec {
relative.tv_sec -= 1;
relative.tv_nsec += 1_000_000_000;
}
relative.tv_sec -= time.tv_sec;
relative.tv_nsec -= time.tv_nsec;
self.lock.wait_if(value, Some(&relative));
}
} else {
// Use futex to wait for the next change, without a timeout
self.lock.wait_if(value, None);
}
Sys::sched_yield();
}
}
}