This provides type-safe object casts, and automatic reference counting. Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- qemu/qom-rust.txt | 82 ++++++++++++ qemu/src/lib.rs | 6 + qemu/src/qom/mod.rs | 2 + qemu/src/qom/object.rs | 34 +++++ qemu/src/qom/refs.rs | 274 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 398 insertions(+) create mode 100644 qemu/qom-rust.txt create mode 100644 qemu/src/qom/mod.rs create mode 100644 qemu/src/qom/object.rs create mode 100644 qemu/src/qom/refs.rs
diff --git a/qemu/qom-rust.txt b/qemu/qom-rust.txt new file mode 100644 index 0000000..1588445 --- /dev/null +++ b/qemu/qom-rust.txt @@ -0,0 +1,82 @@ +Rust QOM interoperability design +-------------------------------- + +Passing objects around +---------------------- + +ObjectRef: +-> trait for performing casts on objects +-> upcasts safe at compile time, downcasts safe at runtime +-> implemented by &T and qom::Owned<T> +-> casting &T produces &U, casting qom::Owned<T> produces qom::Owned<U> + +qom::Owned<T> +-> T is a struct for a QOM object +-> cloning qom::Owned calls object_ref, dropping qom::Owned calls object_unref + + +Calling methods +--------------- + +- all methods &self (interior mutability) + - Rust implementation needs to wrap state with Cell<>, RefCell<> or Mutex<> + +one struct per class; one trait per non-final class; one trait per interface +struct: Object, Device, ... +- defines constructors + example: PL011::new() (technically defined on ObjectType) + +- defines methods of final classes + +trait: ObjectMethods, DeviceMethods, UserCreatableMethods, ... +- defines methods of non-final classes and interfaces + example: obj.typename() + +- automatically implemented by &T where T is a subclass + + +all methods expect interior mutability +- structs not Send/Sync by default since they contain C pointers + - hence &T and Owned<T> also not thread-safe +- good: QOM tree (e.g. object_unparent) not thread-safe +- what if objects _are_ thread-safe? + - possibly another trait ObjectSyncMethods? + +Bindings for C classes +---------------------- + +struct must implement ObjectType + + unsafe impl ObjectType for Object { + const TYPE: &'static CStr = c"object"; + } + +struct must implement IsA<T> for all superclasses T + + unsafe impl IsA<Object> for Object {} + + +Defining QOM classes in Rust +---------------------------- + +struct must be #[repr(C)] + +one traits per class + one more if it has virtual functions + +trait #1: ObjectTypeImpl, DeviceTypeImpl, ... +- metadata + type Super: ObjectType; +- functions: + unsafe fn instance_init(obj: *mut Self); + ... + +trait #2: ObjectImpl, DeviceImpl, ... +- functions: + fn unrealize(&self) + +Rust implementation split in configuration (Default + ConstDefault) and +state (Default) + +instance_init implemented automatically via Default/ConstDefault trait + maybe: pre_init hook that replaces memset(obj, 0, type->instance_size)? +instance_finalize implemented automatically via Drop trait diff --git a/qemu/src/lib.rs b/qemu/src/lib.rs index 5f926b8..0d91623 100644 --- a/qemu/src/lib.rs +++ b/qemu/src/lib.rs @@ -2,6 +2,12 @@ #![allow(dead_code)] pub mod bindings; +pub use bindings::Object; + +pub mod qom; +pub use qom::object::ObjectType; +pub use qom::refs::ObjectCast; +pub use qom::refs::Owned; pub mod util; pub use util::error::Error; diff --git a/qemu/src/qom/mod.rs b/qemu/src/qom/mod.rs new file mode 100644 index 0000000..95489c5 --- /dev/null +++ b/qemu/src/qom/mod.rs @@ -0,0 +1,2 @@ +pub mod object; +pub mod refs; diff --git a/qemu/src/qom/object.rs b/qemu/src/qom/object.rs new file mode 100644 index 0000000..bd6b957 --- /dev/null +++ b/qemu/src/qom/object.rs @@ -0,0 +1,34 @@ +//! Bindings for the QOM Object class +//! +//! @author Paolo Bonzini + +use std::ffi::CStr; + +use crate::bindings::Object; + +use crate::qom_isa; + +/// Trait exposed by all structs corresponding to QOM objects. +/// Defines "class methods" for the class. Usually these can be +/// implemented on the class itself; here, using a trait allows +/// each class to define `TYPE`, and it also lets `new()` return the +/// right type. +/// +/// # Safety +/// +/// - the first field of the struct must be of `Object` type, +/// or derived from it +/// +/// - `TYPE` must match the type name used in the `TypeInfo` (no matter +/// if it is defined in C or Rust). +/// +/// - the struct must be `#[repr(C)]` +pub unsafe trait ObjectType: Sized { + const TYPE: &'static CStr; +} + +unsafe impl ObjectType for Object { + const TYPE: &'static CStr = c"object"; +} + +qom_isa!(Object); diff --git a/qemu/src/qom/refs.rs b/qemu/src/qom/refs.rs new file mode 100644 index 0000000..a319bde --- /dev/null +++ b/qemu/src/qom/refs.rs @@ -0,0 +1,274 @@ +//! Casting and reference counting traits for QOM objects +//! +//! @author Paolo Bonzini + +use crate::bindings::object_dynamic_cast; +use crate::bindings::Object; +use crate::bindings::{object_ref, object_unref}; + +use crate::qom::object::ObjectType; + +use std::borrow::Borrow; +use std::mem::ManuallyDrop; +use std::ops::Deref; +use std::ptr::NonNull; + +/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct +/// or indirect parent of `Self`). +/// +/// # Safety +/// +/// The struct `Self` must begin, directly or indirectly, with a field of type +/// `P`. This ensures that invalid casts, which rely on `IsA<>` for static +/// checking, are rejected at compile time. +pub unsafe trait IsA<P: ObjectType>: ObjectType {} + +// SAFETY: it is always safe to cast to your own type +unsafe impl<T: ObjectType> IsA<T> for T {} + +#[macro_export] +macro_rules! qom_isa { + ($struct:ty $(,$parent:ty)* ) => { + $( + impl AsRef<$parent> for $struct { + fn as_ref(&self) -> &$parent { + use $crate::ObjectCast; + self.upcast::<$parent>() + } + } + + // SAFETY: it is the caller responsibility to have $parent as the + // first field + unsafe impl $crate::qom::refs::IsA<$parent> for $struct {} + )* + }; +} + +/// Trait for a reference to a QOM object. Allows conversion to/from +/// C objects in generic code. +pub trait ObjectCast: Copy + Deref +where + Self::Target: ObjectType, +{ + /// Convert this (possibly smart) reference to a basic Rust reference. + fn as_ref(&self) -> &Self::Target { + self.deref() + } + + /// Convert to a const Rust pointer, to be used for example for FFI. + fn as_ptr(&self) -> *const Self::Target { + self.as_ref() + } + + /// Convert to a mutable Rust pointer, to be used for example for FFI. + /// Used to implement interior mutability for objects. + /// + /// # Safety + /// + /// This method is unsafe because it overrides const-ness of `&self`. + /// Bindings to C APIs will use it a lot, but otherwise it should not + /// be necessary. + unsafe fn as_mut_ptr(&self) -> *mut Self::Target { + #[allow(clippy::as_ptr_cast_mut)] + { + self.as_ptr().cast_mut() + } + } + + /// Perform a cast to a superclass + fn upcast<'a, U: ObjectType>(self) -> &'a U + where + Self::Target: IsA<U>, + Self: 'a, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait + unsafe { self.unsafe_cast::<U>() } + } + + /// Perform a cast to a subclass. Checks at compile time that the + /// cast can succeed, but the final verification will happen at + /// runtime only. + fn downcast<'a, U: IsA<Self::Target>>(self) -> Option<&'a U> + where + Self: 'a, + { + self.dynamic_cast::<U>() + } + + /// Perform a cast between QOM types. The check that U is indeed + /// the dynamic type of `self` happens at runtime. + fn dynamic_cast<'a, U: ObjectType>(self) -> Option<&'a U> + where + Self: 'a, + { + unsafe { + // SAFETY: upcasting to Object is always valid, and the + // return type is either NULL or the argument itself + let result: *const U = + object_dynamic_cast(self.unsafe_cast::<Object>().as_mut_ptr(), U::TYPE.as_ptr()) + .cast(); + + result.as_ref() + } + } + + /// Unconditional cast to an arbitrary QOM type. + /// + /// # Safety + /// + /// What safety? You need to know yourself that the cast is correct; only use + /// when performance is paramount. It is still better than a raw pointer + /// `cast()`, which does not even check that you remain in the realm of + /// QOM `ObjectType`s. + /// + /// `unsafe_cast::<Object>()` can also be used, and is always safe, if all + /// you have is an `ObjectType` (as opposed to an `IsA<Object>`). + unsafe fn unsafe_cast<'a, U: ObjectType>(self) -> &'a U + where + Self: 'a, + { + &*(self.as_ptr().cast::<U>()) + } +} + +impl<T: ObjectType> ObjectCast for &T {} + +/// An owned reference to a QOM object. +/// +/// Like [`std::sync::Arc`], references are added with [`Clone::clone`] and removed +/// by dropping the `Owned`. +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Owned<T: ObjectType>(NonNull<T>); + +// QOM knows how to handle reference counting across threads, but sending +// the Owned to another thread requires the implementation itself to be +// thread-safe (aka Sync). But I'm not entirely sure that this is enough +// (see for example ARef in rust/kernel/types.rs, which is very similar +// to this type). +// +//unsafe impl<T: Sync + ObjectType> Send for Owned<T> {} +//unsafe impl<T: ObjectType> Sync for Owned<T> {} + +impl<T: ObjectType> Owned<T> { + /// Obtain a reference from a raw C pointer + /// + /// # Safety + /// + /// Typically this function will only be used by low level bindings + /// to C APIs. + pub unsafe fn from_raw(ptr: *const T) -> Self { + // SAFETY NOTE: while NonNull requires a mutable pointer, + // only Deref is implemented so the pointer passed to from_raw + // remains const + Owned(NonNull::new_unchecked(ptr.cast_mut())) + } + + /// Obtain a raw C pointer from a reference. `src` is consumed + /// and the reference is leaked. + pub fn into_raw(src: Owned<T>) -> *const T { + let src = ManuallyDrop::new(src); + src.0.as_ptr() + } + + + /// Increase the reference count of a QOM object and return + /// + /// # Safety + /// + /// Unsafe because the object could be embedded in another. To + /// obtain an `Owned` safely, use `ObjectType::new()`. + pub unsafe fn from(obj: &T) -> Self { + object_ref(obj.unsafe_cast::<Object>().as_mut_ptr()); + + // SAFETY NOTE: while NonNull requires a mutable pointer, + // only Deref is implemented so the pointer passed to from_raw + // remains const + Owned(NonNull::new_unchecked(obj.as_mut_ptr())) + } + + /// Perform a cast to a superclass + pub fn upcast<U: ObjectType>(src: Owned<T>) -> Owned<U> + where + T: IsA<U>, + { + // SAFETY: soundness is declared via IsA<U>, which is an unsafe trait + unsafe { Owned::unsafe_cast::<U>(src) } + } + + /// Perform a cast to a subclass. Checks at compile time that the + /// cast can succeed, but the final verification will happen at + /// runtime only. + pub fn downcast<U: IsA<T>>(src: Owned<T>) -> Result<Owned<U>, Owned<T>> { + Owned::dynamic_cast::<U>(src) + } + + /// Perform a cast between QOM types. The check that U is indeed + /// the dynamic type of `self` happens at runtime. + pub fn dynamic_cast<U: ObjectType>(src: Owned<T>) -> Result<Owned<U>, Owned<T>> { + // override automatic drop to skip the unref/ref + let src = ManuallyDrop::new(src); + match src.dynamic_cast::<U>() { + // get the ownership back from the ManuallyDrop<> + None => Err(ManuallyDrop::into_inner(src)), + + // SAFETY: the ref is moved (thanks to ManuallyDrop) from + // self to casted_ref + Some(casted_ref) => Ok(unsafe { Owned::<U>::from_raw(casted_ref) }), + } + } + + /// Unconditional cast to an arbitrary QOM type. + /// + /// # Safety + /// + /// What safety? You need to know yourself that the cast is correct. Only use + /// when performance is paramount + pub unsafe fn unsafe_cast<U: ObjectType>(src: Owned<T>) -> Owned<U> { + // override automatic drop to skip the unref/ref + let src = ManuallyDrop::new(src); + let casted_ref = src.unsafe_cast::<U>(); + Owned::<U>::from_raw(casted_ref) + } +} + +impl<T: ObjectType> AsRef<T> for Owned<T> { + fn as_ref(&self) -> &T { + self.deref() + } +} + +impl<T: ObjectType> Borrow<T> for Owned<T> { + fn borrow(&self) -> &T { + self.deref() + } +} + +impl<T: ObjectType> Clone for Owned<T> { + fn clone(&self) -> Self { + // SAFETY: creation method is unsafe, and whoever calls it + // has responsibility that the pointer is valid + unsafe { Owned::from(self.deref()) } + } +} + +impl<T: ObjectType> Deref for Owned<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: creation method is unsafe, and whoever calls it + // has responsibility that the pointer has a static lifetime. + // Once that is guaranteed, reference counting ensures that + // the object remains alive. + unsafe { &*self.0.as_ptr() } + } +} + +impl<T: ObjectType> Drop for Owned<T> { + fn drop(&mut self) { + // SAFETY: creation method is unsafe, and whoever calls it + // has responsibility that the pointer is valid + unsafe { + object_unref(self.unsafe_cast::<Object>().as_mut_ptr()); + } + } +} -- 2.45.2