Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2023 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 : #include "PlumedMainInitializer.h"
23 : #include "PlumedMain.h"
24 : #include "tools/Exception.h"
25 : #include "lepton/Exception.h"
26 : #include <cstdlib>
27 : #include <cstring>
28 : #include <iostream>
29 : #if defined __PLUMED_HAS_DLOPEN
30 : #include <dlfcn.h>
31 : #endif
32 : #include <exception>
33 : #include <stdexcept>
34 : #include <ios>
35 : #include <new>
36 : #include <typeinfo>
37 : #include <system_error>
38 : #include <future>
39 : #include <memory>
40 : #include <functional>
41 : #include <regex>
42 : #include <any>
43 : #include <variant>
44 : #include <optional>
45 : #include <filesystem>
46 : #include "tools/TypesafePtr.h"
47 : #include "tools/Log.h"
48 : #include "tools/Tools.h"
49 :
50 :
51 20137 : static bool getenvTypesafeDebug() noexcept {
52 20137 : static const auto* res=std::getenv("PLUMED_TYPESAFE_DEBUG");
53 20137 : return res;
54 : }
55 :
56 : // cppcheck-suppress passedByValue
57 0 : static void typesafeDebug(const char*key,plumed_safeptr_x safe) noexcept {
58 0 : std::fprintf(stderr,"+++ PLUMED_TYPESAFE_DEBUG %s %p %zu",key,safe.ptr,safe.nelem);
59 0 : const size_t* shape=safe.shape;
60 0 : if(shape) {
61 0 : std::fprintf(stderr," (");
62 0 : while(*shape!=0) {
63 0 : std::fprintf(stderr," %zu",*shape);
64 0 : shape++;
65 : }
66 0 : std::fprintf(stderr," )");
67 : }
68 0 : std::fprintf(stderr," %zx %p\n",safe.flags,safe.opt);
69 0 : }
70 :
71 : // create should never throw
72 : // in case of a problem, it logs the error and return a null pointer
73 : // when loaded by an interface >=2.5, this will result in a non valid plumed object.
74 : // earlier interfaces will just give a segfault or a failed assertion.
75 805619 : extern "C" void*plumed_plumedmain_create() {
76 : try {
77 805619 : return new PLMD::PlumedMain;
78 0 : } catch(const std::exception & e) {
79 0 : std::cerr<<"+++ an error happened while creating a plumed object\n";
80 0 : std::cerr<<e.what()<<std::endl;
81 : return nullptr;
82 0 : } catch(...) {
83 0 : std::cerr<<"+++ an unknown error happened while creating a plumed object"<<std::endl;
84 : return nullptr;
85 0 : }
86 : }
87 :
88 8000671 : extern "C" unsigned plumed_plumedmain_create_reference(void*plumed) {
89 8000671 : plumed_massert(plumed,"trying to create a reference to a plumed object which is not initialized");
90 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
91 8000671 : return p->increaseReferenceCounter();
92 : }
93 :
94 8806290 : extern "C" unsigned plumed_plumedmain_delete_reference(void*plumed) {
95 8806290 : plumed_massert(plumed,"trying to delete a reference to a plumed object which is not initialized");
96 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
97 8806290 : return p->decreaseReferenceCounter();
98 : }
99 :
100 42 : extern "C" unsigned plumed_plumedmain_use_count(void*plumed) {
101 42 : plumed_massert(plumed,"trying to delete a reference to a plumed object which is not initialized");
102 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
103 42 : return p->useCountReferenceCounter();
104 : }
105 :
106 357 : extern "C" void plumed_plumedmain_cmd(void*plumed,const char*key,const void*val) {
107 357 : plumed_massert(plumed,"trying to use a plumed object which is not initialized");
108 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
109 357 : p->cmd(key,PLMD::TypesafePtr::unchecked(val));
110 357 : }
111 :
112 : extern "C" {
113 95 : static void plumed_plumedmain_cmd_safe(void*plumed,const char*key,plumed_safeptr_x safe) {
114 95 : plumed_massert(plumed,"trying to use a plumed object which is not initialized");
115 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
116 95 : if(getenvTypesafeDebug()) typesafeDebug(key,safe);
117 95 : p->cmd(key,PLMD::TypesafePtr::fromSafePtr(&safe));
118 95 : }
119 : }
120 :
121 : /// Internal tool
122 : /// Throws the currently managed exception and call the nothrow handler.
123 : /// If nested is not null, it is passed and then gets populated with a pointer that should
124 : /// be called on the nested exception
125 : /// If msg is not null, it overrides the message. Can be used to build a concatenated message.
126 178 : static void translate_current(plumed_nothrow_handler_x nothrow,void**nested=nullptr,const char*msg=nullptr) {
127 178 : const void* opt[11]= {"n",nested,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr};
128 : try {
129 : // this function needs to be called while catching an exception
130 : // cppcheck-suppress rethrowNoCurrentException
131 178 : throw;
132 178 : } catch(const PLMD::ExceptionTypeError & e) {
133 52 : if(!msg) msg=e.what();
134 52 : nothrow.handler(nothrow.ptr,20300,msg,opt);
135 105 : } catch(const PLMD::ExceptionError & e) {
136 53 : if(!msg) msg=e.what();
137 53 : nothrow.handler(nothrow.ptr,20200,msg,opt);
138 54 : } catch(const PLMD::ExceptionDebug & e) {
139 1 : if(!msg) msg=e.what();
140 1 : nothrow.handler(nothrow.ptr,20100,msg,opt);
141 24 : } catch(const PLMD::Exception & e) {
142 23 : if(!msg) msg=e.what();
143 23 : nothrow.handler(nothrow.ptr,20000,msg,opt);
144 24 : } catch(const PLMD::lepton::Exception & e) {
145 1 : if(!msg) msg=e.what();
146 1 : nothrow.handler(nothrow.ptr,19900,msg,opt);
147 : // 11000 to 12000 are "bad exceptions". message will be copied without new allocations
148 2 : } catch(const std::bad_variant_access & e) {
149 1 : if(!msg) msg=e.what();
150 1 : nothrow.handler(nothrow.ptr,11700,msg,opt);
151 2 : } catch(const std::bad_optional_access & e) {
152 1 : if(!msg) msg=e.what();
153 1 : nothrow.handler(nothrow.ptr,11600,msg,opt);
154 2 : } catch(const std::bad_exception & e) {
155 1 : if(!msg) msg=e.what();
156 1 : nothrow.handler(nothrow.ptr,11500,msg,opt);
157 2 : } catch(const std::bad_array_new_length & e) {
158 1 : if(!msg) msg=e.what();
159 1 : nothrow.handler(nothrow.ptr,11410,msg,opt);
160 4 : } catch(const std::bad_alloc & e) {
161 3 : if(!msg) msg=e.what();
162 3 : nothrow.handler(nothrow.ptr,11400,msg,opt);
163 4 : } catch(const std::bad_function_call & e) {
164 1 : if(!msg) msg=e.what();
165 1 : nothrow.handler(nothrow.ptr,11300,msg,opt);
166 2 : } catch(const std::bad_weak_ptr & e) {
167 1 : if(!msg) msg=e.what();
168 1 : nothrow.handler(nothrow.ptr,11200,msg,opt);
169 2 : } catch(const std::bad_any_cast & e) {
170 1 : if(!msg) msg=e.what();
171 1 : nothrow.handler(nothrow.ptr,11150,msg,opt);
172 2 : } catch(const std::bad_cast & e) {
173 1 : if(!msg) msg=e.what();
174 1 : nothrow.handler(nothrow.ptr,11100,msg,opt);
175 2 : } catch(const std::bad_typeid & e) {
176 1 : if(!msg) msg=e.what();
177 1 : nothrow.handler(nothrow.ptr,11000,msg,opt);
178 14 : } catch(const std::regex_error & e) {
179 13 : if(!msg) msg=e.what();
180 13 : if(e.code()==std::regex_constants::error_collate) nothrow.handler(nothrow.ptr,10240,msg,opt);
181 1 : else if(e.code()==std::regex_constants::error_ctype) nothrow.handler(nothrow.ptr,10241,msg,opt);
182 1 : else if(e.code()==std::regex_constants::error_escape) nothrow.handler(nothrow.ptr,10242,msg,opt);
183 1 : else if(e.code()==std::regex_constants::error_backref) nothrow.handler(nothrow.ptr,10243,msg,opt);
184 1 : else if(e.code()==std::regex_constants::error_brack) nothrow.handler(nothrow.ptr,10244,msg,opt);
185 1 : else if(e.code()==std::regex_constants::error_paren) nothrow.handler(nothrow.ptr,10245,msg,opt);
186 1 : else if(e.code()==std::regex_constants::error_brace) nothrow.handler(nothrow.ptr,10246,msg,opt);
187 1 : else if(e.code()==std::regex_constants::error_badbrace) nothrow.handler(nothrow.ptr,10247,msg,opt);
188 1 : else if(e.code()==std::regex_constants::error_range) nothrow.handler(nothrow.ptr,10248,msg,opt);
189 1 : else if(e.code()==std::regex_constants::error_space) nothrow.handler(nothrow.ptr,10249,msg,opt);
190 1 : else if(e.code()==std::regex_constants::error_badrepeat) nothrow.handler(nothrow.ptr,10250,msg,opt);
191 1 : else if(e.code()==std::regex_constants::error_complexity) nothrow.handler(nothrow.ptr,10251,msg,opt);
192 1 : else if(e.code()==std::regex_constants::error_stack) nothrow.handler(nothrow.ptr,10252,msg,opt);
193 : // fallback to generic runtime_error
194 0 : else nothrow.handler(nothrow.ptr,10200,msg,opt);
195 16 : } catch(const std::filesystem::filesystem_error & e) {
196 3 : if(!msg) msg=e.what();
197 3 : int value=e.code().value();
198 :
199 3 : opt[2]="c"; // "c" passes the error code.
200 3 : opt[3]=&value;
201 :
202 3 : opt[4]="C"; // "C" passes the error category
203 3 : int generic_category=1;
204 3 : int system_category=2;
205 3 : int iostream_category=3;
206 3 : int future_category=4;
207 3 : if(e.code().category()==std::generic_category()) opt[5]=&generic_category;
208 0 : else if(e.code().category()==std::system_category()) opt[5]=&system_category;
209 0 : else if(e.code().category()==std::iostream_category()) opt[5]=&iostream_category;
210 0 : else if(e.code().category()==std::future_category()) opt[5]=&future_category;
211 0 : else opt[5]=nullptr;
212 :
213 : // local class, just needed to propely pass path information
214 : // path is stored as a span of bytes.
215 : // in theory, could be wchar type (on Windows, not tested),
216 : // so we explicitly store the number of bytes
217 : struct Path {
218 : std::size_t numbytes=0;
219 : const void* ptr=nullptr;
220 : Path(const std::filesystem::path & path):
221 : numbytes(sizeof(std::filesystem::path::value_type)*path.native().length()),
222 : ptr(path.c_str())
223 : {}
224 : Path() = default;
225 : };
226 :
227 3 : opt[6]="p"; // path1
228 3 : Path path1; // declared here since it should survive till the end of this function
229 3 : if(!e.path1().empty()) {
230 2 : path1=Path(e.path1());
231 2 : opt[7]=&path1;
232 : }
233 :
234 3 : opt[8]="q"; // path2
235 3 : Path path2; // declared here since it should survive till the end of this function
236 3 : if(!e.path2().empty()) {
237 1 : path2=Path(e.path2());
238 1 : opt[9]=&path2;
239 : }
240 :
241 3 : nothrow.handler(nothrow.ptr,10229,msg,opt);
242 4 : } catch(const std::ios_base::failure & e) {
243 1 : if(!msg) msg=e.what();
244 1 : int value=e.code().value();
245 1 : opt[2]="c"; // "c" passes the error code.
246 1 : opt[3]=&value;
247 1 : if(e.code().category()==std::generic_category()) nothrow.handler(nothrow.ptr,10230,msg,opt);
248 1 : else if(e.code().category()==std::system_category()) nothrow.handler(nothrow.ptr,10231,msg,opt);
249 1 : else if(e.code().category()==std::iostream_category()) nothrow.handler(nothrow.ptr,10232,msg,opt);
250 0 : else if(e.code().category()==std::future_category()) nothrow.handler(nothrow.ptr,10233,msg,opt);
251 : else
252 : // 10239 represents std::ios_base::failure with default constructur
253 0 : nothrow.handler(nothrow.ptr,10239,msg,opt);
254 5 : } catch(const std::system_error & e) {
255 4 : if(!msg) msg=e.what();
256 4 : int value=e.code().value();
257 4 : opt[2]="c"; // "c" passes the error code.
258 4 : opt[3]=&value;
259 4 : if(e.code().category()==std::generic_category()) nothrow.handler(nothrow.ptr,10220,msg,opt);
260 3 : else if(e.code().category()==std::system_category()) nothrow.handler(nothrow.ptr,10221,msg,opt);
261 2 : else if(e.code().category()==std::iostream_category()) nothrow.handler(nothrow.ptr,10222,msg,opt);
262 1 : else if(e.code().category()==std::future_category()) nothrow.handler(nothrow.ptr,10223,msg,opt);
263 : // fallback to generic runtime_error
264 0 : else nothrow.handler(nothrow.ptr,10200,msg,opt);
265 5 : } catch(const std::underflow_error &e) {
266 1 : if(!msg) msg=e.what();
267 1 : nothrow.handler(nothrow.ptr,10215,msg,opt);
268 2 : } catch(const std::overflow_error &e) {
269 1 : if(!msg) msg=e.what();
270 1 : nothrow.handler(nothrow.ptr,10210,msg,opt);
271 2 : } catch(const std::range_error &e) {
272 1 : if(!msg) msg=e.what();
273 1 : nothrow.handler(nothrow.ptr,10205,msg,opt);
274 2 : } catch(const std::runtime_error & e) {
275 1 : if(!msg) msg=e.what();
276 1 : nothrow.handler(nothrow.ptr,10200,msg,opt);
277 5 : } catch(const std::future_error & e) {
278 4 : if(!msg) msg=e.what();
279 1 : if(e.code()==std::make_error_code(std::future_errc::broken_promise)) nothrow.handler(nothrow.ptr,10125,msg,opt);
280 1 : else if(e.code()==std::make_error_code(std::future_errc::future_already_retrieved)) nothrow.handler(nothrow.ptr,10126,msg,opt);
281 1 : else if(e.code()==std::make_error_code(std::future_errc::promise_already_satisfied)) nothrow.handler(nothrow.ptr,10127,msg,opt);
282 1 : else if(e.code()==std::make_error_code(std::future_errc::no_state)) nothrow.handler(nothrow.ptr,10128,msg,opt);
283 : // fallback to generic logic_error
284 0 : else nothrow.handler(nothrow.ptr,10100,msg,opt);
285 5 : } catch(const std::out_of_range & e) {
286 1 : if(!msg) msg=e.what();
287 1 : nothrow.handler(nothrow.ptr,10120,msg,opt);
288 2 : } catch(const std::length_error & e) {
289 1 : if(!msg) msg=e.what();
290 1 : nothrow.handler(nothrow.ptr,10115,msg,opt);
291 2 : } catch(const std::domain_error & e) {
292 1 : if(!msg) msg=e.what();
293 1 : nothrow.handler(nothrow.ptr,10110,msg,opt);
294 2 : } catch(const std::invalid_argument & e) {
295 1 : if(!msg) msg=e.what();
296 1 : nothrow.handler(nothrow.ptr,10105,msg,opt);
297 2 : } catch(const std::logic_error & e) {
298 1 : if(!msg) msg=e.what();
299 1 : nothrow.handler(nothrow.ptr,10100,msg,opt);
300 : // generic exception. message will be copied without new allocations
301 : // reports all non caught exceptions that are derived from std::exception
302 : // for instance, boost exceptions would end up here
303 1 : } catch(const std::exception & e) {
304 0 : if(!msg) msg=e.what();
305 0 : nothrow.handler(nothrow.ptr,10000,msg,opt);
306 1 : } catch(const char* m) {
307 1 : if(!msg) msg=m;
308 1 : nothrow.handler(nothrow.ptr,10000,msg,opt);
309 1 : } catch(const std::string & s) {
310 0 : if(!msg) msg=s.c_str();
311 0 : nothrow.handler(nothrow.ptr,10000,msg,opt);
312 1 : } catch (...) {
313 : // if exception cannot be translated, we add a bad_exception to the stack
314 1 : nothrow.handler(nothrow.ptr,11500,"plumed could not translate exception",opt);
315 1 : }
316 178 : }
317 :
318 68 : static void translate_nested(plumed_nothrow_handler_x nothrow) {
319 : try {
320 68 : throw;
321 68 : } catch (const std::nested_exception & e) {
322 : // If this exception has a nested one:
323 12 : auto nothrow_nested=nothrow;
324 12 : nothrow_nested.ptr=nullptr;
325 : // translate the current exception asking the wrapper to allocate a new exception
326 12 : translate_current(nothrow,¬hrow_nested.ptr);
327 : // if the wrapper cannot allocate the exception, this will be a nullptr
328 12 : if(nothrow_nested.ptr) {
329 : try {
330 : // transfer control to the nested exception
331 12 : e.rethrow_nested();
332 12 : } catch (...) {
333 : // recursively translate it
334 12 : translate_nested(nothrow_nested);
335 12 : }
336 : }
337 68 : } catch (...) {
338 : // otherwise, just translate the current exception
339 56 : translate_current(nothrow);
340 56 : }
341 68 : }
342 :
343 : extern "C" {
344 20042 : static void plumed_plumedmain_cmd_safe_nothrow(void*plumed,const char*key,plumed_safeptr_x safe,plumed_nothrow_handler_x nothrow) {
345 : // This is a workaround for a suboptimal choice in PLUMED <2.8
346 : // In particular, the only way to bypass the exception handling process was to call the plumed_plumedmain_cmd_safe
347 : // function directly.
348 : // With this modification, it is possible to just call the plumed_plumedmain_cmd_safe_nothrow function
349 : // passing a null error handler.
350 20042 : if(!nothrow.handler) {
351 0 : plumed_plumedmain_cmd_safe(plumed,key,safe);
352 0 : return;
353 : }
354 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
355 : // At library boundaries we translate exceptions to error codes.
356 : // This allows an exception to be catched also if the MD code
357 : // was linked against a different C++ library
358 : try {
359 20042 : plumed_massert(plumed,"trying to use a plumed object which is not initialized");
360 20042 : if(getenvTypesafeDebug()) typesafeDebug(key,safe);
361 20042 : p->cmd(key,PLMD::TypesafePtr::fromSafePtr(&safe));
362 166 : } catch(...) {
363 166 : if(p->getNestedExceptions()) {
364 56 : translate_nested(nothrow);
365 : } else {
366 : // In this case, we just consider the latest thrown exception and
367 : // supplement it with a concatenated message so as not to
368 : // loose information.
369 110 : auto msg=PLMD::Tools::concatenateExceptionMessages();
370 110 : translate_current(nothrow,nullptr,msg.c_str());
371 : }
372 166 : }
373 : }
374 : }
375 :
376 : extern "C" {
377 0 : static void plumed_plumedmain_cmd_nothrow(void*plumed,const char*key,const void*val,plumed_nothrow_handler_x nothrow) {
378 : plumed_safeptr_x safe;
379 0 : plumed_assert(nothrow.handler) << "Accepting a null pointer here would make the calling code non compatible with plumed 2.5 to 2.7";
380 0 : safe.ptr=val;
381 0 : safe.nelem=0;
382 0 : safe.shape=NULL;
383 0 : safe.flags=0;
384 0 : safe.opt=NULL;
385 0 : plumed_plumedmain_cmd_safe_nothrow(plumed,key,safe,nothrow);
386 0 : }
387 : }
388 :
389 805619 : extern "C" void plumed_plumedmain_finalize(void*plumed) {
390 805619 : plumed_massert(plumed,"trying to deallocate a plumed object which is not initialized");
391 : // I think it is not possible to replace this delete with a smart pointer
392 : // since the ownership of this pointer is in a C structure. GB
393 805619 : delete static_cast<PLMD::PlumedMain*>(plumed);
394 805619 : }
395 :
396 : // values here should be consistent with those in plumed_symbol_table_init !!!!
397 : plumed_symbol_table_type_x plumed_symbol_table= {
398 : 4,
399 : {plumed_plumedmain_create,plumed_plumedmain_cmd,plumed_plumedmain_finalize},
400 : plumed_plumedmain_cmd_nothrow,
401 : plumed_plumedmain_cmd_safe,
402 : plumed_plumedmain_cmd_safe_nothrow,
403 : plumed_plumedmain_create_reference,
404 : plumed_plumedmain_delete_reference,
405 : plumed_plumedmain_use_count
406 : };
407 :
408 : // values here should be consistent with those above !!!!
409 810904 : extern "C" void plumed_symbol_table_init() {
410 810904 : plumed_symbol_table.version=4;
411 810904 : plumed_symbol_table.functions.create=plumed_plumedmain_create;
412 810904 : plumed_symbol_table.functions.cmd=plumed_plumedmain_cmd;
413 810904 : plumed_symbol_table.functions.finalize=plumed_plumedmain_finalize;
414 810904 : plumed_symbol_table.cmd_nothrow=plumed_plumedmain_cmd_nothrow;
415 810904 : plumed_symbol_table.cmd_safe=plumed_plumedmain_cmd_safe;
416 810904 : plumed_symbol_table.cmd_safe_nothrow=plumed_plumedmain_cmd_safe_nothrow;
417 810904 : plumed_symbol_table.create_reference=plumed_plumedmain_create_reference;
418 810904 : plumed_symbol_table.delete_reference=plumed_plumedmain_delete_reference;
419 810904 : plumed_symbol_table.use_count=plumed_plumedmain_use_count;
420 810904 : }
421 :
422 : namespace PLMD {
423 :
424 : #define plumed_convert_fptr(ptr,fptr) { ptr=NULL; std::memcpy(&ptr,&fptr,(sizeof(fptr)>sizeof(ptr)?sizeof(ptr):sizeof(fptr))); }
425 :
426 : /// Static object which registers Plumed.
427 : /// This is a static object which, during its construction at startup,
428 : /// registers the pointers to plumed_plumedmain_create, plumed_plumedmain_cmd and plumed_plumedmain_finalize
429 : /// to the plumed_kernel_register function.
430 : /// Registration is only required with plumed loader <=2.4, but we do it anyway in order to maintain
431 : /// backward compatibility. Notice that as of plumed 2.5 the plumed_kernel_register is found
432 : /// using dlsym, in order to allow the libplumedKernel library to be loadable also when
433 : /// the plumed_kernel_register symbol is not available.
434 : namespace {
435 : class PlumedMainInitializer {
436 : const bool debug;
437 : public:
438 5316 : PlumedMainInitializer():
439 5316 : debug(std::getenv("PLUMED_LOAD_DEBUG"))
440 : {
441 : // make sure static plumed_function_pointers is initialized here
442 5316 : plumed_symbol_table_init();
443 5316 : if(debug) std::fprintf(stderr,"+++ Initializing PLUMED with plumed_symbol_table version %i at %p\n",plumed_symbol_table.version,(void*)&plumed_symbol_table);
444 : #if defined(__PLUMED_HAS_DLOPEN)
445 5316 : if(std::getenv("PLUMED_LOAD_SKIP_REGISTRATION")) {
446 0 : if(debug) std::fprintf(stderr,"+++ Skipping registration +++\n");
447 0 : return;
448 : }
449 : typedef plumed_plumedmain_function_holder_x* (*plumed_kernel_register_type_x)(const plumed_plumedmain_function_holder_x*);
450 : plumed_kernel_register_type_x plumed_kernel_register=nullptr;
451 : void* handle=nullptr;
452 : #if defined(__PLUMED_HAS_RTLD_DEFAULT)
453 5316 : if(debug) std::fprintf(stderr,"+++ Registering functions. Looking in RTLD_DEFAULT +++\n");
454 5316 : void* dls=dlsym(RTLD_DEFAULT,"plumed_kernel_register");
455 : #else
456 : handle=dlopen(NULL,RTLD_LOCAL);
457 : if(debug) std::fprintf(stderr,"+++ Registering functions. dlopen handle at %p +++\n",handle);
458 : void* dls=dlsym(handle,"plumed_kernel_register");
459 : #endif
460 5316 : *(void **)(&plumed_kernel_register)=dls;
461 5316 : if(debug) {
462 0 : if(plumed_kernel_register) {
463 0 : std::fprintf(stderr,"+++ plumed_kernel_register found at %p +++\n",dls);
464 : }
465 0 : else std::fprintf(stderr,"+++ plumed_kernel_register not found +++\n");
466 : }
467 : void*createp;
468 : void*cmdp;
469 : void*finalizep;
470 : plumed_convert_fptr(createp,plumed_symbol_table.functions.create);
471 : plumed_convert_fptr(cmdp,plumed_symbol_table.functions.cmd);
472 : plumed_convert_fptr(finalizep,plumed_symbol_table.functions.finalize);
473 5316 : if(plumed_kernel_register && debug) std::fprintf(stderr,"+++ Registering functions at %p (%p,%p,%p) +++\n",
474 : (void*)&plumed_symbol_table.functions,createp,cmdp,finalizep);
475 5316 : if(plumed_kernel_register) (*plumed_kernel_register)(&plumed_symbol_table.functions);
476 : // Notice that handle could be null in the following cases:
477 : // - if we use RTLD_DEFAULT
478 : // - on Linux if we don't use RTLD_DEFAULT, since dlopen(NULL,RTLD_LOCAL) returns a null pointer.
479 : if(handle) dlclose(handle);
480 : #endif
481 : }
482 5316 : ~PlumedMainInitializer() {
483 5316 : if(debug) std::fprintf(stderr,"+++ Finalizing PLUMED with plumed_symbol_table at %p\n",(void*)&plumed_symbol_table);
484 5316 : }
485 : } PlumedMainInitializerRegisterMe;
486 : }
487 :
488 : }
489 :
490 :
|