Friday, April 27, 2007

Simple component system for embedded system

1. Objective

  • Separate interface and implementation
    • User depends on only interface not implementation, the implementation can evolve without breaking user.
    • User can use several implementation of one interface simultaneously.
  • Modular
    • Component is a special module, more modular.
    • Manage the dependency relationship of software modules.
  • Testable
    • The component is the test unit.
  • Position transparent (single-thread/multi-thread transparent)
    • local/remote, same thread/different thread transparent

2. Interface

  • Describe in IDL formally: language neutral
  • Binary standard: vtable
  • Implementation in C: function pointer structure
    typedef struct
    {
    void (*dvFooInit)(dvFooIntf intf);
    void (*dvFooDestroy)(dvFooIntf intf,
    FOO_DESCRIPTION sFooDesc);
    void (*dvFooBarEnable)(dvFooIntf intf, BOOL bEnable);
    ...
    } dvFooOps;

    typedef struct
    {
    dvFooOps *ops;
    } dvFoo;

    typedef dvFoo *dvFooIntf;
  • Implementation in C++: class with only pure virtual method
    class dvFoo
    {
    public:
    virtual void dvFooInit(void) = 0;
    virtual int32 dvFooDesctroy(FOO_DESCRIPTION desc) = 0;
    virtual void dvFooBarEnable(BOOL bEnable) = 0;
    ...
    };

    typedef dvFoo *dvFooIntf;
  • A tool can be developed to generate C++ and C implementation of interface from IDL automatically.

3. Component (object)

  • Properties:
    • Software module that implement one or several interfaces. The interfaces is the API of component and should be stable.
    • The source code, document, configuration information, test code of component is organized in individual folder.
    • Every component has its own version number and can evolve individually.
    • Can be selected and configured via a configuration tool.
  • Implementation
    • Implementation in C: fill function pointer structure
      dvFooOps opsfoo = {
      dvLisaFooInit,
      dvLisaFooDesctory,
      dvLisaFooBarEnable,
      ...
      };

      typedef struct
      {
      dvFooOps *ops;
      /* data members for Lisa */
      } dvLisaFoo;

      dvLisaFoo foo = {
      &opsfoo,
      /* data members for Lisa */
      };
      For driver implementation, instance number can be used as the data member.
    • Implementation in C++: inherit implemented interfaces
      class dvLisaFoo : public dvFoo
      {
      /* data members for Lisa */
      public:
      void dvFooInit(void);
      int32 dvFooDestroy(FOO_DESCRIPTION desc);
      void dvFooBarEnable(BOOL bEnable);
      ...
      };
      For driver implementation, instance number can be used as the data member.

4. Usage

After getting the pointer to the interface of the component, user of component can use the component via direct function call without need to know the implementation of component. (C user can use C++ implementation).
#define dvFooInit(intf) (intf)->ops->dvFooInit((intf))
#define dvFooDestroy(intf, sFooDesc)
(intf)->ops->dvFooDesctroy((intf), (sFooDesc))

dvFooIntf intf;
/* Get interface */
dvFooInit(intf);
dvFooDestroy(intf, sFooDesc);

5. Inter-thread (inter-process) component

If the the user and implementer of component is resided in different thread (or process), it is not sufficient to use direct function call simply. To use component across thread (process), the following mechanism is provided.
  • A proxy is provided in user thread (process), which is the representative of the component which implemented in different thread (process). The user can use the proxy in same way of component in single thread environment. The proxy implement the interface with inter-thread (inter-process) communication (such as message sending and receiving).
  • A stub is provided in implementation thread (process), which is the representative of the user which is in different thread (process). The stub use the component in the same way of user in single thread environment. The stub simulate the user with inter-thread (inter-process) communication (such as message receiving and sending).
  • A simple implementation of inter-thread inter-process provides a simple mutual exclusion resolution like crude force serialization between all functions of one component.
  • In implementation, the implementing thread id can be used in proxy as the data member.
  • A tool can be developed to generate proxy and stub implementation of interface from IDL automatically.

6. Component manager (component directory/component factory)

In order to get the interface of component, a component manager should be provided. The simplest component manager is as follow:
  • Create all components before using components. Such as, all device driver components are created using the source code generated by configuration tool. All middleware components are created using the source code generated by configuration tool too.
  • Component managers have lists of all components of system. Such as the device driver manager has the list of all device driver components.
  • Component manager provide a interface to get the interfaces of components. Such as all the interfaces of device driver components can be gotten from device driver manager.
  • For inter-thread (inter-process) components, the proxy and stub is created before using as that of the component. The proxy instead of component itself is in the list of components in component manager. The user of component will get the proxy, it is desirable.

No comments: