Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Implement arena allocation for VersionVec #12

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ checkpoint = ["serde", "serde_derive", "serde_json"]

[dependencies]
cfg-if = "0.1.6"
# libc = "0.2.44"
scoped-tls = "0.1.2"

# Provides a generator based runtime
generator = { version = "0.6.10", optional = true }

# Provides a runtime based on libfringe. Requires nightly.
# fringe = { git = "https://github.com/carllerche/libfringe", branch = "track-nightly", optional = true }
fringe = { git = "https://github.com/carllerche/libfringe", branch = "track-nightly", optional = true }

# Optional futures support
futures = { version = "0.1.25", optional = true }
Expand All @@ -42,3 +41,9 @@ futures = { version = "0.1.25", optional = true }
serde = { version = "1.0.80", optional = true }
serde_derive = { version = "1.0.80", optional = true }
serde_json = { version = "1.0.33", optional = true }

[target.'cfg(unix)'.dependencies]
libc = "0.2.44"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.7", features = ["basetsd", "memoryapi", "minwindef", "sysinfoapi", "winnt"] }
2 changes: 1 addition & 1 deletion src/futures/atomic_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl AtomicTask {
task: RefCell::new(None),
// TODO: Make a custom object?
object: execution.objects.insert(Object::condvar()),
sync: RefCell::new(Synchronize::new(execution.threads.max())),
sync: RefCell::new(Synchronize::new(&mut execution.arena, execution.threads.max())),
}
})
}
Expand Down
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,13 @@

#[macro_use]
extern crate cfg_if;
// extern crate libc;

#[cfg(unix)]
extern crate libc;

#[cfg(windows)]
extern crate winapi;

#[macro_use]
extern crate scoped_tls;

Expand Down
229 changes: 172 additions & 57 deletions src/rt/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,32 @@ use std::alloc::Layout;
use std::cell::Cell;
use std::cmp;
use std::fmt;
use std::marker;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::rc::Rc;
use std::slice;

#[cfg(feature = "checkpoint")]
use serde::{Serialize, Serializer};

#[derive(Debug)]
pub struct Arena {
// inner: Rc<Inner>,
inner: Rc<Inner>,
}

/*
pub struct Slice<T> {
ptr: *mut T,
len: usize,
_inner: Rc<Inner>,
}

pub struct Iter<'a, T: 'a> {
ptr: *const T,
end: *const T,
_marker: marker::PhantomData<&'a T>,
}

#[derive(Debug)]
struct Inner {
/// Head of the arena space
Expand All @@ -32,92 +41,138 @@ struct Inner {
/// Total capacity of the arena
cap: usize,
}
*/

#[cfg(unix)]
fn create_mapping(capacity: usize) -> *mut u8 {
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
capacity,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_ANON | libc::MAP_PRIVATE,
-1,
0,
)
};

ptr as *mut u8
}

#[cfg(windows)]
fn get_page_size() -> usize {
use std::mem;
use winapi::um::sysinfoapi::GetSystemInfo;

unsafe {
let mut info = mem::zeroed();
GetSystemInfo(&mut info);

info.dwPageSize as usize
}
}

#[cfg(windows)]
fn create_mapping(capacity: usize) -> *mut u8 {
use std::ptr;
use winapi::shared::basetsd::SIZE_T;
use winapi::shared::minwindef::LPVOID;
use winapi::um::memoryapi::VirtualAlloc;
use winapi::um::winnt::{PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE};

let lpAddress: LPVOID = ptr::null_mut();
let page_size = get_page_size();
let len = if capacity % page_size == 0 {
capacity
} else {
capacity + page_size - (capacity % page_size)
};
let flAllocationType = MEM_COMMIT | MEM_RESERVE;
let flProtect = PAGE_READWRITE;

let r = unsafe {
VirtualAlloc(lpAddress, len as SIZE_T, flAllocationType, flProtect)
};

r as *mut u8
}

