rust: qom: wrap Object with Opaque<>

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-02-14 12:09:53 +01:00
parent 9c9a6a889c
commit 7fb4a99df1
4 changed files with 26 additions and 20 deletions

View file

@ -46,9 +46,6 @@ unsafe impl Sync for MemoryRegion {}
unsafe impl Send for ObjectClass {} unsafe impl Send for ObjectClass {}
unsafe impl Sync for ObjectClass {} unsafe impl Sync for ObjectClass {}
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
unsafe impl Send for SysBusDevice {} unsafe impl Send for SysBusDevice {}
unsafe impl Sync for SysBusDevice {} unsafe impl Sync for SysBusDevice {}

View file

@ -157,7 +157,7 @@ impl MemoryRegion {
let cstr = CString::new(name).unwrap(); let cstr = CString::new(name).unwrap();
memory_region_init_io( memory_region_init_io(
slot, slot,
owner.cast::<Object>(), owner.cast::<bindings::Object>(),
ops, ops,
owner.cast::<c_void>(), owner.cast::<c_void>(),
cstr.as_ptr(), cstr.as_ptr(),

View file

@ -52,7 +52,7 @@ pub trait ResettablePhasesImpl {
/// can be downcasted to type `T`. We also expect the device is /// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time. /// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>( unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
obj: *mut Object, obj: *mut bindings::Object,
typ: ResetType, typ: ResetType,
) { ) {
let state = NonNull::new(obj).unwrap().cast::<T>(); let state = NonNull::new(obj).unwrap().cast::<T>();
@ -65,7 +65,7 @@ unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is /// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time. /// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>( unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
obj: *mut Object, obj: *mut bindings::Object,
typ: ResetType, typ: ResetType,
) { ) {
let state = NonNull::new(obj).unwrap().cast::<T>(); let state = NonNull::new(obj).unwrap().cast::<T>();
@ -78,7 +78,7 @@ unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is /// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time. /// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>( unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
obj: *mut Object, obj: *mut bindings::Object,
typ: ResetType, typ: ResetType,
) { ) {
let state = NonNull::new(obj).unwrap().cast::<T>(); let state = NonNull::new(obj).unwrap().cast::<T>();

View file

@ -101,16 +101,24 @@ use std::{
ptr::NonNull, ptr::NonNull,
}; };
pub use bindings::{Object, ObjectClass}; pub use bindings::ObjectClass;
use crate::{ use crate::{
bindings::{ bindings::{
self, object_class_dynamic_cast, object_dynamic_cast, object_get_class, self, object_class_dynamic_cast, object_dynamic_cast, object_get_class,
object_get_typename, object_new, object_ref, object_unref, TypeInfo, object_get_typename, object_new, object_ref, object_unref, TypeInfo,
}, },
cell::bql_locked, cell::{bql_locked, Opaque},
}; };
/// A safe wrapper around [`bindings::Object`].
#[repr(transparent)]
#[derive(Debug, qemu_api_macros::Wrapper)]
pub struct Object(Opaque<bindings::Object>);
unsafe impl Send for Object {}
unsafe impl Sync for Object {}
/// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct /// Marker trait: `Self` can be statically upcasted to `P` (i.e. `P` is a direct
/// or indirect parent of `Self`). /// or indirect parent of `Self`).
/// ///
@ -199,7 +207,7 @@ impl<T: fmt::Display + ObjectType> fmt::Display for ParentField<T> {
} }
} }
unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) { unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut bindings::Object) {
let mut state = NonNull::new(obj).unwrap().cast::<T>(); let mut state = NonNull::new(obj).unwrap().cast::<T>();
// SAFETY: obj is an instance of T, since rust_instance_init<T> // SAFETY: obj is an instance of T, since rust_instance_init<T>
// is called from QOM core as the instance_init function // is called from QOM core as the instance_init function
@ -209,7 +217,7 @@ unsafe extern "C" fn rust_instance_init<T: ObjectImpl>(obj: *mut Object) {
} }
} }
unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut Object) { unsafe extern "C" fn rust_instance_post_init<T: ObjectImpl>(obj: *mut bindings::Object) {
let state = NonNull::new(obj).unwrap().cast::<T>(); let state = NonNull::new(obj).unwrap().cast::<T>();
// SAFETY: obj is an instance of T, since rust_instance_post_init<T> // SAFETY: obj is an instance of T, since rust_instance_post_init<T>
// is called from QOM core as the instance_post_init function // is called from QOM core as the instance_post_init function
@ -230,7 +238,7 @@ unsafe extern "C" fn rust_class_init<T: ObjectType + ObjectImpl>(
<T as ObjectImpl>::CLASS_INIT(unsafe { klass.as_mut() }) <T as ObjectImpl>::CLASS_INIT(unsafe { klass.as_mut() })
} }
unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut Object) { unsafe extern "C" fn drop_object<T: ObjectImpl>(obj: *mut bindings::Object) {
// SAFETY: obj is an instance of T, since drop_object<T> is called // SAFETY: obj is an instance of T, since drop_object<T> is called
// from the QOM core function object_deinit() as the instance_finalize // from the QOM core function object_deinit() as the instance_finalize
// function for class T. Note that while object_deinit() will drop the // function for class T. Note that while object_deinit() will drop the
@ -280,14 +288,14 @@ pub unsafe trait ObjectType: Sized {
/// Return the receiver as an Object. This is always safe, even /// Return the receiver as an Object. This is always safe, even
/// if this type represents an interface. /// if this type represents an interface.
fn as_object(&self) -> &Object { fn as_object(&self) -> &Object {
unsafe { &*self.as_object_ptr() } unsafe { &*self.as_ptr().cast() }
} }
/// Return the receiver as a const raw pointer to Object. /// Return the receiver as a const raw pointer to Object.
/// This is preferrable to `as_object_mut_ptr()` if a C /// This is preferrable to `as_object_mut_ptr()` if a C
/// function only needs a `const Object *`. /// function only needs a `const Object *`.
fn as_object_ptr(&self) -> *const Object { fn as_object_ptr(&self) -> *const bindings::Object {
self.as_ptr().cast() self.as_object().as_ptr()
} }
/// Return the receiver as a mutable raw pointer to Object. /// Return the receiver as a mutable raw pointer to Object.
@ -297,8 +305,8 @@ pub unsafe trait ObjectType: Sized {
/// This cast is always safe, but because the result is mutable /// This cast is always safe, but because the result is mutable
/// and the incoming reference is not, this should only be used /// and the incoming reference is not, this should only be used
/// for calls to C functions, and only if needed. /// for calls to C functions, and only if needed.
unsafe fn as_object_mut_ptr(&self) -> *mut Object { unsafe fn as_object_mut_ptr(&self) -> *mut bindings::Object {
self.as_object_ptr() as *mut _ self.as_object().as_mut_ptr()
} }
} }
@ -621,7 +629,7 @@ pub trait ObjectImpl: ObjectType + IsA<Object> {
/// We expect the FFI user of this function to pass a valid pointer that /// We expect the FFI user of this function to pass a valid pointer that
/// can be downcasted to type `T`. We also expect the device is /// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time. /// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut Object) { unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut bindings::Object) {
let state = NonNull::new(dev).unwrap().cast::<T>(); let state = NonNull::new(dev).unwrap().cast::<T>();
T::UNPARENT.unwrap()(unsafe { state.as_ref() }); T::UNPARENT.unwrap()(unsafe { state.as_ref() });
} }
@ -796,8 +804,9 @@ pub trait ObjectClassMethods: IsA<Object> {
// SAFETY: the object created by object_new is allocated on // SAFETY: the object created by object_new is allocated on
// the heap and has a reference count of 1 // the heap and has a reference count of 1
unsafe { unsafe {
let obj = &*object_new(Self::TYPE_NAME.as_ptr()); let raw_obj = object_new(Self::TYPE_NAME.as_ptr());
Owned::from_raw(obj.unsafe_cast::<Self>()) let obj = Object::from_raw(raw_obj).unsafe_cast::<Self>();
Owned::from_raw(obj)
} }
} }
} }