use glommio::enclose;
use glommio::prelude::*;
use glommio::sync::Semaphore;
use std::cell::Cell;
use std::rc::Rc;
use std::time::Instant;

fn main() {
    let local_ex = LocalExecutorBuilder::new()
        .pin_to_cpu(0)
        .spawn(|| async move {
            let runs: u32 = 10_000_000;
            let s = Rc::new(Semaphore::new(10_000_000));
            let t = Instant::now();
            for _ in 0..runs {
                s.acquire(1).await.unwrap();
            }
            println!(
                "cost of acquiring uncontended semaphore: {:#?}",
                t.elapsed() / runs
            );
        })
        .unwrap();
    local_ex.join().unwrap();

    let local_ex = LocalExecutorBuilder::new()
        .pin_to_cpu(0)
        .spawn(|| async move {
            let runs: u32 = 10_000_000;
            let s = Rc::new(Semaphore::new(0));
            let acquisitions = Rc::new(Cell::new(0));

            let signals = Local::local(enclose! { (acquisitions, s) async move {
                let mut expected : u32 = 0;
                while expected != runs {
                    while expected != acquisitions.get() {
                        Local::later().await;
                    }
                    s.signal(1);
                    expected += 1;
                }
            }})
            .detach();

            let t = Instant::now();
            for i in 0..runs {
                acquisitions.set(i);
                s.acquire(1).await.unwrap();
            }
            println!(
                "cost of acquiring contended semaphore: {:#?}",
                t.elapsed() / runs
            );
            signals.await;
        })
        .unwrap();
    local_ex.join().unwrap();
}
