Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2018-2020 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 "PlumedHandle.h" 23 : #include "core/PlumedMain.h" 24 : #include "Tools.h" 25 : #include <cstring> 26 : #ifdef __PLUMED_HAS_DLOPEN 27 : #include <dlfcn.h> 28 : #endif 29 : 30 : namespace PLMD 31 : { 32 : 33 22 : PlumedHandle::DlHandle::~DlHandle() { 34 : #ifdef __PLUMED_HAS_DLOPEN 35 11 : if(handle) dlclose(handle); 36 : #endif 37 11 : } 38 : 39 11 : PlumedHandle::PlumedHandle(): 40 22 : local(new PlumedMain) 41 : { 42 11 : } 43 : 44 0 : PlumedHandle::PlumedHandle(const char* kernel) 45 : #ifdef __PLUMED_HAS_DLOPEN 46 : : 47 0 : handle([&]() { 48 0 : dlerror(); 49 : int mode = RTLD_LOCAL | RTLD_NOW; 50 : #ifdef RTLD_DEEPBIND 51 : // Needed on Linux to avoid namespace clashes 52 : mode |= RTLD_DEEPBIND; 53 : #endif 54 0 : void* h=::dlopen(kernel,mode); 55 : // try to remove the "Kernel" string. 56 : // needed to load old versions 57 0 : if(!h) { 58 0 : std::string k(kernel); 59 : auto i=k.rfind("Kernel"); 60 0 : if(i!=std::string::npos) { 61 0 : k=k.substr(0,i) + k.substr(i+6); 62 0 : h=::dlopen(k.c_str(),mode); 63 : } 64 : } 65 0 : plumed_assert(h) << "there was a problem loading kernel "<<kernel <<"\n"<<dlerror(); 66 0 : return DlHandle(h); 67 : // once the DlHandle has been constructed we know that later exceptions will also call dlclose(). 68 : }()), 69 0 : symbol_((plumed_symbol_table_type*) dlsym(handle,"plumed_symbol_table")), 70 0 : create_([&]() { 71 0 : if(symbol_) { 72 0 : plumed_assert(symbol_->functions.create); 73 : return symbol_->functions.create; 74 : } 75 : void* c=nullptr; 76 0 : if(!c) c=dlsym(handle,"plumedmain_create"); 77 0 : if(!c) c=dlsym(handle,"plumed_plumedmain_create"); 78 0 : plumed_assert(c) << "in kernel "<<kernel<<" I could not find (plumed_)plumedmain_create"; 79 : plumed_create_pointer cc; 80 0 : *(void **)(&cc)=c; 81 0 : return cc; 82 0 : }()), 83 0 : cmd_([&]() { 84 0 : if(symbol_) { 85 0 : plumed_assert(symbol_->functions.cmd); 86 : return symbol_->functions.cmd; 87 : } 88 : void* c=nullptr; 89 0 : if(!c) c=dlsym(handle,"plumedmain_cmd"); 90 0 : if(!c) c=dlsym(handle,"plumed_plumedmain_cmd"); 91 0 : plumed_assert(c) << "in kernel "<<kernel<<" I could not find (plumed_)plumedmain_cmd"; 92 : plumed_cmd_pointer cc; 93 0 : *(void **)(&cc)=c; 94 0 : return cc; 95 0 : }()), 96 0 : finalize_([&]() { 97 0 : if(symbol_) { 98 0 : plumed_assert(symbol_->functions.finalize); 99 : return symbol_->functions.finalize; 100 : } 101 : void* f=nullptr; 102 0 : if(!f) f=dlsym(handle,"plumedmain_finalize"); 103 0 : if(!f) f=dlsym(handle,"plumed_plumedmain_finalize"); 104 0 : plumed_assert(f) << "in kernel "<<kernel<<" I could not find (plumed_)plumedmain_finalize"; 105 : plumed_finalize_pointer ff; 106 0 : *(void **)(&ff)=f; 107 0 : return ff; 108 0 : }()), 109 0 : p(create_()) 110 : // No exceptions thrown past this point. 111 : // Thus, destructor PlumedHandle::~PlumedHandle() will always be called and p will always be finalized. 112 0 : {} 113 : #else 114 : { 115 : plumed_error() << "You are trying to dynamically load a kernel, but PLUMED was compiled without dlopen"; 116 : } 117 : #endif 118 : 119 33 : PlumedHandle::~PlumedHandle() { 120 : #ifdef __PLUMED_HAS_DLOPEN 121 11 : if(p) finalize_(p); 122 : #endif 123 11 : } 124 : 125 0 : PlumedHandle PlumedHandle::dlopen(const char* path) { 126 0 : return PlumedHandle(path); 127 : } 128 : 129 1254 : void PlumedHandle::cmd(const char*key,const void*ptr) { 130 2508 : if(local) local->cmd(key,ptr); 131 0 : else if(p && cmd_) cmd_(p,key,ptr); 132 0 : else plumed_error() << "should never arrive here (either one or the other should work)"; 133 1254 : } 134 : 135 : }