Closed
Description
Running the following code:
#![feature(futures_api)]
use std::ptr::NonNull;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{LocalWaker, Waker, UnsafeWake};
pub fn new_waker() -> LocalWaker {
let waker = Box::new(MyWaker { count: AtomicUsize::new(0) });
let ptr: *const dyn UnsafeWake = Box::into_raw(waker);
let ptr = unsafe { NonNull::new_unchecked(ptr as *mut _) };
unsafe { LocalWaker::new(ptr) }
}
#[derive(Debug)]
struct MyWaker {
count: AtomicUsize,
}
unsafe impl UnsafeWake for MyWaker {
unsafe fn clone_raw(&self) -> Waker {
println!("clone_raw");
let ptr: *const UnsafeWake = self;
let ptr = NonNull::new_unchecked(ptr as *mut _);
self.count.fetch_add(1, Ordering::SeqCst);
Waker::new(ptr)
}
unsafe fn drop_raw(&self) {
println!("drop_raw");
if self.count.fetch_sub(1, Ordering::SeqCst) == 1 {
// TODO: actually drop self.
}
}
unsafe fn wake(&self) {
println!("wake");
}
}
fn main() {
let local_waker1 = new_waker();
let local_waker2 = local_waker1.clone();
local_waker2.wake();
drop(local_waker1);
drop(local_waker2);
}
Prints the following:
clone_raw
drop_raw # The problem.
wake
drop_raw
drop_raw
It has an extra call to drop_raw
.
I think it's because of the Clone
implementation of LocalWaker
:
unsafe {
LocalWaker { inner: self.inner.as_ref().clone_raw().inner }
}
As UnsafeWake::clone_raw
returns an Waker
the LocalWaker
code just takes the inner value. However because of this the Waker
will be dropped and hence the erroneous extra call to drop_raw
.
Metadata
Metadata
Assignees
Labels
No labels