#![doc = include_str!("../README.md")]
#[macro_use]
extern crate may;
use may::coroutine;
use rcu_cell::RcuCell;
use rcu_list::d_list::{Entry, LinkedList};
use std::sync::Arc;
type CoNode = Arc<RcuCell<coroutine::JoinHandle<()>>>;
type CoList = Arc<LinkedList<CoNode>>;
#[derive(Default)]
pub struct Manager {
co_list: CoList,
}
impl Manager {
pub fn new() -> Self {
Manager {
co_list: Arc::new(Default::default()),
}
}
pub fn add<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let slot = Arc::new(RcuCell::none());
let slot_dup = slot.clone();
let co_list = self.co_list.clone();
let co = go!(move || {
let entry = co_list.push_front(slot_dup);
let _sub_co = SubCo { entry };
f();
});
slot.write(co);
}
pub unsafe fn add_unsafe<'a, F>(&self, f: F)
where
F: FnOnce() + Send + 'a,
{
let slot = Arc::new(RcuCell::none());
let slot_dup = slot.clone();
let co_list = self.co_list.clone();
let closure: Box<dyn FnOnce() + Send + 'a> = Box::new(f);
let closure: Box<dyn FnOnce() + Send> = std::mem::transmute(closure);
let co = go!(move || {
let entry = co_list.push_front(slot_dup);
let _sub_co = SubCo { entry };
closure()
});
slot.write(co);
}
}
impl Drop for Manager {
fn drop(&mut self) {
self.co_list.iter().for_each(|co| {
let co = co.read().unwrap();
unsafe { co.coroutine().cancel() };
co.wait()
});
while !self.co_list.is_empty() {
coroutine::yield_now();
}
}
}
pub struct SubCo<'a> {
entry: Entry<'a, CoNode>,
}
impl Drop for SubCo<'_> {
fn drop(&mut self) {
self.entry.remove();
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn thread_exit() {
let manager = Manager::new();
struct Dummy(usize);
impl Drop for Dummy {
fn drop(&mut self) {
println!("co dropped, id={}", self.0);
}
}
for i in 0..10 {
manager.add(move || {
let d = Dummy(i);
println!("sub started, id = {}", d.0);
loop {
coroutine::sleep(Duration::from_millis(10));
}
});
}
coroutine::sleep(Duration::from_millis(100));
println!("parent started");
drop(manager);
println!("parent exit");
}
#[test]
fn coroutine_cancel() {
let j = go!(|| {
println!("parent started");
let manager = Manager::new();
struct Dummy(usize);
impl Drop for Dummy {
fn drop(&mut self) {
println!("co dropped, id={}", self.0);
}
}
for i in 0..10 {
manager.add(move || {
let d = Dummy(i);
println!("sub started, id = {}", d.0);
loop {
coroutine::sleep(Duration::from_millis(10));
}
});
}
coroutine::park();
});
coroutine::sleep(Duration::from_millis(100));
unsafe { j.coroutine().cancel() };
j.join().ok();
println!("parent exit");
coroutine::sleep(Duration::from_millis(1000));
}
}