diff --git a/src/praetor/mod.rs b/src/praetor/mod.rs index 5e8af9d..b7ab61f 100644 --- a/src/praetor/mod.rs +++ b/src/praetor/mod.rs @@ -190,6 +190,7 @@ mod job { any::Any, cell::{Cell, UnsafeCell}, fmt::Debug, + marker::PhantomPinned, mem::{self, ManuallyDrop, MaybeUninit}, pin::Pin, ptr::{self, NonNull}, @@ -284,6 +285,7 @@ mod job { } } + #[derive(Debug)] pub struct JobList { head: Pin>, tail: Pin>, @@ -291,50 +293,68 @@ mod job { impl JobList { pub fn new() -> JobList { - let mut head = Box::pin(Job::empty()); - let mut tail = Box::pin(Job::empty()); + let head = Box::pin(Job::empty()); + let tail = Box::pin(Job::empty()); // head and tail point at themselves unsafe { - (&mut *head.err_or_link.get()).link.next = NonNull::new_unchecked(&mut *head); - (&mut *head.err_or_link.get()).link.prev = NonNull::new_unchecked(&mut *tail); + (&mut *head.err_or_link.get()).link.next = + NonNull::new_unchecked((&raw const *head).cast_mut()); + (&mut *head.err_or_link.get()).link.prev = + NonNull::new_unchecked((&raw const *tail).cast_mut()); - (&mut *tail.err_or_link.get()).link.next = NonNull::new_unchecked(&mut *head); - (&mut *tail.err_or_link.get()).link.prev = NonNull::new_unchecked(&mut *tail); + (&mut *tail.err_or_link.get()).link.next = + NonNull::new_unchecked((&raw const *head).cast_mut()); + (&mut *tail.err_or_link.get()).link.prev = + NonNull::new_unchecked((&raw const *tail).cast_mut()); } + Self { head, tail } } + fn head_ptr(&self) -> *const Job { + &raw const *self.head + } + fn tail_ptr(&self) -> *const Job { + &raw const *self.tail + } + fn head(&self) -> NonNull { + unsafe { NonNull::new_unchecked(self.head_ptr().cast_mut()) } + } + fn tail(&self) -> NonNull { + unsafe { NonNull::new_unchecked(self.tail_ptr().cast_mut()) } + } + /// elem must be valid until it is popped. - pub unsafe fn push_front(&mut self, elem: &Job) { + pub unsafe fn push_front(&mut self, elem: Pin<&Job>) { let head_link = unsafe { self.head.link_mut() }; let prev = head_link.prev; let prev_link = unsafe { prev.as_ref().link_mut() }; - let elem_ptr = unsafe { NonNull::new_unchecked(elem as *const Job as *mut Job) }; + let elem_ptr = unsafe { NonNull::new_unchecked(&*elem as *const Job as *mut Job) }; head_link.prev = elem_ptr; prev_link.next = elem_ptr; let elem_link = unsafe { elem.link_mut() }; elem_link.prev = prev; - elem_link.next = unsafe { NonNull::new_unchecked(&mut *self.head) }; + elem_link.next = self.head(); } /// elem must be valid until it is popped. - pub unsafe fn push_back(&mut self, elem: &Job) { + pub unsafe fn push_back(&mut self, elem: Pin<&Job>) { let tail_link = unsafe { self.tail.link_mut() }; let next = tail_link.next; let next_link = unsafe { next.as_ref().link_mut() }; - let elem_ptr = unsafe { NonNull::new_unchecked(elem as *const Job as *mut Job) }; + let elem_ptr = unsafe { NonNull::new_unchecked(&*elem as *const Job as *mut Job) }; tail_link.next = elem_ptr; next_link.prev = elem_ptr; let elem_link = unsafe { elem.link_mut() }; elem_link.next = next; - elem_link.prev = unsafe { NonNull::new_unchecked(&mut *self.tail) }; + elem_link.prev = self.tail(); } pub fn pop_front(&mut self) -> Option> { @@ -348,9 +368,9 @@ mod job { head_link.prev = unsafe { NonNull::new_unchecked(prev) }; let prev_link = unsafe { (&*prev).link_mut() }; - prev_link.next = unsafe { NonNull::new_unchecked(&mut *self.head) }; + prev_link.next = self.head(); - if elem.as_ptr() == ptr::from_ref(&*self.tail).cast_mut() { + if elem == self.tail() { None } else { Some(elem) @@ -369,9 +389,9 @@ mod job { tail_link.next = unsafe { NonNull::new_unchecked(next) }; let next_link = unsafe { (&*next).link_mut() }; - next_link.prev = unsafe { NonNull::new_unchecked(&mut *self.tail) }; + next_link.prev = self.tail(); - if elem.as_ptr() == ptr::from_ref(&*self.head).cast_mut() { + if elem == self.head() { None } else { Some(elem) @@ -416,6 +436,7 @@ mod job { val_or_this: UnsafeCell>, /// (prev,next) before execute(), Box<...> after err_or_link: UnsafeCell>, + phantom: PhantomPinned, } impl Debug for Job { @@ -483,6 +504,7 @@ mod job { next: NonNull::dangling(), }, }), + phantom: PhantomPinned, } } pub fn empty() -> Job { @@ -497,6 +519,7 @@ mod job { next: NonNull::dangling(), }, }), + phantom: PhantomPinned, } } @@ -536,8 +559,10 @@ mod job { Ordering::Release, Ordering::Relaxed, ); + eprintln!("wait({:?}): eepy", self as *const _); std::thread::park(); spin.reset(); + eprintln!("wait({:?}): woken", self as *const _); // after sleeping, state should be `Finished` continue; @@ -559,6 +584,11 @@ mod job { return result; } else { // spin until lock is released. + eprintln!( + "wait({:?}): spinning ({:?})", + self as *const _, + JobState::from_u8(state as u8).unwrap() + ); spin.spin(); } } @@ -617,10 +647,10 @@ mod job { break; } Err(tag) => { - // eprintln!( - // "complete(): spin waiting for lock to complete: ({:?})", - // JobState::from_u8(tag as u8).unwrap() - // ); + eprintln!( + "complete(): spin waiting for lock to complete: ({:?})", + JobState::from_u8(tag as u8).unwrap() + ); spin.spin(); } } @@ -733,7 +763,7 @@ use std::{ cell::UnsafeCell, collections::BTreeMap, mem, - pin::pin, + pin::{pin, Pin}, ptr::NonNull, sync::{ atomic::{AtomicBool, Ordering}, @@ -849,12 +879,12 @@ impl Scope { SCOPE.with(|ptr| unsafe { (&*ptr.get()).map(|ptr| ptr.as_ref()) }) } - fn push_front(&self, job: &Job) { + fn push_front(&self, job: Pin<&Job>) { unsafe { self.queue.as_mut_unchecked().push_front(job); } } - fn push_back(&self, job: &Job) { + fn push_back(&self, job: Pin<&Job>) { unsafe { self.queue.as_mut_unchecked().push_back(job); } @@ -876,7 +906,7 @@ impl Scope { let b = StackJob::new(b); let job = pin!(b.as_job()); - self.push_front(&job); + self.push_front(job.as_ref()); let ra = a(); @@ -888,7 +918,9 @@ impl Scope { self.tick(); unsafe { b.unwrap()() } } else { - match self.wait_until::(unsafe { mem::transmute(&job) }) { + match self.wait_until::(unsafe { + mem::transmute::>, Pin<&Job>>(job.as_ref()) + }) { Some(Ok(t)) => t, Some(Err(payload)) => std::panic::resume_unwind(payload), None => unsafe { b.unwrap()() }, @@ -932,7 +964,7 @@ impl Scope { } #[cold] - pub fn wait_until(&self, job: &Job) -> Option> { + pub fn wait_until(&self, job: Pin<&Job>) -> Option> { // let shared_job = self.context.shared.lock().jobs.remove(&self.index); // if let Some(ptr) = shared_job { @@ -955,6 +987,7 @@ impl Scope { .pop_first() .map(|(_, job)| job) }) else { + // no more jobs, sleep instead break; }; diff --git a/src/praetor/tests.rs b/src/praetor/tests.rs index e5daf56..6c6a133 100644 --- a/src/praetor/tests.rs +++ b/src/praetor/tests.rs @@ -2,26 +2,31 @@ use std::pin::Pin; use super::{util::TaggedAtomicPtr, *}; +fn pin_ptr(pin: &Pin<&mut T>) -> NonNull { + let a = &raw const **pin; + unsafe { NonNull::new_unchecked(a.cast_mut()) } +} + #[test] fn job_list_pop_back() { let mut list = JobList::new(); - let mut a = Job::empty(); - let mut b = Job::empty(); - let mut c = Job::empty(); + let mut a = pin!(Job::empty()); + let mut b = pin!(Job::empty()); + let mut c = pin!(Job::empty()); unsafe { - list.push_front(&a); - list.push_front(&b); - list.push_back(&c); + list.push_front(a.as_ref()); + list.push_front(b.as_ref()); + list.push_back(c.as_ref()); } - assert_eq!(list.pop_back(), NonNull::new(&mut c)); + assert_eq!(list.pop_back(), Some(pin_ptr(&c))); unsafe { - list.push_front(&c); + list.push_front(c.as_ref()); } - assert_eq!(list.pop_back(), NonNull::new(&mut a)); - assert_eq!(list.pop_back(), NonNull::new(&mut b)); - assert_eq!(list.pop_back(), NonNull::new(&mut c)); + assert_eq!(list.pop_back(), Some(pin_ptr(&a))); + assert_eq!(list.pop_back(), Some(pin_ptr(&b))); + assert_eq!(list.pop_back(), Some(pin_ptr(&c))); assert_eq!(list.pop_back(), None); assert_eq!(list.pop_front(), None); } @@ -29,23 +34,23 @@ fn job_list_pop_back() { #[test] fn job_list_pop_front() { let mut list = JobList::new(); - let mut a = Job::empty(); - let mut b = Job::empty(); - let mut c = Job::empty(); + let mut a = pin!(Job::<()>::empty()); + let mut b = pin!(Job::<()>::empty()); + let mut c = pin!(Job::<()>::empty()); unsafe { - list.push_front(&a); - list.push_front(&b); - list.push_back(&c); + list.push_front(a.as_ref()); + list.push_front(b.as_ref()); + list.push_back(c.as_ref()); } - assert_eq!(list.pop_front(), NonNull::new(&mut b)); + assert_eq!(list.pop_front(), Some(pin_ptr(&b))); unsafe { - list.push_back(&b); + list.push_back(b.as_ref()); } - assert_eq!(list.pop_front(), NonNull::new(&mut a)); - assert_eq!(list.pop_front(), NonNull::new(&mut c)); - assert_eq!(list.pop_front(), NonNull::new(&mut b)); + assert_eq!(list.pop_front(), Some(pin_ptr(&a))); + assert_eq!(list.pop_front(), Some(pin_ptr(&c))); + assert_eq!(list.pop_front(), Some(pin_ptr(&b))); assert_eq!(list.pop_front(), None); assert_eq!(list.pop_back(), None); } @@ -53,22 +58,22 @@ fn job_list_pop_front() { #[test] fn unlink_job_middle() { let mut list = JobList::new(); - let mut a = Job::empty(); - let b = Job::<()>::empty(); - let mut c = Job::empty(); + let mut a = pin!(Job::<()>::empty()); + let mut b = pin!(Job::<()>::empty()); + let mut c = pin!(Job::<()>::empty()); unsafe { - list.push_front(&a); - list.push_front(&b); - list.push_front(&c); + list.push_front(a.as_ref()); + list.push_front(b.as_ref()); + list.push_front(c.as_ref()); } unsafe { b.unlink(); } - assert_eq!(list.pop_front(), NonNull::new(&mut c)); - assert_eq!(list.pop_front(), NonNull::new(&mut a)); + assert_eq!(list.pop_front(), Some(pin_ptr(&c))); + assert_eq!(list.pop_front(), Some(pin_ptr(&a))); assert_eq!(list.pop_front(), None); assert_eq!(list.pop_back(), None); } @@ -76,22 +81,22 @@ fn unlink_job_middle() { #[test] fn unlink_job_front() { let mut list = JobList::new(); - let a = Job::<()>::empty(); - let mut b = Job::<()>::empty(); - let mut c = Job::<()>::empty(); + let mut a = pin!(Job::<()>::empty()); + let mut b = pin!(Job::<()>::empty()); + let mut c = pin!(Job::<()>::empty()); unsafe { - list.push_front(&a); - list.push_front(&b); - list.push_front(&c); + list.push_front(a.as_ref()); + list.push_front(b.as_ref()); + list.push_front(c.as_ref()); } unsafe { a.unlink(); } - assert_eq!(list.pop_front(), NonNull::new(&mut c)); - assert_eq!(list.pop_front(), NonNull::new(&mut b)); + assert_eq!(list.pop_front(), Some(pin_ptr(&c))); + assert_eq!(list.pop_front(), Some(pin_ptr(&b))); assert_eq!(list.pop_front(), None); assert_eq!(list.pop_back(), None); } @@ -99,22 +104,22 @@ fn unlink_job_front() { #[test] fn unlink_job_back() { let mut list = JobList::new(); - let mut a = Job::<()>::empty(); - let mut b = Job::<()>::empty(); - let c = Job::<()>::empty(); + let mut a = pin!(Job::<()>::empty()); + let mut b = pin!(Job::<()>::empty()); + let mut c = pin!(Job::<()>::empty()); unsafe { - list.push_front(&a); - list.push_front(&b); - list.push_front(&c); + list.push_front(a.as_ref()); + list.push_front(b.as_ref()); + list.push_front(c.as_ref()); } unsafe { c.unlink(); } - assert_eq!(list.pop_front(), NonNull::new(&mut b)); - assert_eq!(list.pop_front(), NonNull::new(&mut a)); + assert_eq!(list.pop_front(), Some(pin_ptr(&b))); + assert_eq!(list.pop_front(), Some(pin_ptr(&a))); assert_eq!(list.pop_front(), None); assert_eq!(list.pop_back(), None); } @@ -122,10 +127,10 @@ fn unlink_job_back() { #[test] fn unlink_job_single() { let mut list = JobList::new(); - let a = Job::<()>::empty(); + let a = pin!(Job::<()>::empty()); unsafe { - list.push_front(&a); + list.push_front(a.as_ref()); } unsafe { @@ -165,14 +170,3 @@ fn tagged_ptr_exchange_failure() { assert_eq!(ptr.tag(Ordering::Relaxed), 1); assert_eq!(ptr.ptr(Ordering::Relaxed).as_ptr(), boxed); } - -fn pinstuff() { - let pinned = pin!(5); - - let b = pinned.as_ref(); - let a = takes_pinned_ref(pinned.as_ref()); -} - -fn takes_pinned_ref(r: Pin<&i32>) -> i32 { - *r -}