pinning?
This commit is contained in:
parent
5cd7f43f45
commit
a4992e7dc7
|
@ -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<Box<Job>>,
|
||||
tail: Pin<Box<Job>>,
|
||||
|
@ -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<Job> {
|
||||
unsafe { NonNull::new_unchecked(self.head_ptr().cast_mut()) }
|
||||
}
|
||||
fn tail(&self) -> NonNull<Job> {
|
||||
unsafe { NonNull::new_unchecked(self.tail_ptr().cast_mut()) }
|
||||
}
|
||||
|
||||
/// elem must be valid until it is popped.
|
||||
pub unsafe fn push_front<T>(&mut self, elem: &Job<T>) {
|
||||
pub unsafe fn push_front<T>(&mut self, elem: Pin<&Job<T>>) {
|
||||
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<T> as *mut Job) };
|
||||
let elem_ptr = unsafe { NonNull::new_unchecked(&*elem as *const Job<T> 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<T>(&mut self, elem: &Job<T>) {
|
||||
pub unsafe fn push_back<T>(&mut self, elem: Pin<&Job<T>>) {
|
||||
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<T> as *mut Job) };
|
||||
let elem_ptr = unsafe { NonNull::new_unchecked(&*elem as *const Job<T> 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<NonNull<Job>> {
|
||||
|
@ -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<ValueOrThis<T>>,
|
||||
/// (prev,next) before execute(), Box<...> after
|
||||
err_or_link: UnsafeCell<LinkOrError<Job>>,
|
||||
phantom: PhantomPinned,
|
||||
}
|
||||
|
||||
impl<T> Debug for Job<T> {
|
||||
|
@ -483,6 +504,7 @@ mod job {
|
|||
next: NonNull::dangling(),
|
||||
},
|
||||
}),
|
||||
phantom: PhantomPinned,
|
||||
}
|
||||
}
|
||||
pub fn empty() -> Job<T> {
|
||||
|
@ -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<T>(&self, job: &Job<T>) {
|
||||
fn push_front<T>(&self, job: Pin<&Job<T>>) {
|
||||
unsafe {
|
||||
self.queue.as_mut_unchecked().push_front(job);
|
||||
}
|
||||
}
|
||||
fn push_back<T>(&self, job: &Job<T>) {
|
||||
fn push_back<T>(&self, job: Pin<&Job<T>>) {
|
||||
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::<RB>(unsafe { mem::transmute(&job) }) {
|
||||
match self.wait_until::<RB>(unsafe {
|
||||
mem::transmute::<Pin<&Job<()>>, Pin<&Job<RB>>>(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<T>(&self, job: &Job<T>) -> Option<std::thread::Result<T>> {
|
||||
pub fn wait_until<T>(&self, job: Pin<&Job<T>>) -> Option<std::thread::Result<T>> {
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,26 +2,31 @@ use std::pin::Pin;
|
|||
|
||||
use super::{util::TaggedAtomicPtr, *};
|
||||
|
||||
fn pin_ptr<T>(pin: &Pin<&mut T>) -> NonNull<T> {
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue