1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2018-2021 The plumed team
3    (see the PEOPLE file at the root of the distribution for a list of names)
4 
5    See http://www.plumed.org for more information.
6 
7    This file is part of plumed, version 2.
8 
9    plumed is free software: you can redistribute it and/or modify
10    it under the terms of the GNU Lesser General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    plumed is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU Lesser General Public License
20    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #ifndef __PLUMED_tools_PlumedHandle_h
23 #define __PLUMED_tools_PlumedHandle_h
24 #include "core/PlumedMainInitializer.h"
25 #include <memory>
26 
27 namespace PLMD
28 {
29 
30 class PlumedMain;
31 
32 /**
33 Tiny local class to load a PLUMED kernel.
34 
35 Maps command to either a loaded PLUMED kernel or to the present one.
36 It is a simplified version of the interface located at wrapper/Plumed.h.
37 Differences are:
38 - It does not use the `PLUMED_KERNEL` env var. Indeed, it would not make sense to use it,
39   since this class is meant to load different kernels.
40 - It does not implement interoperability with C/FORTRAN interfaces.
41 - It does not implement global versions (e.g. PLMD::Plumed::gcmd).
42 - It does not implement PLMD::Plumed::ginitialized. If it cannot be loaded, it crashes in its constructor.
43   This will make sure that once constructed the object is usable.
44 
45 The mechanism for loading the kernel is anyway very similar to the one in wrapper/Plumed.c.
46 In particular, it can load both kernels from PLUMED <=2.4 and >=2.5, and it
47 tries to load the `libplumed.so` object if the `libplumedKernel.so` object does not load correctly.
48 It can also be created without passing any kernel path. In that case it refers to the current one
49 (the one to which this class belongs).
50 
51 The following syntax creates a handle referring to the current kernel
52 \verbatim
53 PlumedHandle p;
54 // Alternatively:
55 // auto p=PlumedHandle();
56 p.cmd("init");
57 \endverbatim
58 
59 The following syntax instead creates a handle referring to a loaded kernel
60 \verbatim
61 PlumedHandle p(PlumedHandle::dlopen("/path/to/libplumedkernel.so");
62 // Alternatively:
63 // auto p=PlumedHandle::dlopen("/path/to/libplumedkernel.so");
64 p.cmd("init");
65 \endverbatim
66 
67 Notice that if there are problems loading the kernel an exception is thrown.
68 Thus, once constructed the object is guaranteed to be functional.
69 
70 */
71 class PlumedHandle {
72 /// Automatically dlclosing auxiliary class.
73 /// Just used to make sure that handle is dlclosed correctly.
74   class DlHandle {
75     void *handle=nullptr;
76   public:
77 /// Default construct as nullptr
DlHandle()78     DlHandle() {}
79 /// Construct from a void*
DlHandle(void * h)80     explicit DlHandle(void*h): handle(h) {}
81 /// Destructor will call dlclose if necessary
82     ~DlHandle();
83 /// Covertible to void* so that it can be used directly
84     operator void*() const {
85       return handle;
86     }
87   };
88 /// Pointer to PlumedMain.
89 /// Used when using the current kernel in order to avoid unneeded indirections.
90   std::unique_ptr<PlumedMain> local;
91 /// Pointer to dlsym handle used to open the kernel.
92 /// Null when using current kernel.
93   DlHandle handle;
94 /// Pointer to symbol table.
95 /// Used for kernels>=2.5. We store it here since it is needed
96 /// in constructor to initialize create_/cmd_/finalize_.
97 /// Later on we might use the additional version information that it carries.
98   plumed_symbol_table_type* const symbol_=nullptr;
99 /// Pointer to create function.
100 /// Used when kernel is dlopened.
101   const plumed_create_pointer create_=nullptr;
102 /// Pointer to cmd function.
103 /// Used when kernel is dlopened.
104   const plumed_cmd_pointer cmd_=nullptr;
105 /// Pointer to finalize function.
106 /// Used when kernel is dlopened.
107   const plumed_finalize_pointer finalize_=nullptr;
108 /// Pointer to the plumed object.
109 /// Used when kernel is dlopened.
110   void* const p=nullptr;
111 /// Constructor using the path to a kernel.
112 /// I keep it private to avoid confusion wrt the
113 /// similar constructor of PLMD::Plumed that accepts a string (conversion from FORTRAN).
114   explicit PlumedHandle(const char* path);
115 public:
116 /// Default constructor.
117 /// Maps following commands to the current kernel.
118   PlumedHandle();
119 /// Construct a PlumedHandle given the path to a kernel.
120 /// It just uses the private constructor PlumedHandle(const char* path).
121   static PlumedHandle dlopen(const char* path);
122 /// Destructor.
123 /// In case a kernel was dlopened, it dlcloses it.
124 /// I make it virtual for future extensibility, though this is not necessary now.
125   virtual ~PlumedHandle();
126 /// Move constructor.
127   PlumedHandle(PlumedHandle &&) = default;
128 /// Execute cmd.
129   void cmd(const char*key,const void*ptr=nullptr);
130 };
131 
132 }
133 #endif
134