impl Arena {
/// Create an `Arena` with specified capacity.
///
/// Capacity must be a power of 2. The capacity cannot be grown after the fact.
pub fn with_capacity(capacity: usize) -> Arena {
Arena {}
/*
let head = unsafe {
libc::mmap(
ptr::null_mut(),
capacity,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_ANON | libc::MAP_PRIVATE,
-1,
0,
)
};
let head = create_mapping(capacity);

Arena {
inner: Rc::new(Inner {
head: head as *mut u8,
head,
pos: Cell::new(0),
cap: capacity,
}),
})
}
*/
}

pub fn clear(&mut self) {
/*
println!("rc: {}", Rc::strong_count(&self.inner));
assert!(1 == Rc::strong_count(&self.inner));
self.inner.pos.set(0);
*/
}
}
/*

pub fn slice<T>(&mut self, len: usize) -> Slice<T>
where
T: Default,
{
let ptr: *mut T = self.allocate(len);
slice(&self.inner, len)
}
}

for i in 0..len {
unsafe {
ptr::write(ptr.offset(i as isize), T::default());
}
}
fn slice<T>(inner: &Rc<Inner>, len: usize) -> Slice<T>
where
T: Default,
{
let ptr: *mut T = allocate(inner, len);

Slice {
ptr,
len,
_inner: self.inner.clone(),
for i in 0..len {
unsafe {
ptr::write(ptr.offset(i as isize), T::default());
}
}

fn allocate<T>(&mut self, count: usize) -> *mut T {
let layout = Layout::new::<T>();
let mask = layout.align() - 1;
let pos = self.inner.pos.get();
Slice {
ptr,
len,
_inner: inner.clone(),
}
}

debug_assert!(layout.align() >= (pos & mask));
fn allocate<T>(inner: &Rc<Inner>, count: usize) -> *mut T {
let layout = Layout::new::<T>();
let mask = layout.align() - 1;
let pos = inner.pos.get();

let mut skip = layout.align() - (pos & mask);
debug_assert!(layout.align() >= (pos & mask));

if skip == layout.align() {
skip = 0;
}
let mut skip = layout.align() - (pos & mask);

let additional = skip + layout.size() * count;
if skip == layout.align() {
skip = 0;
}

assert!(pos + additional <= self.inner.cap, "arena overflow");
let additional = skip + layout.size() * count;

self.inner.pos.set(pos + additional);
assert!(pos + additional <= inner.cap, "arena overflow");

let ret = unsafe { self.inner.head.offset((pos + skip) as isize) as *mut T };
inner.pos.set(pos + additional);

debug_assert!((ret as usize) >= self.inner.head as usize);
debug_assert!((ret as usize) < (self.inner.head as usize + self.inner.cap));
let ret = unsafe { inner.head.offset((pos + skip) as isize) as *mut T };

ret
}
debug_assert!((ret as usize) >= inner.head as usize);
debug_assert!((ret as usize) < (inner.head as usize + inner.cap));

ret
}

#[cfg(unix)]
impl Drop for Inner {
fn drop(&mut self) {
let res = unsafe { libc::munmap(self.head as *mut libc::c_void, self.cap) };
Expand All @@ -127,20 +182,50 @@ impl Drop for Inner {
}
}

impl<T: Clone> Slice<T> {
pub fn clone_with(&self, arena: &mut Arena) -> Slice<T> {
let ptr: *mut T = arena.allocate(self.len);
#[cfg(windows)]
impl Drop for Inner {
fn drop(&mut self) {
use winapi::shared::minwindef::LPVOID;
use winapi::um::memoryapi::VirtualFree;
use winapi::um::winnt::MEM_RELEASE;

let res = unsafe { VirtualFree(self.head as LPVOID, 0, MEM_RELEASE) };

// TODO: Do something on error
debug_assert_ne!(res, 0);
}
}

impl<T> Slice<T> {
pub fn iter(&self) -> Iter<T> {
unsafe {
// no ZST support
let ptr = self.ptr;
let end = self.ptr.add(self.len);

Iter {
ptr,
end,
_marker: marker::PhantomData,
}
}
}
}

impl<T: Clone> Clone for Slice<T> {
fn clone(&self) -> Self {
let ptr: *mut T = allocate(&self._inner, self.len);

for i in 0..self.len {
unsafe {
ptr::write(ptr.offset(i as isize), self[i].clone());
ptr::write(ptr.offset(i as isize), (*self.ptr.offset(i as isize)).clone());
}
}

Slice {
ptr,
len: self.len,
_inner: arena.inner.clone(),
_inner: self._inner.clone(),
}
}
}
Expand Down Expand Up @@ -181,11 +266,41 @@ impl<T: PartialOrd> PartialOrd for Slice<T> {

impl<T> Drop for Slice<T> {
fn drop(&mut self) {
for i in 0..self.len {
unsafe {
ptr::drop_in_place(&mut self[..]);
}
}
}

#[cfg(feature = "checkpoint")]
impl<T> Serialize for Slice<T>
where
T: Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq(self.iter())
}
}

impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;

#[inline]
fn next(&mut self) -> Option<&'a T> {
if self.ptr == self.end {
None
} else {
unsafe {
ptr::read(self.ptr.offset(i as isize) as *const _);
// we do not ZSTs right now, the stdlib does some dancing for this
// which we can safely avoid for now
let old = self.ptr;
self.ptr = self.ptr.offset(1);
Some(&*old)
}
}
}
}
*/
Loading