lundi 17 septembre 2018

Best way to register a C++ service implementation library that can be loaded, registered and unloaded

I want to provide service collection feature in my container application. As a part of this feature, I want to expose two interfaces, a '''Service''' and a '''ServiceRegistry'''. The idea is to make various service providers to add their service implementation to the service collection by using the registry interface. There is some overlap in the application users and the application providers community.

I am thinking of following options for the service interface:

  /// Option 1
  class Service
  {
      ...
  public:
      virtual void doWork() = 0;
      ...
  };

  /// Option 2
  using service_impl_type = std::function<void()>;

I am thinking of following options for the registry interface:

  /// Option A
  class ServiceRegistry
  {
      ...
  public:
      static void register( std::string const& name, 
                            shared_ptr<Service> const& service );
      ...
  };

  /// Option B
  namespace services
  {
      void register( std::string const& name, 
                     service_impl_type const& service );
  }

The application is part of a shared object '''libContainer.so''' and is loaded by an executable '''container'''. The new interfaces would be part of the '''libServices.so''' library. The '''libContainer.so''' will depend on '''libServices.so'''.

The service providers are expected to deploy a library '''libSvcProviderXYZ.so''' containing their service implementation in a folder known to the application. The '''container''' executable loads the shared object dynamically (dlopen) and calls a known exported function '''registerYourself()''' that will be present in all the provider libraries. The '''registerYourself()''' is expected to call the service registry interface with an implementation of the service in a synchronous fashion.

My question is whether the provider shared object '''libSvcProviderXYZ.so''' can be unloaded some times after the '''registerYourself()''' completes successfully.

If I go with Option 1 for Option A (for service & registry), the xyz provider may provide the following in '''libSvcProviderXYZ.so''':

  class ServiceImpl : public Service
  {
  public:
      void doWork()
      {
          ...
      }
  };

  void registerYourself()
  {
      ServiceRegistry::register("xyz", std::make_shared<ServiceImpl>());
  }

In this case can I safely unload the provider shared object '''libSvcProviderXYZ.so''' after '''registerYourself()''' completes successfully?

If I go with Option 2 for Option B (for service & registry), the xyz provider may provide the following in '''libSvcProviderXYZ.so''':

  class ServiceImpl
  {
  public:
      void operator()()
      {
      }
  };

  void registerYourself()
  {
      ServiceImpl impl;
      services::register("xyz", impl);
  }

In this case can I safely unload the provider shared object '''libSvcProviderXYZ.so''' after '''registerYourself()''' completes successfully because of type-erasure of ServiceImpl?

Many thanks in advance for any help/advice in this regard!

Aucun commentaire:

Enregistrer un commentaire