Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:20

0001 // @(#)root/base:$Id$
0002 // Author: Fons Rademakers   26/1/2002
0003 
0004 /*************************************************************************
0005  * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
0006  * All rights reserved.                                                  *
0007  *                                                                       *
0008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0010  *************************************************************************/
0011 
0012 #ifndef ROOT_TPluginManager
0013 #define ROOT_TPluginManager
0014 
0015 
0016 //////////////////////////////////////////////////////////////////////////
0017 //                                                                      //
0018 // TPluginManager                                                       //
0019 //                                                                      //
0020 // This class implements a plugin library manager. It keeps track of    //
0021 // a list of plugin handlers. A plugin handler knows which plugin       //
0022 // library to load to get a specific class that is used to extend the   //
0023 // functionality of a specific base class and how to create an object   //
0024 // of this class. For example, to extend the base class TFile to be     //
0025 // able to read SQLite files one needs to load the plugin library       //
0026 // libRSQLite.so which defines the TSQLiteServer class. This loading    //
0027 // should be triggered when a given URI contains a regular expression   //
0028 // defined by the handler.                                              //
0029 // Plugin handlers can be defined via macros in a list of plugin        //
0030 // directories. With $ROOTSYS/etc/plugins the default top plugin        //
0031 // directory specified in $ROOTSYS/etc/system.rootrc. Additional        //
0032 // directories can be specified by adding them to the end of the list.  //
0033 // Macros for identical plugin handlers in later directories will       //
0034 // override previous ones (the inverse of normal search path behavior). //
0035 // The macros must have names like <BaseClass>/PX0_<PluginClass>.C,     //
0036 // e.g.:                                                                //
0037 //    TSQLServer/P20_TMySQLServer.C, etc.                               //
0038 // to allow easy sorting and grouping. If the BaseClass is in a         //
0039 // namespace the directory must have the name NameSpace@@BaseClass as   //
0040 // : is a reserved pathname character on some operating systems.        //
0041 // Macros not beginning with 'P' and ending with ".C" are ignored.      //
0042 // These macros typically look like:                                    //
0043 //                                                                      //
0044 //   void P10_TDCacheFile()                                             //
0045 //   {                                                                  //
0046 //       gPluginMgr->AddHandler("TFile", "^dcache", "TDCacheFile",      //
0047 //          "DCache", "TDCacheFile(const char*,Option_t*)");            //
0048 //   }                                                                  //
0049 //                                                                      //
0050 // Plugin handlers can also be defined via resources in the .rootrc     //
0051 // file. Although now deprecated this method still works for backward   //
0052 // compatibility, e.g.:                                                 //
0053 //                                                                      //
0054 //   Plugin.TSQLServer:  ^mysql:  TMySQLServer MySQL  "<constructor>"   //
0055 //   +Plugin.TSQLServer: ^pgsql:  TPgSQLServer PgSQL  "<constructor>"   //
0056 //   Plugin.TVirtualFitter: *     TFitter      Minuit "TFitter(Int_t)"  //
0057 //                                                                      //
0058 // Where the + in front of Plugin.TSQLServer says that it extends the   //
0059 // existing definition of TSQLServer, useful when there is more than    //
0060 // one plugin that can extend the same base class. The "<constructor>"  //
0061 // should be the constructor or a static method that generates an       //
0062 // instance of the specified class. Global methods should start with    //
0063 // "::" in their name, like "::CreateFitter()".                         //
0064 // Instead of being a shared library a plugin can also be a CINT        //
0065 // script, so instead of libDialog.so one can have Dialog.C.            //
0066 // The * is a placeholder in case there is no need for a URI to         //
0067 // differentiate between different plugins for the same base class.     //
0068 // For the default plugins see $ROOTSYS/etc/system.rootrc.              //
0069 //                                                                      //
0070 // Plugin handlers can also be registered at run time, e.g.:            //
0071 //                                                                      //
0072 //   gPluginMgr->AddHandler("TSQLServer", "^sqlite:",                   //
0073 //                          "TSQLiteServer", "RSQLite",                 //
0074 //             "TSQLiteServer(const char*,const char*,const char*)");   //
0075 //                                                                      //
0076 // A list of currently defined handlers can be printed using:           //
0077 //                                                                      //
0078 //   gPluginMgr->Print(); // use option="a" to see ctors                //
0079 //                                                                      //
0080 // The use of the plugin library manager removes all textual references //
0081 // to hard-coded class and library names and the resulting dependencies //
0082 // in the base classes. The plugin manager is used to extend a.o.       //
0083 // TFile, TSQLServer, TGrid, etc. functionality.                        //
0084 //                                                                      //
0085 //////////////////////////////////////////////////////////////////////////
0086 
0087 #include "TObject.h"
0088 #include "TString.h"
0089 #include "TMethodCall.h"
0090 #include "TVirtualMutex.h"
0091 #include "TInterpreter.h"
0092 #include "TClass.h"
0093 
0094 class TEnv;
0095 class TList;
0096 class THashTable;
0097 class TFunction;
0098 class TPluginManager;
0099 
0100 #include <atomic>
0101 #include <mutex>
0102 
0103 class TPluginHandler : public TObject {
0104 
0105 friend class TPluginManager;
0106 
0107 private:
0108    using AtomicInt_t = std::atomic<Int_t>;
0109 
0110    TString      fBase;      // base class which will be extended by plugin
0111    TString      fRegexp;    // regular expression which must be matched in URI
0112    TString      fClass;     // class to be loaded from plugin library
0113    TString      fPlugin;    // plugin library which should contain fClass
0114    TString      fCtor;      // ctor used to instantiate object of fClass
0115    TString      fOrigin;    // origin of plugin handler definition
0116    TMethodCall *fCallEnv;   //!ctor method call environment
0117    TFunction   *fMethod;    //!ctor method or global function
0118    std::vector<std::string> fArgTupleTypeInfo; // Cached type_info name for fast comparison
0119    AtomicInt_t  fCanCall;   //!if 1 fCallEnv is ok, -1 fCallEnv is not ok, 0 fCallEnv not setup yet.
0120    Bool_t       fIsMacro;   // plugin is a macro and not a library
0121    Bool_t       fIsGlobal;  // plugin ctor is a global function
0122    std::once_flag fLoadStatusFlag; // plugin is loaded
0123    Int_t fLoadStatus;              // cached plugin load status
0124 
0125    TPluginHandler() :
0126       fBase(), fRegexp(), fClass(), fPlugin(), fCtor(), fOrigin(),
0127       fCallEnv(nullptr), fMethod(nullptr), fCanCall(0), fIsMacro(kTRUE), fIsGlobal(kTRUE) { }
0128    TPluginHandler(const char *base, const char *regexp,
0129                   const char *className, const char *pluginName,
0130                   const char *ctor, const char *origin);
0131    TPluginHandler(const TPluginHandler &) = delete;
0132    TPluginHandler& operator=(const TPluginHandler &) = delete;
0133 
0134    ~TPluginHandler();
0135 
0136    const char *GetBase() const { return fBase; }
0137    const char *GetRegexp() const { return fRegexp; }
0138    const char *GetPlugin() const { return fPlugin; }
0139    const char *GetCtor() const { return fCtor; }
0140    const char *GetOrigin() const { return fOrigin; }
0141 
0142    Bool_t CanHandle(const char *base, const char *uri);
0143    void   SetupCallEnv();
0144 
0145    Bool_t CheckForExecPlugin(Int_t nargs);
0146    void LoadPluginImpl();
0147 
0148    bool CheckNameMatch(int iarg, const std::type_info &ti);
0149 
0150    template <typename T0>
0151    bool CheckExactMatch(int iarg, const T0&)
0152    {
0153       return CheckNameMatch(iarg, typeid(T0));
0154    }
0155 
0156    template <typename T0, typename... T>
0157    bool CheckExactMatch(int iarg, const T0&, const T&... params)
0158    {
0159       if (CheckNameMatch(iarg, typeid(T0)))
0160          return CheckExactMatch(iarg + 1, params...);
0161       else
0162          return false;
0163    }
0164 
0165    template <typename... T>
0166    bool ExactArgMatch(const T&... params)
0167    {
0168       constexpr auto nargs = sizeof...(T);
0169       auto name = typeid(std::tuple<T...>).name();
0170       if (!fArgTupleTypeInfo[nargs - 1].empty())
0171          return name == fArgTupleTypeInfo[nargs - 1];
0172 
0173       R__LOCKGUARD(gInterpreterMutex);
0174       if (!CheckExactMatch<T...>(0, params...))
0175          return false;
0176       fArgTupleTypeInfo[nargs - 1] = name;
0177       return true;
0178    }
0179 
0180    template <typename... T> Longptr_t ExecPluginImpl(const T&... params)
0181    {
0182       constexpr auto nargs = sizeof...(params);
0183       if (!CheckForExecPlugin((Int_t)nargs)) return 0;
0184 
0185       Longptr_t ret;
0186 
0187       // check if types match such that function can be called directly
0188       if (ExactArgMatch<T...>(params...)) {
0189          const void *args[nargs] = {&params...};
0190          // locking is handled within this call, but will only be needed
0191          // on the first call for initialization
0192          fCallEnv->Execute(nullptr, args, nargs, &ret);
0193 
0194          return ret;
0195       }
0196 
0197       // Fallback to slow path with type conversion for arguments.
0198 
0199       // The fCallEnv object is shared, since the PluginHandler is a global
0200       // resource ... and both SetParams and Execute ends up taking the lock
0201       // individually anyway ...
0202 
0203       R__LOCKGUARD(gInterpreterMutex);
0204       fCallEnv->SetParams(params...);
0205 
0206       fCallEnv->Execute(ret);
0207 
0208       return ret;
0209    }
0210 
0211 public:
0212    const char *GetClass() const { return fClass; }
0213    Int_t       CheckPlugin() const;
0214    Int_t       LoadPlugin();
0215 
0216    // zero arguments case
0217    Longptr_t ExecPluginImpl()
0218    {
0219       if (!CheckForExecPlugin(0))
0220          return 0;
0221 
0222       Longptr_t ret;
0223       // locking is handled within this call, but will only be needed
0224       // on the first call for initialization
0225       fCallEnv->Execute(nullptr, nullptr, 0, &ret);
0226 
0227       return ret;
0228    }
0229 
0230    // zero arguments case
0231    Longptr_t ExecPlugin(int nargs)
0232    {
0233       // For backward compatibility.
0234       if ((gDebug > 1) && (nargs != 0)) {
0235          Warning("ExecPlugin", "Announced number of args different from the real number of argument passed %d vs 0",
0236                  nargs);
0237       }
0238 
0239       return ExecPluginImpl();
0240    }
0241 
0242    template <typename... T> Longptr_t ExecPlugin(int nargs, const T&... params)
0243    {
0244       // For backward compatibility.
0245       if ((gDebug > 1) && (nargs != (int)sizeof...(params))) {
0246          Warning("ExecPlugin","Announced number of args different from the real number of argument passed %d vs %lu",
0247                  nargs, (unsigned long)sizeof...(params) );
0248       }
0249       return ExecPluginImpl<T...>(params...);
0250    }
0251 
0252    void        Print(Option_t *opt = "") const override;
0253 
0254    ClassDefOverride(TPluginHandler,3)  // Handler for plugin libraries
0255 };
0256 
0257 
0258 class TPluginManager : public TObject {
0259 
0260 private:
0261    TList      *fHandlers;     // list of plugin handlers
0262    THashTable *fBasesLoaded;  //! table of base classes already checked or loaded
0263    Bool_t      fReadingDirs;  //! true if we are running LoadHandlersFromPluginDirs
0264 
0265    TPluginManager(const TPluginManager &) = delete;
0266    TPluginManager& operator=(const TPluginManager &) = delete;
0267    void   LoadHandlerMacros(const char *path);
0268 
0269 public:
0270    TPluginManager();
0271    ~TPluginManager();
0272 
0273    void   LoadHandlersFromEnv(TEnv *env);
0274    void   LoadHandlersFromPluginDirs(const char *base = nullptr);
0275    void   AddHandler(const char *base, const char *regexp,
0276                      const char *className, const char *pluginName,
0277                      const char *ctor = nullptr, const char *origin = nullptr);
0278    void   RemoveHandler(const char *base, const char *regexp = nullptr);
0279 
0280    TPluginHandler *FindHandler(const char *base, const char *uri = nullptr);
0281 
0282    void   Print(Option_t *opt = "") const override;
0283    Int_t  WritePluginMacros(const char *dir, const char *plugin = nullptr) const;
0284    Int_t  WritePluginRecords(const char *envFile, const char *plugin = nullptr) const;
0285 
0286    ClassDefOverride(TPluginManager,1)  // Manager for plugin handlers
0287 };
0288 
0289 R__EXTERN TPluginManager *gPluginMgr;
0290 
0291 #endif