[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC] QOM design - add instance data to Object
From: |
Liviu Ionescu |
Subject: |
Re: [Qemu-devel] [RFC] QOM design - add instance data to Object |
Date: |
Sat, 13 Jun 2015 11:42:11 +0300 |
any object oriented gurus around?
regards,
Liviu
> On 12 Jun 2015, at 14:33, Liviu Ionescu <address@hidden> wrote:
>
> while implementing the cortex-m hierarchical objects I faced several problems
> that required some hack, and I wanted to know your comments on them.
>
> for convenience I'll explain the problem in C++ and then return to the issues
> of the C implementation. (the C++ syntax may not be very strict).
>
> one of my goals was to emulate a representative number of MCUs, from several
> vendors. the model I used is hierarchical, grouping vendor common
> characteristics. for example for ST I have:
>
> class CortexM {};
> class STM32 : public CortexM {};
> class STM32F103RB : public STM32 {};
>
> to facilitate configuration of the CortexM and STM objects, I defined some
> 'capabilities' classes:
>
> class CortexMCapabilities {};
> class STM32Capabilities : public CortexMCapabilities {};
>
> in the CortexMCapabilities I store the Cortex-M family
> (M0/M0+/M1/M3/M4/M4F/M7/M7F), flash/sram memory sizes, number of interrupts,
> flags telling if MPU, ITP, or other ARM peripherals are present.
>
> in the STM32Capabilities I store STM family (F1/F2/F4/F4/etc), number of
> GPIOs, etc.
>
> a capabilities object must be defined for each device, for example:
>
> STM32Capabilities stm32f103rb_capabilities; ...
>
> this pointer is passed to the constructors and as such would be available to
> all objects:
>
> class CortexM
> {
> public:
> CortexM(CortexMCapabilities* capabilities) {
> fCapabilities = capabilities;
> ...
> }
>
> CortexMCapabilities* fCapabilities;
> ...
> }
>
> class STM32 : public CortexM {
> public:
> STM32(STM32Capabilities* capabilities) : CortexM(capabilities) {
> ...
> }
> }
>
> class STM32F103RB : public STM32 {
> public:
> STM32F103RB(STM32Capabilities* capabilities) : STM32(capabilities) {
> ...
> }
> }
>
> when constructing a new mcu:
>
> STM32F103RB* mcu = new STM32F103RB(&stm32f103rb_capabilities);
>
> the constructors are executed in the natural 'parent first' order:
>
> CortexM(...)
> STM32(...)
> STM32F103RB(...)
>
> and each object gets access to the capabilities during the construction, as
> expected.
>
>
> now let's return to the qemu objects I used, where I have
>
> - a 'cortex-mcu' object derived from 'sys-bus-device', which has as member a
> pointer to the capabilities
> - a 'stm32-mcu' object, derived from 'cortex-mcu'
> - a 'STM32F103RB' object, derived from 'stm32-mcu' (the name matches the
> CMSIS device name).
>
> the natural place to define the capabilities is the more specfic instance_init
>
> static void stm32f103rb_mcu_instance_init_callback(Object *obj)
> {
> qemu_log_function_name();
>
> CortexMState *cm_state = CORTEXM_MCU_STATE(obj);
> cm_state->capabilities = (CortexMCapabilities *) &stm32f103rb_capabilities;
> }
>
>
> constructing a mcu is done with:
>
> dev = qdev_create(NULL, 'STM32F103RB');
>
> which calls in order:
>
> cortexm_mcu_instance_init_callback()
> stm32_mcu_instance_init_callback()
> stm32f103rb_mcu_instance_init_callback()
>
> as you can see, the stm32f103rb call is executed last (as it should be). this
> also means that during the execution of the cortexm_ and stm_ functions the
> capabilities **are not** available.
>
>
> the workaround I used was to move the object construction from instance_init
> to instance_post_init, which are executed after the instance_init, so when
> they run the capabilities pointer is already set.
>
> unfortunately, these calls are executed in reverse order of the constructors,
> 'child first', which might create problems if references to parent objects
> are required.
>
> stm32f103rb_mcu_instance_post_init_callback()
> stm32_mcu_instance_post_init_callback()
> ...
> cortexm_mcu_instance_post_init_callback()
> ...
>
> to solve the problem of references to parent objects, the third construction
> step is performed during realize().
>
> unfortunately realize() is a simple virtual call, and since pointers to
> virtuals are stored in the class structure and not as separate vtbls, access
> to parent realize() is not possible directly, but only by manually storing
> the pointer in a separate parent_realize(0 and explicitly calling it at the
> beginning of each realize().
>
>
> ---
>
> another similar problem that required a hack was passing some of the machine
> fields (kernel_filename & cpu_model) to the mcu constructor.
>
> so, the actual mcu costructor has, in addition to the mcu name
> ('STM32F103RB'), a pointer to the machine.
>
> for not being able to pass it to the constructor, I had to store it in a
> static variable and in the constructor refer to it, but this is definitely a
> non-reentrant kludge:
>
> static MachineState *global_machine;
>
> DeviceState *cortexm_mcu_create(MachineState *machine, const char *mcu_type)
> {
> /*
> * Kludge, since it is not possible to pass data to object creation,
> * we use a static variable.
> */
> global_machine = machine;
> DeviceState *dev;
> dev = qdev_create(NULL, mcu_type);
>
> return dev;
> }
>
> static void cortexm_mcu_instance_init_callback(Object *obj)
> {
> qemu_log_function_name();
>
> CortexMState *cm_state = CORTEXM_MCU_STATE(obj);
> assert(global_machine != NULL);
>
> if (global_machine->kernel_filename) {
> cm_state->kernel_filename = global_machine->kernel_filename;
> }
>
> if (global_machine->cpu_model) {
> cm_state->cpu_model = global_machine->cpu_model;
> }
> }
>
> ---
>
> I think that both the above cases show that a mechanism to pass instance data
> to the constructor is missing from the QOM design.
>
> a bit curious is that the designer considered a similar mechanism to pass
> class data when creating class objects, but this cannot be used for classes
> that have multiple instances.
>
>
> to avoid breaking compatibility, the solution that I suggest is to add
> separate initialisation functions
> - add a new "void* instance_data;" member to Object,
> - add a new function to object_initialize_with_instance_data(), to pass this
> pointer
> - add a new function qdev_create_with_instance_data() to pass this pointer
>
> calling the existing constructor functions will create objects with this
> pointer set to NULL, calling the new functions will create objects with this
> pointer set to the desired value.
>
> please note that this pointer must be set before any call to the
> instance_init() callbacks.
>
> access to the instance data would be easy, using something like
> "OBJECT(dev)->instance_data", or, even better, a specialised getter
>
> void* object_get_instance_data(Object*);
>
> ---
>
> as a conclusion, a very simple thing like passing initialisation data to a
> C++ constructor requires a pretty sustained effort with the Qemu C
> implementation. unfortunately, this is also true for some other QOM aspects,
> like calling parent virtual methods.
>
> a solution to simplify things is to add instance data to the object, and
> functions to set/get it.
>
> my initial guess is that this solution can be implemented without breaking
> compatibility with existing code, by adding new functions; the suggested
> names are obviously not mandatory, any other more inspired names may be used.
>
>
> regards,
>
> Liviu
>
>
> p.s. I generally appreciate creativity and the desire to invent new solutions
> for various problems; Stroustrup solution to the need of objects was to
> create a new programming language; your solution to the need of objects,
> instead of choosing a more appropriate language, was to insist on using C and
> invent a very, very complicated infrastructure, that requires a lot of
> explicit code to be manually written, it is relatively error prone, and it
> still has several design flaws; please believe me, it is quite difficult to
> outsmart Stroustrup...
>
>
>
>
- [Qemu-devel] [RFC] QOM design - add instance data to Object, Liviu Ionescu, 2015/06/12
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object,
Liviu Ionescu <=
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object, Peter Crosthwaite, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object, Liviu Ionescu, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Liviu Ionescu, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object, Peter Crosthwaite, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object, Liviu Ionescu, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Liviu Ionescu, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Peter Crosthwaite, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Liviu Ionescu, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Peter Crosthwaite, 2015/06/13
- Re: [Qemu-devel] [RFC] QOM design - add instance data to Object (-> add constructors), Liviu Ionescu, 2015/06/14