All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel <qemu-devel@nongnu.org>,
	qemu-rust@nongnu.org, Junjie Mao <junjie.mao@hotmail.com>
Subject: Re: [PATCH 24/26] rust: qom: move device_id to PL011 class side
Date: Wed, 18 Dec 2024 14:57:54 +0800	[thread overview]
Message-ID: <Z2JycooziPsfV8vX@intel.com> (raw)
In-Reply-To: <CABgObfY=jyu96eZ+ZcU9GXU+amt2wRm53vpvubHYTaeY9MWd2A@mail.gmail.com>

On Tue, Dec 17, 2024 at 05:50:09PM +0100, Paolo Bonzini wrote:
> Date: Tue, 17 Dec 2024 17:50:09 +0100
> From: Paolo Bonzini <pbonzini@redhat.com>
> Subject: Re: [PATCH 24/26] rust: qom: move device_id to PL011 class side
> 
> Il mar 17 dic 2024, 04:39 Zhao Liu <zhao1.liu@intel.com> ha scritto:
> 
> > > +impl ClassInitImpl<PL011Class> for PL011State {
> > > +    fn class_init(klass: &mut PL011Class) {
> > > +        klass.device_id = DeviceId::ARM;
> > > +        <Self as ClassInitImpl<SysBusDeviceClass>>::class_init(&mut
> > klass.parent_class);
> >
> > This seems a bit of a conflict with the C version of QOM semantics. In C,
> > class_init is registered in TypeInfo, and then the QOM code will
> > automatically call the parent's class_init without needing to explicitly
> > call the parent's in the child's class_init.
> >
> 
> This is the same in Rust.
> 
> The difference is that in C you have a single class_init function that sets
> all members of ObjectClass, DeviceClass, etc. In Rust each class has one
> trait and there is a chain of ClassInitImpl implementations—one filling in
> "oc" from ObjectImpl, one filling in "dc" from DeviceImpl and so on.
>
> But in both cases you get a chain of calls from qom/object.c.
> 
> Therefore, the call here seems valid from the code logic's perspective.

I supposed a case, where there is such a QOM (QEMU Object Model)
structure relationship:

* DummyState / DummyClass: defined in Rust side, and registered the
  TypeInfo by `Object` macro.

  - So its class_init will be called by C QOM code.

* DummyChildState / DummyChildClass: defined in Rust side as the
  child-object of DummyState, and registered the TypeInfo by `Object`
  macro. And suppose it can inherit the trait of DummyClass -
  ClassInitImpl<DummyClass> (but I found a gap here, as detailed later;
  I expect it should be able to inherit normally).

 - So its class_init will be called by C QOM code. In C code call chain,
   its parent's class_init should be called by C before its own
   class_init.
 - However, note that according to the Rust class initialization call
   chain, it should also call the parent's class_init within its own
   class_init.
 - :( the parent's class_init gets called twice.

If you agree this case indeed exists, then I think we should distinguish
between different class_init methods for the Rust and C call chains.

Moving on to another topic, about the gap (or question :-)) where a
child class inherits the ClassInitImpl trait from the parent, please see
my test case example below: Doing something similar to SysBusDevice and
DeviceState using a generic T outside of the QOM library would violate
the orphan rule.

diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs
index 7edadf911cca..8cae222a37be 100644
--- a/rust/qemu-api/tests/tests.rs
+++ b/rust/qemu-api/tests/tests.rs
@@ -13,8 +13,8 @@
 use qemu_api::{
     bindings::*,
     c_str, declare_properties, define_property,
-    qdev::{DeviceImpl, DeviceState, Property},
-    qom::{ObjectCast, ObjectCastMut, ObjectImpl, ObjectMethods, ObjectType},
+    qdev::{DeviceClass, DeviceImpl, DeviceState, Property},
+    qom::{ClassInitImpl, ObjectCast, ObjectCastMut, ObjectImpl, ObjectMethods, ObjectType},
     qom_isa,
     vmstate::VMStateDescription,
     zeroable::Zeroable,
@@ -37,6 +37,10 @@ pub struct DummyState {

 qom_isa!(DummyState: Object, DeviceState);

+pub struct DummyClass {
+    parent_class: <DeviceState as ObjectType>::Class,
+}
+
 declare_properties! {
     DUMMY_PROPERTIES,
         define_property!(
@@ -49,7 +53,7 @@ pub struct DummyState {
 }

 unsafe impl ObjectType for DummyState {
-    type Class = <DeviceState as ObjectType>::Class;
+    type Class = DummyClass;
     const TYPE_NAME: &'static CStr = c_str!("dummy");
 }

@@ -67,6 +71,51 @@ fn vmsd() -> Option<&'static VMStateDescription> {
     }
 }

+// `impl<T> ClassInitImpl<DummyClass> for T` doesn't work since it violates orphan rule.
+impl ClassInitImpl<DummyClass> for DummyState {
+    fn class_init(klass: &mut DummyClass) {
+        <Self as ClassInitImpl<DeviceClass>>::class_init(&mut klass.parent_class);
+    }
+}
+
+#[derive(qemu_api_macros::offsets)]
+#[repr(C)]
+#[derive(qemu_api_macros::Object)]
+pub struct DummyChildState {
+    parent: DummyState,
+    migrate_clock: bool,
+}
+
+qom_isa!(DummyChildState: Object, DeviceState, DummyState);
+
+pub struct DummyChildClass {
+    parent_class: <DummyState as ObjectType>::Class,
+}
+
+unsafe impl ObjectType for DummyChildState {
+    type Class = DummyChildClass;
+    const TYPE_NAME: &'static CStr = c_str!("dummy_child");
+}
+
+impl ObjectImpl for DummyChildState {
+    type ParentType = DummyState;
+    const ABSTRACT: bool = false;
+}
+
+impl DeviceImpl for DummyChildState {}
+
+impl ClassInitImpl<DummyClass> for DummyChildState {
+    fn class_init(klass: &mut DummyClass) {
+        <Self as ClassInitImpl<DeviceClass>>::class_init(&mut klass.parent_class);
+    }
+}
+
+impl ClassInitImpl<DummyChildClass> for DummyChildState {
+    fn class_init(klass: &mut DummyChildClass) {
+        <Self as ClassInitImpl<DummyClass>>::class_init(&mut klass.parent_class);
+    }
+}
+
 fn init_qom() {
     static ONCE: Mutex<Cell<bool>> = Mutex::new(Cell::new(false));

@@ -85,6 +134,7 @@ fn test_object_new() {
     init_qom();
     unsafe {
         object_unref(object_new(DummyState::TYPE_NAME.as_ptr()).cast());
+        object_unref(object_new(DummyChildState::TYPE_NAME.as_ptr()).cast());
     }
 }

> > But, when there is deeper class inheritance, it seems impossible to
> > prevent class_init from being called both by the C side's QOM code and by
> > this kind of recursive case on the Rust side.
> >
> 
> Note that here you have two parameters: what class is being filled (the
> argument C of ClassInitImpl<C>) *and* what type is being initialized
> (that's Self).
> 
> The "recursion" is only on the argument C, and matches the way C code
> implements class_init.

For Rust side, PL011Class' class_init calls SysBusDeviceClass' class_init,
and SysBusDeviceClass will also call DeviceClass' class_init. So this is
also recursion, right?

> Maybe the confusion is because I implemented class_init twice instead of
> using a separate trait "PL011Impl"?

Ah, yes! But I think the Rust call chain should not use class_init anymore
but should use a different method. This way, the original class_init would
only serve the C QOM. A separate trait might break the inheritance
relationship similar to ClassInitImpl.

Regards,
Zhao




  reply	other threads:[~2024-12-18  6:39 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-09 12:36 [PATCH 00/26] rust: bundle of prerequisites for HPET implementation Paolo Bonzini
2024-12-09 12:36 ` [PATCH 01/26] bql: check that the BQL is not dropped within marked sections Paolo Bonzini
2024-12-09 12:36 ` [PATCH 02/26] rust: cell: add BQL-enforcing Cell variant Paolo Bonzini
2024-12-09 12:36 ` [PATCH 03/26] rust: cell: add BQL-enforcing RefCell variant Paolo Bonzini
2024-12-09 12:36 ` [PATCH 04/26] rust: define prelude Paolo Bonzini
2024-12-10  7:19   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 05/26] rust: add bindings for interrupt sources Paolo Bonzini
2024-12-10  7:25   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 06/26] rust: add a bit operation module Paolo Bonzini
2024-12-10  8:13   ` Zhao Liu
2024-12-10  9:30     ` Paolo Bonzini
2024-12-09 12:36 ` [PATCH 07/26] rust: qom: add default definitions for ObjectImpl Paolo Bonzini
2024-12-10  8:21   ` Zhao Liu
2024-12-09 12:36 ` [PATCH 08/26] rust: qom: rename Class trait to ClassInitImpl Paolo Bonzini
2024-12-10  8:24   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 09/26] rust: qom: convert type_info! macro to an associated const Paolo Bonzini
2024-12-10  8:30   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 10/26] rust: qom: move ClassInitImpl to the instance side Paolo Bonzini
2024-12-10 16:03   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 11/26] rust: qdev: move device_class_init! body to generic function, ClassInitImpl implementation to macro Paolo Bonzini
2024-12-10 16:06   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 12/26] rust: qdev: move bridge for realize and reset functions out of pl011 Paolo Bonzini
2024-12-10 16:07   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 13/26] rust: qom: automatically use Drop trait to implement instance_finalize Paolo Bonzini
2024-12-10 16:16   ` Zhao Liu
2024-12-11 12:42     ` Paolo Bonzini
2024-12-11 15:37       ` Zhao Liu
2024-12-09 12:37 ` [PATCH 14/26] rust: qom: move bridge for TypeInfo functions out of pl011 Paolo Bonzini
2024-12-10 15:50   ` Zhao Liu
2024-12-10 17:38     ` Paolo Bonzini
2024-12-11  7:59       ` Zhao Liu
2024-12-11  9:11         ` Paolo Bonzini
2024-12-11 16:56           ` Zhao Liu
2024-12-12  9:24             ` Paolo Bonzini
2024-12-13  8:53               ` Zhao Liu
2024-12-10 16:02   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 15/26] rust: qom: split ObjectType from ObjectImpl trait Paolo Bonzini
2024-12-11  8:41   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 16/26] rust: qom: change the parent type to an associated type Paolo Bonzini
2024-12-11  8:47   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 17/26] rust: qom: put class_init together from multiple ClassInitImpl<> Paolo Bonzini
2024-12-12  9:15   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 18/26] rust: qom: add possibility of overriding unparent Paolo Bonzini
2024-12-12  9:40   ` Zhao Liu
2024-12-12 11:15     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 19/26] rust: rename qemu-api modules to follow C code a bit more Paolo Bonzini
2024-12-12  9:52   ` Zhao Liu
2024-12-12 11:28     ` Paolo Bonzini
2024-12-13  9:19       ` Zhao Liu
2024-12-13 11:24         ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 20/26] rust: re-export C types from qemu-api submodules Paolo Bonzini
2024-12-12  9:55   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 21/26] rust: tests: allow writing more than one test Paolo Bonzini
2024-12-12 10:04   ` Zhao Liu
2024-12-16 15:07     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 22/26] rust: qom: add casting functionality Paolo Bonzini
2024-12-16 12:53   ` Zhao Liu
2024-12-16 15:17     ` Paolo Bonzini
2024-12-09 12:37 ` [PATCH 23/26] rust: qom: add initial subset of methods on Object Paolo Bonzini
2024-12-16 15:18   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 24/26] rust: qom: move device_id to PL011 class side Paolo Bonzini
2024-12-17  3:58   ` Zhao Liu
2024-12-17 16:50     ` Paolo Bonzini
2024-12-18  6:57       ` Zhao Liu [this message]
2024-12-18  7:14         ` Paolo Bonzini
2024-12-18 10:26           ` Paolo Bonzini
2024-12-18 14:46             ` Zhao Liu
2024-12-18 16:01               ` Paolo Bonzini
2024-12-18 14:30           ` Zhao Liu
2024-12-18 14:47   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 25/26] rust: qemu-api: add a module to wrap functions and zero-sized closures Paolo Bonzini
2024-12-17 15:03   ` Zhao Liu
2024-12-09 12:37 ` [PATCH 26/26] rust: callbacks: allow passing optional callbacks as () Paolo Bonzini
2024-12-17 16:13   ` Zhao Liu
2024-12-17 16:40     ` Paolo Bonzini
2024-12-18  7:09       ` Zhao Liu
2024-12-18  7:32         ` Paolo Bonzini
2024-12-18 15:09           ` Zhao Liu
2024-12-09 16:24 ` [PATCH 00/26] rust: bundle of prerequisites for HPET implementation Philippe Mathieu-Daudé
2024-12-09 17:23   ` Paolo Bonzini
2024-12-10  2:38     ` Zhao Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Z2JycooziPsfV8vX@intel.com \
    --to=zhao1.liu@intel.com \
    --cc=junjie.mao@hotmail.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-rust@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.