LCOV - code coverage report
Current view: top level - core - PlumedMainInitializer.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 199 251 79.3 %
Date: 2026-03-30 13:16:06 Functions: 14 16 87.5 %

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

Generated by: LCOV version 1.16