tokio/tokio-sync/tests/fuzz_semaphore.rs
Carl Lerche e3115231dd
sync: fix mpsc/sempahore when releasing permits (#904)
This patch fixes Semaphore by adding a missing code path to the release
routine that handles the case where the waiter's node is queued in the
sempahore but has not yet been assigned the permit.

This fix is used by mpsc to handle the case when the Sender has called
`poll_ready` and is dropped before the permit is acquired.

Fixes #900
2019-02-19 16:26:05 -08:00

165 lines
3.5 KiB
Rust

#[macro_use]
extern crate futures;
#[macro_use]
extern crate loom;
#[path = "../src/semaphore.rs"]
#[allow(warnings)]
mod semaphore;
use semaphore::*;
use futures::{future, Future, Async, Poll};
use loom::thread;
use loom::futures::block_on;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
#[test]
fn basic_usage() {
const NUM: usize = 2;
struct Actor {
waiter: Permit,
shared: Arc<Shared>,
}
struct Shared {
semaphore: Semaphore,
active: AtomicUsize,
}
impl Future for Actor {
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
try_ready!(
self.waiter.poll_acquire(&self.shared.semaphore)
.map_err(|_| ()));
let actual = self.shared.active.fetch_add(1, SeqCst);
assert!(actual <= NUM-1);
let actual = self.shared.active.fetch_sub(1, SeqCst);
assert!(actual <= NUM);
self.waiter.release(&self.shared.semaphore);
Ok(Async::Ready(()))
}
}
loom::fuzz(|| {
let shared = Arc::new(Shared {
semaphore: Semaphore::new(NUM),
active: AtomicUsize::new(0),
});
for _ in 0..NUM {
let shared = shared.clone();
thread::spawn(move || {
block_on(Actor {
waiter: Permit::new(),
shared,
}).unwrap();
});
}
block_on(Actor {
waiter: Permit::new(),
shared
}).unwrap();
});
}
#[test]
fn release() {
loom::fuzz(|| {
let semaphore = Arc::new(Semaphore::new(1));
{
let semaphore = semaphore.clone();
thread::spawn(move || {
let mut permit = Permit::new();
block_on(future::lazy(|| {
permit.poll_acquire(&semaphore).unwrap();
Ok::<_, ()>(())
})).unwrap();
permit.release(&semaphore);
});
}
let mut permit = Permit::new();
block_on(future::poll_fn(|| {
permit.poll_acquire(&semaphore)
})).unwrap();
permit.release(&semaphore);
});
}
#[test]
fn basic_closing() {
const NUM: usize = 2;
loom::fuzz(|| {
let semaphore = Arc::new(Semaphore::new(1));
for _ in 0..NUM {
let semaphore = semaphore.clone();
thread::spawn(move || {
let mut permit = Permit::new();
for _ in 0..2 {
block_on(future::poll_fn(|| {
permit.poll_acquire(&semaphore)
.map_err(|_| ())
}))?;
permit.release(&semaphore);
}
Ok::<(), ()>(())
});
}
semaphore.close();
});
}
#[test]
fn concurrent_close() {
const NUM: usize = 3;
loom::fuzz(|| {
let semaphore = Arc::new(Semaphore::new(1));
for _ in 0..NUM {
let semaphore = semaphore.clone();
thread::spawn(move || {
let mut permit = Permit::new();
block_on(future::poll_fn(|| {
permit.poll_acquire(&semaphore)
.map_err(|_| ())
}))?;
permit.release(&semaphore);
semaphore.close();
Ok::<(), ()>(())
});
}
});
}