How to Write a Service

Complete: 4

Introduction

Services are meant to be application extensions and as such their use should have no effect on physics results. Therefore, loggers and histogrammers make good services, while a tracker fitter would not be. Algorithms that effect physics should be obtained through the edm::Event or edm::EventSetup so that the provenance can be tracked.

Restrictions on Service Classes

There are no restrictions on the interface for a Service class, e.g., it does not have to inherit from a specific base class. However, services may be shared between different threads and therefore standard thread safety issues should be followed.

Application State Available to Services

Services are allowed to see application state transistions (e.g., starting to process a new event). This is accomplished through the edm::ActivityRegistry. The edm::ActivityRegistry uses sigc++ signals to allow Services to register callback functions that are called when an application state transition occurs. The presently available transitions are given below

name arguments for callback description
preSourceConstruction const edm::ModuleDescription& called before the calling of the InputSource's constructor
postSourceConstruction const edm::ModuleDescription& called after the calling of the InputSource's constructor
preModuleConstruction const edm::ModuleDescription& called before the calling of a Module's constructor
postModuleConstruction const edm::ModuleDescription& called after the calling of a Module's constructor
preModuleBeginJob const edm::ModuleDescription& called before the calling of a Module's beginJob
postModuleBeginJob const edm::ModuleDescription& called after the calling of a Module's beginJob
postBeginJob none called after all modules have successfully had beginJob called
preModuleEndJob const edm::ModuleDescription& called before the calling of a Module's endJob
postModuleEndJob const edm::ModuleDescription& called after the calling of a Module's endJob
postEndJob none called after all modules have successfully had endJob called
jobFailure none called if event or end-of-job processing terminated because of an uncaught exception
preSource none called just before the InputSource starts to make an event
postSource none called just after the InputSource has made an event
preSourceRun none called just before the InputSource starts to make a run
postSourceRun none called just after the InputSource has made a run
preSourceLumi none called just before the InputSource starts to make a luminosity block
postSourceLumi none called just after the InputSource has made a luminosity block
preOpenFile none called just before the InputSource opens a primary ROOT/EDM file
postOpenFile none called just after the InputSource has opened a primary ROOT/EDM file
preCloseFile none called just before the InputSource closes a primary ROOT/EDM file
postCloseFile none called just after the InputSource has closed a primary ROOT/EDM file
preProcessEvent const edm::EventID&, const edm::Timestamp& called after event has been fetched by InputSource but before any modules have processed the Event
postProcessEvent const edm::Event&, const edm::EventSetup& called after all modules have processed an Event
preBeginRun const edm::RunID&, const edm::Timestamp& called after run has been fetched by InputSource but before any modules have processed the beginRun
postBeginRun const edm::Run&, const edm::EventSetup& called after all modules have processed a beginRun
preEndRun const edm::RunID&, const edm::Timestamp& called before any modules have processed an endRun
postEndRun const edm::Run&, const edm::EventSetup& called after all modules have processed an endRun
preBeginLumi const edm::LuminosityBlockID&, const edm::Timestamp& called after lumi has been fetched by InputSource but before any modules have processed the beginLuminosityBlock
postBeginLumi const edm::LuminosityBlock&, const edm::EventSetup& called after all modules have processed a beginLuminosityBlock
preEndLumi const edm::LuminosityBlockID&, const edm::Timestamp& called before any modules have processed an endLuminosityBlock
postEndLumi const edm::LuminosityBlock&, const edm::EventSetup& called after all modules have processed an endLuminosityBlock
preProcessPath const std::string& called before processing of a path begins for an Event
postProcessPath const std::string&, const edm::HLTPathStatus& called after processing of a path for an Event ends
prePathBeginRun const std::string& called before processing of a path begins for beginRun
postPathBeginRun const std::string&, const edm::HLTPathStatus& called after processing of a path for beginRun ends
prePathEndRun const std::string& called before processing of a path begins for endRun
postPathEndRun const std::string&, const edm::HLTPathStatus& called after processing of a path for endRun ends
prePathBeginLumi const std::string& called before processing of a path begins for beginLuminosityBlock
postPathBeginLumi const std::string&, const edm::HLTPathStatus& called after processing of a path for beginLuminosityBlock ends
prePathEndLumi const std::string& called before processing of a path begins for endLuminosityBlock
postPathEndLumi const std::string&, const edm::HLTPathStatus& called after processing of a path for endLuminosityBlock ends
preModule const edm::ModuleDescription& called before the module starts to process an Event
postModule const edm::ModuleDescription& called after the module successfully processed an Event
preModuleBeginRun const edm::ModuleDescription& called before the calling of a Module's beginRun
postModuleBeginRun const edm::ModuleDescription& called after the calling of a Module's beginRun
preModuleEndRun const edm::ModuleDescription& called before the calling of a Module's endRun
postModuleEndRun const edm::ModuleDescription& called after the calling of a Module's endRun
preModuleBeginLumi const edm::ModuleDescription& called before the calling of a Module's beginLuminosityBlock
postModuleBeginLumi const edm::ModuleDescription& called after the calling of a Module's beginLuminosityBlock
preModuleEndLumi const edm::ModuleDescription& called before the calling of a Module's endLuminosityBlock
postModuleEndLumi const edm::ModuleDescription& called after the calling of a Module's endLuminosityBlock

