From ced29b9a851725e25bb0957473ebb48399635da8 Mon Sep 17 00:00:00 2001 From: Daniel Bittman Date: Wed, 18 Dec 2024 22:01:48 -0800 Subject: [PATCH 1/2] Adding store effects. --- src/lib/twizzler/src/marker.rs | 34 +++++++++++ src/lib/twizzler/src/object/builder.rs | 83 +++++++++++++++++++++++++- src/lib/twizzler/src/ptr/invariant.rs | 11 +++- src/lib/twizzler/src/ptr/resolved.rs | 10 +++- 4 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/lib/twizzler/src/marker.rs b/src/lib/twizzler/src/marker.rs index c54cc50f..767f9ac2 100644 --- a/src/lib/twizzler/src/marker.rs +++ b/src/lib/twizzler/src/marker.rs @@ -1,5 +1,7 @@ //! Marker types for invariance, store side-effects, and base types. +use std::mem::MaybeUninit; + /// Indicates that a type is _invariant_ and thus can be stored in an object. /// /// # Safety @@ -50,9 +52,41 @@ pub struct PhantomStoreEffect; impl !StoreCopy for PhantomStoreEffect {} impl !Unpin for PhantomStoreEffect {} +#[derive(Debug)] +pub struct Storable(MaybeUninit, Option<()>); + +unsafe impl StoreCopy for Storable {} + +impl From for Storable { + fn from(value: T) -> Self { + Self(MaybeUninit::new(value), None) + } +} + +impl Storable { + pub fn into_inner(self) -> T { + unsafe { self.0.assume_init() } + } +} + +impl Storable { + pub unsafe fn new(value: T) -> Self { + Self(MaybeUninit::new(value), None) + } + + pub unsafe fn into_inner_unchecked(self) -> T { + unsafe { self.0.assume_init() } + } +} + pub trait BaseType { /// The fingerprint of this type. fn fingerprint() -> u64 { 0 } } + +impl BaseType for u8 {} +impl BaseType for u16 {} +impl BaseType for u32 {} +impl BaseType for u64 {} diff --git a/src/lib/twizzler/src/object/builder.rs b/src/lib/twizzler/src/object/builder.rs index 5e986b57..d41ac3fe 100644 --- a/src/lib/twizzler/src/object/builder.rs +++ b/src/lib/twizzler/src/object/builder.rs @@ -4,8 +4,11 @@ use thiserror::Error; use twizzler_abi::syscall::{ObjectCreate, ObjectCreateError}; use twizzler_rt_abi::object::{MapError, ObjectHandle}; -use super::RawObject; -use crate::marker::BaseType; +use super::{Object, RawObject}; +use crate::{ + marker::{BaseType, Storable, StoreCopy}, + tx::TxHandle, +}; #[derive(Clone, Copy, Debug, Error)] /// Possible errors from creating an object. @@ -19,6 +22,7 @@ pub enum CreateError { } /// An object builder, for constructing objects using a builder API. +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct ObjectBuilder { spec: ObjectCreate, _pd: PhantomData, @@ -34,6 +38,22 @@ impl ObjectBuilder { } } +impl ObjectBuilder { + pub fn build(self, base: Base) -> Result, CreateError> { + todo!() + } +} + +impl ObjectBuilder { + pub fn build_with(self, ctor: F) -> Result, CreateError> + where + F: FnOnce(UninitObject) -> SB, + SB: Into>, + { + todo!() + } +} + impl Default for ObjectBuilder { fn default() -> Self { Self::new(ObjectCreate::default()) @@ -51,3 +71,62 @@ impl RawObject for UninitObject { &self.handle } } + +impl<'a, B> TxHandle<'a> for &mut UninitObject { + fn tx_mut(&self, data: *const T) -> crate::tx::TxResult<*mut T, E> { + todo!() + } +} +impl<'a, B> TxHandle<'a> for UninitObject { + fn tx_mut(&self, data: *const T) -> crate::tx::TxResult<*mut T, E> { + todo!() + } +} +mod tests { + use super::ObjectBuilder; + use crate::{ + marker::{BaseType, Storable, StoreCopy}, + object::TypedObject, + ptr::{InvPtr, Ref}, + tx::TxHandle, + }; + + fn builder_simple() { + let builder = ObjectBuilder::default(); + let obj = builder.build(42u32).unwrap(); + let base = obj.base(); + assert_eq!(*base, 42); + } + + struct Foo { + ptr: InvPtr, + } + + impl BaseType for Foo {} + + impl Foo { + pub fn new_in<'a>( + target: &impl TxHandle<'a>, + ptr: Storable>, + ) -> Storable { + unsafe { + Storable::new(Foo { + ptr: ptr.into_inner_unchecked(), + }) + } + } + } + + fn builder_complex() { + let builder = ObjectBuilder::default(); + let obj_1 = builder.build_with(|_uo| 42u32).unwrap(); + let base = obj_1.base(); + assert_eq!(*base, 42); + + let builder = ObjectBuilder::::default(); + let obj = builder + .build_with(|uo| Foo::new_in(&uo, InvPtr::new_in(&uo))) + .unwrap(); + let base_foo = obj.base(); + } +} diff --git a/src/lib/twizzler/src/ptr/invariant.rs b/src/lib/twizzler/src/ptr/invariant.rs index c1c10987..67ac85ae 100644 --- a/src/lib/twizzler/src/ptr/invariant.rs +++ b/src/lib/twizzler/src/ptr/invariant.rs @@ -1,6 +1,9 @@ use std::marker::PhantomData; -use crate::marker::{Invariant, PhantomStoreEffect}; +use crate::{ + marker::{Invariant, PhantomStoreEffect, Storable}, + tx::TxHandle, +}; #[repr(C)] #[derive(Debug, PartialEq, PartialOrd, Ord, Eq)] @@ -9,3 +12,9 @@ pub struct InvPtr { _pse: PhantomStoreEffect, _pd: PhantomData<*const T>, } + +impl InvPtr { + pub fn new_in<'a>(target: &impl TxHandle<'a>) -> Storable { + todo!() + } +} diff --git a/src/lib/twizzler/src/ptr/resolved.rs b/src/lib/twizzler/src/ptr/resolved.rs index 2f65395e..4c421c81 100644 --- a/src/lib/twizzler/src/ptr/resolved.rs +++ b/src/lib/twizzler/src/ptr/resolved.rs @@ -1,4 +1,4 @@ -use std::marker::PhantomData; +use std::{marker::PhantomData, ops::Deref}; use twizzler_rt_abi::object::ObjectHandle; @@ -7,3 +7,11 @@ pub struct Ref<'obj, T> { handle: *const ObjectHandle, _pd: PhantomData<&'obj T>, } + +impl<'obj, T> Deref for Ref<'obj, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.ptr.as_ref().unwrap_unchecked() } + } +} From 8e97567a5d56f73f633a49ef6c4bc3b9b4538dc4 Mon Sep 17 00:00:00 2001 From: Daniel Bittman Date: Thu, 19 Dec 2024 13:32:23 -0800 Subject: [PATCH 2/2] Adding transactional stubs. --- src/lib/twizzler/src/alloc/arena.rs | 24 ++++++++- src/lib/twizzler/src/alloc/invbox.rs | 59 ++++++++++++++++++++- src/lib/twizzler/src/object.rs | 18 ++++--- src/lib/twizzler/src/object/builder.rs | 20 +++---- src/lib/twizzler/src/ptr/invariant.rs | 7 ++- src/lib/twizzler/src/ptr/resolved.rs | 39 +++++++++++++- src/lib/twizzler/src/tx.rs | 27 +++++----- src/lib/twizzler/src/tx/batch.rs | 73 ++++++++++++++++++++++++++ src/lib/twizzler/src/tx/object.rs | 70 ++++++++++++++++++++++++ src/lib/twizzler/src/tx/unsafe.rs | 0 src/lib/twizzler/src/tx/unsafetx.rs | 15 ++++++ 11 files changed, 314 insertions(+), 38 deletions(-) create mode 100644 src/lib/twizzler/src/tx/batch.rs create mode 100644 src/lib/twizzler/src/tx/object.rs delete mode 100644 src/lib/twizzler/src/tx/unsafe.rs create mode 100644 src/lib/twizzler/src/tx/unsafetx.rs diff --git a/src/lib/twizzler/src/alloc/arena.rs b/src/lib/twizzler/src/alloc/arena.rs index 923fbca9..161aaaad 100644 --- a/src/lib/twizzler/src/alloc/arena.rs +++ b/src/lib/twizzler/src/alloc/arena.rs @@ -1,10 +1,30 @@ use super::Allocator; -use crate::object::Object; +use crate::{object::Object, ptr::GlobalPtr}; -pub struct ArenaAllocator { +pub struct ArenaObject { obj: Object, } +impl ArenaObject { + pub fn new() -> Self { + todo!() + } + + pub fn allocator(&self) -> ArenaAllocator { + todo!() + } +} + +pub struct ArenaAllocator { + ptr: GlobalPtr, +} + +impl ArenaAllocator { + pub fn new(ptr: GlobalPtr) -> Self { + Self { ptr } + } +} + #[repr(C)] pub struct ArenaBase {} diff --git a/src/lib/twizzler/src/alloc/invbox.rs b/src/lib/twizzler/src/alloc/invbox.rs index 47333c17..8bf2c43e 100644 --- a/src/lib/twizzler/src/alloc/invbox.rs +++ b/src/lib/twizzler/src/alloc/invbox.rs @@ -1,5 +1,60 @@ -use crate::{marker::Invariant, ptr::InvPtr}; +use super::Allocator; +use crate::{ + marker::{Invariant, Storable}, + ptr::InvPtr, + tx::{Result, TxHandle}, +}; -pub struct InvBox { +pub struct InvBox { raw: InvPtr, + alloc: Alloc, +} + +impl InvBox { + pub unsafe fn from_invptr(raw: InvPtr, alloc: Alloc) -> Self { + todo!() + } + + pub fn new_in(val: T, alloc: Alloc, tx: &impl TxHandle) -> Result> { + todo!() + } +} + +mod tests { + use super::InvBox; + use crate::{ + alloc::arena::{ArenaAllocator, ArenaBase, ArenaObject}, + marker::{BaseType, Storable}, + object::{ObjectBuilder, TypedObject}, + tx::TxHandle, + }; + + struct Foo { + x: InvBox, + } + + impl Foo { + pub fn new_in( + target: &impl TxHandle, + ptr: Storable>, + ) -> Storable { + //ptr.check_target(target); + unsafe { + Storable::new(Foo { + x: ptr.into_inner_unchecked(), + }) + } + } + } + + impl BaseType for Foo {} + fn box_simple() { + let builder = ObjectBuilder::::default(); + let alloc = ArenaObject::new().allocator(); + let obj = builder + .build_with(|uo| Foo::new_in(&uo, InvBox::new_in(3, alloc, &uo).unwrap())) + .unwrap(); + let base = obj.base(); + assert_eq!(*base.x.raw.resolve(), 3); + } } diff --git a/src/lib/twizzler/src/object.rs b/src/lib/twizzler/src/object.rs index 89324cd2..77ea6498 100644 --- a/src/lib/twizzler/src/object.rs +++ b/src/lib/twizzler/src/object.rs @@ -2,19 +2,19 @@ use std::marker::PhantomData; -use fot::FotEntry; -use twizzler_abi::{ - meta::MetaInfo, - object::{ObjID, MAX_SIZE, NULLPAGE_SIZE}, -}; +use twizzler_abi::object::{ObjID, MAX_SIZE, NULLPAGE_SIZE}; use twizzler_rt_abi::object::ObjectHandle; -use crate::{marker::BaseType, ptr::Ref}; +use crate::{marker::BaseType, ptr::Ref, tx::TxObject}; mod builder; mod fot; mod meta; +pub use builder::*; +pub use fot::*; +pub use meta::*; + /// Operations common to structured objects. pub trait TypedObject { /// The base type of this object. @@ -100,6 +100,12 @@ pub struct Object { _pd: PhantomData<*const Base>, } +impl Object { + pub fn tx(self) -> crate::tx::Result> { + todo!() + } +} + impl RawObject for Object { fn handle(&self) -> &ObjectHandle { &self.handle diff --git a/src/lib/twizzler/src/object/builder.rs b/src/lib/twizzler/src/object/builder.rs index d41ac3fe..a2c6cdba 100644 --- a/src/lib/twizzler/src/object/builder.rs +++ b/src/lib/twizzler/src/object/builder.rs @@ -39,7 +39,7 @@ impl ObjectBuilder { } impl ObjectBuilder { - pub fn build(self, base: Base) -> Result, CreateError> { + pub fn build(&self, base: Base) -> Result, CreateError> { todo!() } } @@ -72,13 +72,8 @@ impl RawObject for UninitObject { } } -impl<'a, B> TxHandle<'a> for &mut UninitObject { - fn tx_mut(&self, data: *const T) -> crate::tx::TxResult<*mut T, E> { - todo!() - } -} -impl<'a, B> TxHandle<'a> for UninitObject { - fn tx_mut(&self, data: *const T) -> crate::tx::TxResult<*mut T, E> { +impl TxHandle for UninitObject { + fn tx_mut(&self, data: *const u8, len: usize) -> crate::tx::Result<*mut u8> { todo!() } } @@ -105,10 +100,7 @@ mod tests { impl BaseType for Foo {} impl Foo { - pub fn new_in<'a>( - target: &impl TxHandle<'a>, - ptr: Storable>, - ) -> Storable { + pub fn new_in(target: &impl TxHandle, ptr: Storable>) -> Storable { unsafe { Storable::new(Foo { ptr: ptr.into_inner_unchecked(), @@ -125,8 +117,10 @@ mod tests { let builder = ObjectBuilder::::default(); let obj = builder - .build_with(|uo| Foo::new_in(&uo, InvPtr::new_in(&uo))) + .build_with(|uo| Foo::new_in(&uo, InvPtr::new_in(&uo, base))) .unwrap(); let base_foo = obj.base(); + let r = base_foo.ptr.resolve(); + assert_eq!(*r, 42); } } diff --git a/src/lib/twizzler/src/ptr/invariant.rs b/src/lib/twizzler/src/ptr/invariant.rs index 67ac85ae..b8914332 100644 --- a/src/lib/twizzler/src/ptr/invariant.rs +++ b/src/lib/twizzler/src/ptr/invariant.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use super::{GlobalPtr, Ref}; use crate::{ marker::{Invariant, PhantomStoreEffect, Storable}, tx::TxHandle, @@ -14,7 +15,11 @@ pub struct InvPtr { } impl InvPtr { - pub fn new_in<'a>(target: &impl TxHandle<'a>) -> Storable { + pub fn new_in(target: &impl TxHandle, global: impl Into>) -> Storable { + todo!() + } + + pub fn resolve<'a>(&self) -> Ref<'a, T> { todo!() } } diff --git a/src/lib/twizzler/src/ptr/resolved.rs b/src/lib/twizzler/src/ptr/resolved.rs index 4c421c81..6e961554 100644 --- a/src/lib/twizzler/src/ptr/resolved.rs +++ b/src/lib/twizzler/src/ptr/resolved.rs @@ -1,7 +1,12 @@ -use std::{marker::PhantomData, ops::Deref}; +use std::{ + marker::PhantomData, + ops::{Deref, DerefMut}, +}; use twizzler_rt_abi::object::ObjectHandle; +use super::GlobalPtr; + pub struct Ref<'obj, T> { ptr: *const T, handle: *const ObjectHandle, @@ -15,3 +20,35 @@ impl<'obj, T> Deref for Ref<'obj, T> { unsafe { self.ptr.as_ref().unwrap_unchecked() } } } + +impl<'a, T> From> for GlobalPtr { + fn from(value: Ref<'a, T>) -> Self { + todo!() + } +} + +pub struct RefMut<'obj, T> { + ptr: *mut T, + handle: *const ObjectHandle, + _pd: PhantomData<&'obj mut T>, +} + +impl<'obj, T> Deref for RefMut<'obj, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.ptr.as_ref().unwrap_unchecked() } + } +} + +impl<'obj, T> DerefMut for RefMut<'obj, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.ptr.as_mut().unwrap_unchecked() } + } +} + +impl<'a, T> From> for GlobalPtr { + fn from(value: RefMut<'a, T>) -> Self { + todo!() + } +} diff --git a/src/lib/twizzler/src/tx.rs b/src/lib/twizzler/src/tx.rs index 16830d95..22c26b86 100644 --- a/src/lib/twizzler/src/tx.rs +++ b/src/lib/twizzler/src/tx.rs @@ -1,21 +1,22 @@ -/// A trait for implementing transaction handles. -/// -/// Takes a lifetime argument, 'obj. All object handles referenced by this transaction must have -/// this lifetime or longer. -pub trait TxHandle<'obj> { - /// Ensures transactional safety for mutably accessing data given by the range [data, data + - /// sizeof(T)). - fn tx_mut(&self, data: *const T) -> TxResult<*mut T, E>; +mod batch; +mod object; +mod unsafetx; + +pub use batch::*; +pub use object::*; +pub use unsafetx::*; + +/// A trait for implementing per-object transaction handles. +pub trait TxHandle { + /// Ensures transactional safety for mutably accessing data in the range [data, data + len). + fn tx_mut(&self, data: *const u8, len: usize) -> Result<*mut u8>; } -pub type TxResult = Result>; +pub type Result = std::result::Result; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, thiserror::Error)] /// Transaction errors, with user-definable abort type. -pub enum TxError { - /// Transaction aborted. - #[error("aborted: {0}")] - Abort(E), +pub enum TxError { /// Resources exhausted. #[error("resources exhausted")] Exhausted, diff --git a/src/lib/twizzler/src/tx/batch.rs b/src/lib/twizzler/src/tx/batch.rs new file mode 100644 index 00000000..cd7f5960 --- /dev/null +++ b/src/lib/twizzler/src/tx/batch.rs @@ -0,0 +1,73 @@ +use std::marker::PhantomData; + +use super::{Result, TxHandle, TxObject}; +use crate::object::Object; + +#[derive(Default)] +pub struct TxBatch { + txs: Vec>, +} + +#[repr(transparent)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct HandleIdx(usize, PhantomData); + +impl Clone for HandleIdx { + fn clone(&self) -> Self { + Self(self.0, self.1) + } +} + +impl Copy for HandleIdx {} + +impl TxBatch { + pub fn tx(&mut self, obj: Object) -> Result> { + todo!() + } + + pub fn handle(&self, idx: HandleIdx) -> &TxObject { + todo!() + } + + pub fn handle_mut(&mut self, idx: HandleIdx) -> &mut TxObject { + todo!() + } + + pub fn commit(&mut self, idx: HandleIdx) -> Result> { + todo!() + } +} + +mod tests { + use crate::{ + marker::BaseType, + object::{ObjectBuilder, TypedObject}, + tx::TxBatch, + }; + + struct Simple { + x: u32, + } + + impl BaseType for Simple {} + + fn simple_batch_tx() { + let builder = ObjectBuilder::default(); + let obj1 = builder.build(Simple { x: 3 }).unwrap(); + let obj2 = builder.build(Simple { x: 7 }).unwrap(); + + let (obj1, obj2) = { + let mut batch = TxBatch::default(); + let tx1 = batch.tx(obj1).unwrap(); + let tx2 = batch.tx(obj2).unwrap(); + batch.handle_mut(tx1).base_mut().x = 8; + batch.handle_mut(tx2).base_mut().x = 12; + let obj1 = batch.commit(tx1).unwrap(); + let obj2 = batch.commit(tx2).unwrap(); + (obj1, obj2) + }; + + assert_eq!(obj1.base().x, 8); + assert_eq!(obj2.base().x, 12); + } +} diff --git a/src/lib/twizzler/src/tx/object.rs b/src/lib/twizzler/src/tx/object.rs new file mode 100644 index 00000000..b3901da5 --- /dev/null +++ b/src/lib/twizzler/src/tx/object.rs @@ -0,0 +1,70 @@ +use super::{Result, TxHandle}; +use crate::{ + marker::BaseType, + object::{Object, RawObject, TypedObject}, + ptr::RefMut, +}; + +pub struct TxObject { + object: Object, +} + +impl TxObject { + pub fn commit(self) -> Result> { + todo!() + } + + pub fn abort(self) -> Object { + todo!() + } + + pub fn base_mut(&mut self) -> RefMut<'_, T> { + todo!() + } +} + +impl TxHandle for TxObject { + fn tx_mut(&self, data: *const u8, len: usize) -> super::Result<*mut u8> { + todo!() + } +} + +impl RawObject for TxObject { + fn handle(&self) -> &twizzler_rt_abi::object::ObjectHandle { + self.object.handle() + } +} + +impl TypedObject for TxObject { + type Base = B; + + fn base(&self) -> crate::ptr::Ref<'_, Self::Base> { + todo!() + } +} + +mod tests { + use crate::{ + marker::BaseType, + object::{ObjectBuilder, TypedObject}, + }; + + struct Simple { + x: u32, + } + + impl BaseType for Simple {} + + fn single_tx() { + let builder = ObjectBuilder::default(); + let obj = builder.build(Simple { x: 3 }).unwrap(); + let base = obj.base(); + assert_eq!(base.x, 3); + + let mut tx = obj.tx().unwrap(); + let mut base = tx.base_mut(); + base.x = 42; + let obj = tx.commit().unwrap(); + assert_eq!(obj.base().x, 42); + } +} diff --git a/src/lib/twizzler/src/tx/unsafe.rs b/src/lib/twizzler/src/tx/unsafe.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/lib/twizzler/src/tx/unsafetx.rs b/src/lib/twizzler/src/tx/unsafetx.rs new file mode 100644 index 00000000..f450bda3 --- /dev/null +++ b/src/lib/twizzler/src/tx/unsafetx.rs @@ -0,0 +1,15 @@ +use super::TxHandle; + +pub struct UnsafeTxHandle {} + +impl UnsafeTxHandle { + pub unsafe fn new() -> Self { + UnsafeTxHandle {} + } +} + +impl TxHandle for UnsafeTxHandle { + fn tx_mut(&self, data: *const u8, len: usize) -> super::Result<*mut u8> { + todo!() + } +}