Somebase tests for allocator
This commit is contained in:
parent
6691847830
commit
744ecde879
135
network/windows/src/eventloop/_allocator_tests.rs
Normal file
135
network/windows/src/eventloop/_allocator_tests.rs
Normal file
@ -0,0 +1,135 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use super::allocator::Allocator;
|
||||
use std::panic::catch_unwind;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
#[test]
|
||||
fn create_destroy() {
|
||||
let h = Allocator::new();
|
||||
}
|
||||
|
||||
struct FlagOnDrop<'a> {
|
||||
flag: &'a mut bool,
|
||||
}
|
||||
impl<'a> FlagOnDrop<'a> {
|
||||
fn init_pin(self: &mut Pin<&mut Self>, flag: &'a mut bool) {
|
||||
unsafe {
|
||||
Pin::into_inner_unchecked(NonNull::from_mut(self).read()).flag = flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FlagOnDrop<'_> {
|
||||
fn drop(&mut self) {
|
||||
*self.flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_auto_1_success() {
|
||||
let mut destructed = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed));
|
||||
}
|
||||
}
|
||||
assert!(destructed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_auto_2_success() {
|
||||
let mut destructed_1 = false;
|
||||
let mut destructed_2 = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_1));
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_2));
|
||||
}
|
||||
}
|
||||
assert!(destructed_1);
|
||||
assert!(destructed_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_manual_1_auto_2_success() {
|
||||
let mut destructed_1 = false;
|
||||
let mut destructed_2 = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
let a = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_1));
|
||||
h.free(a);
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_2));
|
||||
}
|
||||
}
|
||||
assert!(destructed_1);
|
||||
assert!(destructed_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_manual_2_auto_1_success() {
|
||||
let mut destructed_1 = false;
|
||||
let mut destructed_2 = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_1));
|
||||
let b = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_2));
|
||||
h.free(b);
|
||||
}
|
||||
}
|
||||
assert!(destructed_1);
|
||||
assert!(destructed_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_manual_2_1() {
|
||||
let mut destructed_1 = false;
|
||||
let mut destructed_2 = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
let a = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_1));
|
||||
let b = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_2));
|
||||
h.free(b);
|
||||
h.free(a);
|
||||
}
|
||||
}
|
||||
assert!(destructed_1);
|
||||
assert!(destructed_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destruct_manual_1_2() {
|
||||
let mut destructed_1 = false;
|
||||
let mut destructed_2 = false;
|
||||
{
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
let a = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_1));
|
||||
let b = h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed_2));
|
||||
h.free(a);
|
||||
h.free(b);
|
||||
}
|
||||
}
|
||||
assert!(destructed_1);
|
||||
assert!(destructed_2);
|
||||
}
|
||||
/*
|
||||
#[allow(unused_must_use)]
|
||||
#[test]
|
||||
fn destruct_panic() {
|
||||
let mut destructed = false;
|
||||
catch_unwind(|| {
|
||||
let mut h = Allocator::new();
|
||||
unsafe {
|
||||
h.alloc(|p| FlagOnDrop::init_pin(p, &mut destructed));
|
||||
panic!("Test panic");
|
||||
}
|
||||
});
|
||||
assert!(destructed);
|
||||
}*/
|
||||
@ -1,7 +1,10 @@
|
||||
use crate::errors::throw_from_windows_err_code;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::ptr::NonNull;
|
||||
use std::rc::Rc;
|
||||
use std::thread::panicking;
|
||||
use windows::Win32::Foundation::{GetLastError, HANDLE};
|
||||
use windows::Win32::System::Memory::{
|
||||
@ -10,7 +13,8 @@ use windows::Win32::System::Memory::{
|
||||
|
||||
pub(crate) struct Allocator {
|
||||
win_heap: HANDLE,
|
||||
last: Option<NonNull<Header>>,
|
||||
last: UnsafeCell<Option<NonNull<Header>>>,
|
||||
__not_send: PhantomData<Rc<()>>,
|
||||
}
|
||||
|
||||
struct Header {
|
||||
@ -30,7 +34,8 @@ impl Allocator {
|
||||
}
|
||||
return Allocator {
|
||||
win_heap: h,
|
||||
last: None,
|
||||
last: UnsafeCell::new(None),
|
||||
__not_send: PhantomData::default(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -45,10 +50,7 @@ impl Allocator {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc<'s, T>(
|
||||
&'s mut self,
|
||||
init: impl FnOnce(&mut Pin<&mut T>),
|
||||
) -> Pin<&'s mut T> {
|
||||
pub unsafe fn alloc<'s, T>(&'s self, init: impl FnOnce(&mut Pin<&mut T>)) -> Pin<&'s mut T> {
|
||||
let mut h = NonNull::new(
|
||||
HeapAlloc(
|
||||
self.win_heap,
|
||||
@ -67,13 +69,13 @@ impl Allocator {
|
||||
let mut p = Pin::new_unchecked(h.as_mut().value.cast::<T>().as_mut());
|
||||
heap_free_on_exit::<false, _>(self.win_heap, h.cast(), || init(&mut p));
|
||||
|
||||
if let Some(mut last) = self.last {
|
||||
if let Some(mut last) = self.last.get().read() {
|
||||
last.as_mut().next = Some(h);
|
||||
}
|
||||
h.as_mut().prev = self.last;
|
||||
h.as_mut().prev = self.last.get().read();
|
||||
h.as_mut().next = None;
|
||||
h.as_mut().destructor = Self::_destructor::<T>;
|
||||
self.last = Some(h);
|
||||
self.last.get().write(Some(h));
|
||||
|
||||
return p;
|
||||
}
|
||||
@ -82,7 +84,7 @@ impl Allocator {
|
||||
drop(obj.cast::<T>().read())
|
||||
}
|
||||
|
||||
pub unsafe fn free<T: Drop>(&mut self, p: Pin<&mut T>) {
|
||||
pub unsafe fn free<T: Drop>(&self, p: Pin<&mut T>) {
|
||||
let p = NonNull::from_mut(Pin::into_inner_unchecked(p));
|
||||
let h = NonNull::new_unchecked(
|
||||
p.as_ptr()
|
||||
@ -93,8 +95,8 @@ impl Allocator {
|
||||
|
||||
h.next.map(|mut n| n.as_mut().prev = h.prev);
|
||||
h.prev.map(|mut n| n.as_mut().next = h.next);
|
||||
if self.last == Some(NonNull::from_mut(h)) {
|
||||
self.last = h.prev;
|
||||
if self.last.get().read() == Some(NonNull::from_mut(h)) {
|
||||
self.last.get().write(h.prev);
|
||||
}
|
||||
heap_free_on_exit::<true, _>(self.win_heap, NonNull::from_mut(h).cast(), || {
|
||||
(h.destructor)(p.cast::<c_void>())
|
||||
@ -140,7 +142,7 @@ impl Drop for Allocator {
|
||||
fn drop(&mut self) {
|
||||
drop(RecursiveHeapDestructor {
|
||||
win_heap: self.win_heap,
|
||||
next: self.last,
|
||||
next: unsafe { self.last.get().read() },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
mod socket;
|
||||
mod task;
|
||||
mod allocator;
|
||||
mod _allocator_tests;
|
||||
|
||||
use socket::WindowsOverlappingIcmpSocket;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user