Note: All signals involving runs, luminosity blocks, or opening/closing files were added for the 2_2_X queue (2_2_0?). They are not available in prior releases.

An edm::ActivityRegistry& is optionally passed to a Service in its constructor [technically it is actually passed to the Service's Maker's make function]. There are several ways a callback can be attached to the edm::ActivityRegistry&, the easiest is to use the appropriate 'watch' method. The 'watch' method for a transition prepends 'watch' to the name of the transition (e.g., watchPostBeginJob). The first argument to a 'watch' method is a pointer to the object (usually the Service instance) and the second argument is the address of the member method that should be called. The member method must have the proper signature for the signal being watched. E.g.,

  class Foo {
    public:
      Foo(edm::ActivityRegistry& iAR){
         iAR.watchPostBeginJob(this, &Foo::beginJobFinished);
      }
      void beginJobFinished();
  };

There is an extra rule that applies in the special case where a service depends on another service. In this case, these 'watch' methods should be called in the constructor after any direct or indirect calls to any other service. Putting them at the end of the constructor is a simple way to guarantee this.

Another issue is the order in which the callback functions will be executed when the callbacks are from many different services and associated with the same signal (for example PostBeginJob). When possible it is best to avoid anything that depends on this order. So in most cases, as a service writer or user you do not need to know about this and can stop reading and skip to the next section. But there are some cases where services depend on other services and this is important. For those interested in the details, take a look here: SWGuideEDMServiceDocOrderOfCalls.

Registering a Service

The exact syntax to use to register your code as a service depends on two factors: what arguments your Service takes in its constructor and on whether your Service is access directly or through an abstract interface from which it inherits.

Simple case

The simplest registration can be used if the Service is accessed directly (i.e., the Service<> takes the class as its template argument) and the constructor for the Service takes as arguments: const edm::ParameterSet& and edm::ActivityRegistry&. In that case, in the library that holds the Service, add a file that
  • #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
  • then call the macro DEFINE_FWK_SERVICE(<service class>)

Service makers

In all other cases, you need to follow the same instructions, except, instead of using DEFINE_FWK_SERVICE you must use the DEFINE_FWK_SERVICE_MAKER macro. This macro takes two arguments: the name of your class and a Maker.

A Maker is a C++ class that has a default constructor and defines a method

std::unique_ptr< class name > make(const edm::ParameterSet&, edm::ActivityRegistry&) const

As you probably expect, the Maker is used to construct an instance of your class given an ParameterSet and an ActivityRegistry.

Several templated Maker classes already exist (FWCore/ServiceRegistry/interaface/ServiceMaker.h)

  • AllArgsMaker<T [,TConcrete] > : creates a service providing interface T by constructing a TConcrete (which defaults to T) by passing the ParameterSet and ActivityRegistry to the TConcrete constructor.
  • ParameterSetMaker<T [,TConcrete] > : creates a service providing interface T by constructing a TConcrete by passing only a ParameterSet to the TConcrete constructor.
  • NoArgsMaker<T [,TConcrete] > : creates a service providing interface T by calling the default constructor of TConcrete.

Example: Registering a concrete implementation of an abstract service.

Say we have the abstract interface for a service

  class Foo {
    public:
      virtual void doIt() = 0;
  };

and a concrete implementation of that service

  class FooBar : public Foo {
    public:
      virtual void doIt();
  };

Then to register the FooBar service you would do

  //NOTE: typedef is used since the CPP macro can not handle the ',' needed by the template
  typedef edm::serviceregistry::NoArgsMaker<FooBar,Foo> Maker;
  DEFINE_FWK_SERVICE_MAKER(FooBar,Maker);

Multiple services in one library

If you wish to put more than one Service into a library (or if the library holds Framework modules) then you will need to register all the 'plugins' into one file, and the services registered should use the DEFINE_FWK_SERVICE (or DEFINE_FWK_SERVICE_MAKER) macro.

NOTE: this is analogous to registering multiple framework modules in the same library.

Review Status

Reviewer/Editor and Date (copy from screen) Comments
ChrisDJones - 12 Sep 2005 page author
ChrisDJones - 29 Nov 2005 page content last edited
JennyWilliams - 07 Feb 2007 editing to include in SWGuide
ChrisDJones - 11 Feb 2007 updated to include new signals
WilliamTanenbaum - 11 Oct 2008 updated to include new signals
WilliamTanenbaum - 17 Sep 2016 replace auto_ptr with unique_ptr

Responsible: ChrisDJones
Last reviewed by: Reviewer

Edit | Attach | Watch | Print version | History: r15 < r14 < r13 < r12 < r11 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r15 - 2016-09-17 - WilliamTanenbaum



 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback