Il mer 18 dic 2024, 07:39 Zhao Liu <[email protected]> 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
>