Skip to content

Instantly share code, notes, and snippets.

@thomcc
Created January 5, 2021 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomcc/315983b0a65276c2a407ba1dc51a4dd0 to your computer and use it in GitHub Desktop.
Save thomcc/315983b0a65276c2a407ba1dc51a4dd0 to your computer and use it in GitHub Desktop.
struct Semaphore {
raw: RawSemaphore,
count: AtomicIsize,
}
impl Semaphore {
#[inline]
pub fn new(n: usize) -> Self {
Self {
raw: RawSemaphore::new(),
count: AtomicIsize::new(n.try_into().unwrap()),
}
}
#[inline]
pub fn post() {
if self.count.fetch_add(1, AcqRel) < 0 {
self.raw.post()
}
}
#[inline]
pub fn post_n(n: usize) {
let count: isize = n.try_into().unwrap();
let prev = self.count.fetch_add(count, AcqRel);
if prev < 0 {
let waiters = -prev;
self.raw.post_n(waiters.min(count));
}
}
#[inline]
fn try_wait() -> bool {
let mut c = self.count.load(Acquire);
while c > 0 {
match c.compare_exchange_weak(c, c - 1, AcqRel, Relaxed) {
Ok(_) => return true,
Err(new) => c = new,
}
}
false
}
#[inline]
pub fn wait(&self) {
let spins = 5usize; // or whatever
for _ in 0..spins {
if self.try_wait() {
return;
}
}
if self.count.fetch_sub(1, AcqRel) < 1 {
self.raw.wait();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment