Il mer 18 dic 2024, 07:39 Zhao Liu <zhao1....@intel.com> ha scritto:

> 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.
>

No, I don't think so. You have the same thing already with
PL011State/PL011Luminary.

There, you have

* object_class_init
* device_class_init
* sysbus_device_class_init
* <PL011State as ClassInitImpl<PL011Class>>::class_init
  * <PL011State as ClassInitImpl<SysBusDeviceClass>>::class_init
    * <PL011State as ClassInitImpl<DeviceClass>>::class_init
      * <PL011State as ClassInitImpl<ObjectClass>>::class_init
* <PL011Luminary as ClassInitImpl<PL011Class>>::class_init
  * <PL011Luminary as ClassInitImpl<SysBusDeviceClass>>::class_init
    * <PL011Luminary as ClassInitImpl<DeviceClass>>::class_init
      * <PL011Luminary as ClassInitImpl<ObjectClass>>::class_init

But note that these calls are all different and indeed the last three are
empty (all vtable entries are None). This is like a C class_init
implementation that does not set any of sdc, dc or oc.

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.
>

Ugh, you're right. Maybe ClassInitImpl should just be merged into
ObjectImpl etc. as a default method implementation. I will check.

> > 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?
>

No, Self is not PL011Class. Self is PL011State (or PL011Luminary/ and it
always remains the same. What changes is *what part* of the class is
overwritten, but the order of calls from qom/object.c follows the same
logic in both C and Rust.

> 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.
>

Do you still think that this is the case? I will look into how to avoid the
problem with the orphan rule, but otherwise I think things are fine.

Paolo

>

Reply via email to