From bc57d221bc5561f2eac94e3e096bfb70d283b778 Mon Sep 17 00:00:00 2001 From: Janis Date: Fri, 21 Feb 2025 20:06:44 +0100 Subject: [PATCH] tests and stuff --- Cargo.toml | 4 ++ src/praetor/mod.rs | 75 ++++++++++++++++++++++++ src/praetor/tests.rs | 133 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 211 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 212548b..9127a81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ never-local = [] [profile.bench] debug = true +[profile.release] +debug = true + [dependencies] futures = "0.3" @@ -39,4 +42,5 @@ parking_lot_core = "0.9.10" # derive_more = "1.0.0" [dev-dependencies] +async-std = "1.13.0" tracing-test = "0.2.5" diff --git a/src/praetor/mod.rs b/src/praetor/mod.rs index 4fe77a8..b7db74d 100644 --- a/src/praetor/mod.rs +++ b/src/praetor/mod.rs @@ -1077,6 +1077,81 @@ impl Scope { self.execute(job); } } + + pub fn spawn<'a, F>(&self, f: F) + where + F: FnOnce(&Scope) + Send + 'a, + { + self.job_counter.increment(); + + let this = unsafe { + SendPtr::new_unchecked(&self.job_counter as *const JobCounter as *mut JobCounter) + }; + + let job = HeapJob::new(move |scope: &Scope| unsafe { + f(scope); + this.as_ref().decrement(); + }) + .into_boxed_job(); + + self.push_front(Pin::as_ref(&job)); + mem::forget(job); + } + + pub fn spawn_future<'a, T, F>(&'a self, future: F) -> async_task::Task + where + F: Future + Send + 'a, + T: Send + 'a, + { + self.job_counter.increment(); + + let this = + unsafe { SendPtr::new_unchecked(&raw const self.job_counter as *mut JobCounter) }; + + let future = async move { + let _guard = DropGuard::new(move || unsafe { + this.as_ref().decrement(); + }); + future.await + }; + + let this = SendPtr::new(&raw const *self as *mut Self).unwrap(); + let schedule = move |runnable: Runnable| { + unsafe fn harness(this: *const (), job: *const Job, _: &Scope) { + let runnable = Runnable::<()>::from_raw(NonNull::new_unchecked(this.cast_mut())); + runnable.run(); + + drop(Box::from_raw(job.cast_mut())); + } + + let job = Box::pin(Job::::new(harness::, runnable.into_raw())); + + unsafe { + this.as_ref().push_front(job.as_ref()); + } + mem::forget(job); + }; + + let (runnable, task) = unsafe { async_task::spawn_unchecked(future, schedule) }; + + runnable.schedule(); + + task + } + + #[allow(dead_code)] + fn spawn_async<'a, T, Fut, Fn>(&'a self, f: Fn) -> async_task::Task + where + Fn: FnOnce(&Scope) -> Fut + Send + 'static, + Fut: Future + Send + 'static, + T: Send + 'static, + { + let this = SendPtr::new(self as *const Self as *mut Self).unwrap(); + let future = async move { f(unsafe { this.as_ref() }).await }; + + self.spawn_future(future) + } + #[inline] pub fn join(&self, a: A, b: B) -> (RA, RB) where diff --git a/src/praetor/tests.rs b/src/praetor/tests.rs index 2b3128a..5f774f3 100644 --- a/src/praetor/tests.rs +++ b/src/praetor/tests.rs @@ -1,4 +1,4 @@ -use std::pin::Pin; +use std::{mem::MaybeUninit, pin::Pin}; use super::{util::TaggedAtomicPtr, *}; @@ -315,3 +315,134 @@ fn value_boxed_drop() { } assert_eq!(dropped, 2); } + +#[test] +fn job_list_pop_front_empty() { + let mut list = JobList::new(); + + assert_eq!(list.pop_front(), None); + assert_eq!(list.pop_front(), None); + assert_eq!(list.pop_front(), None); + assert_eq!(list.pop_front(), None); +} + +#[test] +fn job_list_pop_back_empty() { + let mut list = JobList::new(); + + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_back(), None); +} + +#[test] +fn job_list_pop_back_emptied() { + let mut list = JobList::new(); + let a = pin!(Job::<()>::empty()); + + unsafe { + list.push_front(a.as_ref()); + } + + assert_eq!(list.pop_back(), Some(pin_ptr(&a))); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_back(), None); + assert_eq!(list.pop_back(), None); +} + +#[test] +fn job_list_pop_front_emptied() { + let mut list = JobList::new(); + let a = pin!(Job::<()>::empty()); + + unsafe { + list.push_front(a.as_ref()); + } + + assert_eq!(list.pop_front(), Some(pin_ptr(&a))); + assert_eq!(list.pop_front(), None); + assert_eq!(list.pop_front(), None); + assert_eq!(list.pop_front(), None); +} + +#[test] +fn spawn() { + let pool = ThreadPool::new(); + + let mut x = 0; + pool.scope(|s| { + s.spawn(|_| { + x += 1; + }); + }); + + eprintln!("x: {x}"); +} + +#[test] +fn spawn_borrow() { + let pool = ThreadPool::new(); + + pool.scope(|s| { + let mut x = 0; + s.spawn(|_| { + x += 1; + assert_eq!(x, 1); + }); + }); +} + +#[test] +fn spawn_future() { + let pool = ThreadPool::new(); + + let task = pool.scope(|s| { + let task = s.spawn_future(async { + eprintln!("executing future"); + 3 + 1 + }); + + // let task = s.spawn_future(async { + // eprintln!("task: {}", task.await); + // }); + task + }); + let x = async_std::task::block_on(task); + eprintln!("x: {x}"); +} + +#[test] +fn join() { + let pool = ThreadPool::new(); + + let x = pool.scope(|s| { + let (a, b) = s.join(|_| 3, |_| 4); + + a + b + }); + + eprintln!("x: {x}"); +} + +#[test] +fn rebox() { + struct A(u32); + + impl Drop for A { + fn drop(&mut self) { + eprintln!("drop"); + } + } + + let ptr = Box::into_raw(Box::new(A(5))); + + let x = unsafe { &*ptr.offset(mem::offset_of!(A, 0) as isize).cast::() }; + let y = *x; + + unsafe { + ptr.drop_in_place(); + _ = Box::>::from_raw(ptr.cast()); + } + assert_eq!(y, 5); +}