Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2019 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 :
44 :
45 : using namespace std;
46 :
47 : // create should never throw
48 : // in case of a problem, it logs the error and return a null pointer
49 : // when loaded by an interface >=2.5, this will result in a non valid plumed object.
50 : // earlier interfaces will just give a segfault or a failed assertion.
51 2009 : extern "C" void*plumed_plumedmain_create() {
52 : try {
53 2009 : return new PLMD::PlumedMain;
54 0 : } catch(const std::exception & e) {
55 0 : std::cerr<<"+++ an error happened while creating a plumed object\n";
56 0 : std::cerr<<e.what()<<std::endl;
57 : return nullptr;
58 0 : } catch(...) {
59 0 : std::cerr<<"+++ an unknown error happened while creating a plumed object"<<std::endl;
60 : return nullptr;
61 : }
62 : }
63 :
64 380 : extern "C" void plumed_plumedmain_cmd(void*plumed,const char*key,const void*val) {
65 380 : plumed_massert(plumed,"trying to use a plumed object which is not initialized");
66 : auto p=static_cast<PLMD::PlumedMain*>(plumed);
67 760 : p->cmd(key,val);
68 380 : }
69 :
70 7360 : extern "C" void plumed_plumedmain_cmd_nothrow(void*plumed,const char*key,const void*val,plumed_nothrow_handler nothrow) {
71 : // At library boundaries we translate exceptions to error codes.
72 : // This allows an exception to be catched also if the MD code
73 : // was linked against a different C++ library
74 : try {
75 7360 : plumed_massert(plumed,"trying to use a plumed object which is not initialized");
76 14786 : static_cast<PLMD::PlumedMain*>(plumed)->cmd(key,val);;
77 98 : } catch(const PLMD::ExceptionError & e) {
78 49 : nothrow.handler(nothrow.ptr,20200,e.what(),nullptr);
79 2 : } catch(const PLMD::ExceptionDebug & e) {
80 1 : nothrow.handler(nothrow.ptr,20100,e.what(),nullptr);
81 2 : } catch(const PLMD::Exception & e) {
82 1 : nothrow.handler(nothrow.ptr,20000,e.what(),nullptr);
83 2 : } catch(const PLMD::lepton::Exception & e) {
84 1 : nothrow.handler(nothrow.ptr,19900,e.what(),nullptr);
85 : // 11000 to 12000 are "bad exceptions". message will be copied without new allocations
86 2 : } catch(const bad_exception & e) {
87 1 : nothrow.handler(nothrow.ptr,11500,e.what(),nullptr);
88 : #ifdef __PLUMED_LIBCXX11
89 : } catch(const bad_array_new_length & e) {
90 : nothrow.handler(nothrow.ptr,11410,e.what(),nullptr);
91 : #endif
92 2 : } catch(const bad_alloc & e) {
93 1 : nothrow.handler(nothrow.ptr,11400,e.what(),nullptr);
94 : #ifdef __PLUMED_LIBCXX11
95 : } catch(const bad_function_call & e) {
96 : nothrow.handler(nothrow.ptr,11300,e.what(),nullptr);
97 : } catch(const bad_weak_ptr & e) {
98 : nothrow.handler(nothrow.ptr,11200,e.what(),nullptr);
99 : #endif
100 2 : } catch(const bad_cast & e) {
101 1 : nothrow.handler(nothrow.ptr,11100,e.what(),nullptr);
102 2 : } catch(const bad_typeid & e) {
103 1 : nothrow.handler(nothrow.ptr,11000,e.what(),nullptr);
104 : // not implemented yet: std::regex_error
105 : // we do not allow regex yet due to portability problems with gcc 4.8
106 : // as soon as we transition to using <regex> it should be straightforward to add
107 2 : } catch(const std::ios_base::failure & e) {
108 : #ifdef __PLUMED_LIBCXX11
109 : int value=e.code().value();
110 : const void* opt[3]= {"c",&value,nullptr}; // "c" passes the error code. nullptr terminates the optional part.
111 : if(e.code().category()==generic_category()) nothrow.handler(nothrow.ptr,10230,e.what(),opt);
112 : else if(e.code().category()==system_category()) nothrow.handler(nothrow.ptr,10231,e.what(),opt);
113 : else if(e.code().category()==iostream_category()) nothrow.handler(nothrow.ptr,10232,e.what(),opt);
114 : else if(e.code().category()==future_category()) nothrow.handler(nothrow.ptr,10233,e.what(),opt);
115 : else
116 : #endif
117 : // 10239 represents std::ios_base::failure with default constructur
118 1 : nothrow.handler(nothrow.ptr,10239,e.what(),nullptr);
119 : #ifdef __PLUMED_LIBCXX11
120 : } catch(const std::system_error & e) {
121 : int value=e.code().value();
122 : const void* opt[3]= {"c",&value,nullptr}; // "c" passes the error code. nullptr terminates the optional part.
123 : if(e.code().category()==generic_category()) nothrow.handler(nothrow.ptr,10220,e.what(),opt);
124 : else if(e.code().category()==system_category()) nothrow.handler(nothrow.ptr,10221,e.what(),opt);
125 : else if(e.code().category()==iostream_category()) nothrow.handler(nothrow.ptr,10222,e.what(),opt);
126 : else if(e.code().category()==future_category()) nothrow.handler(nothrow.ptr,10223,e.what(),opt);
127 : // fallback to generic runtime_error
128 : else nothrow.handler(nothrow.ptr,10200,e.what(),nullptr);
129 : #endif
130 2 : } catch(const std::underflow_error &e) {
131 1 : nothrow.handler(nothrow.ptr,10215,e.what(),nullptr);
132 2 : } catch(const std::overflow_error &e) {
133 1 : nothrow.handler(nothrow.ptr,10210,e.what(),nullptr);
134 2 : } catch(const std::range_error &e) {
135 1 : nothrow.handler(nothrow.ptr,10205,e.what(),nullptr);
136 2 : } catch(const std::runtime_error & e) {
137 1 : nothrow.handler(nothrow.ptr,10200,e.what(),nullptr);
138 : // not implemented yet: std::future_error
139 : // not clear how useful it would be.
140 2 : } catch(const std::out_of_range & e) {
141 1 : nothrow.handler(nothrow.ptr,10120,e.what(),nullptr);
142 2 : } catch(const std::length_error & e) {
143 1 : nothrow.handler(nothrow.ptr,10115,e.what(),nullptr);
144 2 : } catch(const std::domain_error & e) {
145 1 : nothrow.handler(nothrow.ptr,10110,e.what(),nullptr);
146 2 : } catch(const std::invalid_argument & e) {
147 1 : nothrow.handler(nothrow.ptr,10105,e.what(),nullptr);
148 2 : } catch(const std::logic_error & e) {
149 1 : nothrow.handler(nothrow.ptr,10100,e.what(),nullptr);
150 : // generic exception. message will be copied without new allocations
151 : // reports all non caught exceptions that are derived from std::exception
152 : // for instance, boost exceptions would end up here
153 0 : } catch(const std::exception & e) {
154 0 : nothrow.handler(nothrow.ptr,10000,e.what(),nullptr);
155 0 : } catch(...) {
156 : // if exception cannot be translated, we throw a bad_exception
157 0 : nothrow.handler(nothrow.ptr,11500,"plumed could not translate exception",nullptr);
158 0 : throw;
159 : }
160 7360 : }
161 :
162 2009 : extern "C" void plumed_plumedmain_finalize(void*plumed) {
163 2009 : plumed_massert(plumed,"trying to deallocate a plumed object which is not initialized");
164 : // I think it is not possible to replace this delete with a smart pointer
165 : // since the ownership of this pointer is in a C structure. GB
166 2009 : delete static_cast<PLMD::PlumedMain*>(plumed);
167 2009 : }
168 :
169 : // values here should be consistent with those in plumed_symbol_table_init !!!!
170 : plumed_symbol_table_type plumed_symbol_table= {
171 : 2,
172 : {plumed_plumedmain_create,plumed_plumedmain_cmd,plumed_plumedmain_finalize},
173 : plumed_plumedmain_cmd_nothrow
174 : };
175 :
176 : // values here should be consistent with those above !!!!
177 3958 : extern "C" void plumed_symbol_table_init() {
178 3958 : plumed_symbol_table.version=2;
179 3958 : plumed_symbol_table.functions.create=plumed_plumedmain_create;
180 3958 : plumed_symbol_table.functions.cmd=plumed_plumedmain_cmd;
181 3958 : plumed_symbol_table.functions.finalize=plumed_plumedmain_finalize;
182 3958 : plumed_symbol_table.cmd_nothrow=plumed_plumedmain_cmd_nothrow;
183 3958 : }
184 :
185 : namespace PLMD {
186 :
187 : #define plumed_convert_fptr(ptr,fptr) { ptr=NULL; std::memcpy(&ptr,&fptr,(sizeof(fptr)>sizeof(ptr)?sizeof(ptr):sizeof(fptr))); }
188 :
189 : /// Static object which registers Plumed.
190 : /// This is a static object which, during its construction at startup,
191 : /// registers the pointers to plumed_plumedmain_create, plumed_plumedmain_cmd and plumed_plumedmain_finalize
192 : /// to the plumed_kernel_register function.
193 : /// Registration is only required with plumed loader <=2.4, but we do it anyway in order to maintain
194 : /// backward compatibility. Notice that as of plumed 2.5 the plumed_kernel_register is found
195 : /// using dlsym, in order to allow the libplumedKernel library to be loadable also when
196 : /// the plumed_kernel_register symbol is not available.
197 : static class PlumedMainInitializer {
198 : const bool debug;
199 : public:
200 1958 : PlumedMainInitializer():
201 1958 : debug(std::getenv("PLUMED_LOAD_DEBUG"))
202 : {
203 : // make sure static plumed_function_pointers is initialized here
204 1958 : plumed_symbol_table_init();
205 1958 : if(debug) fprintf(stderr,"+++ Initializing PLUMED with plumed_symbol_table version %i at %p\n",plumed_symbol_table.version,(void*)&plumed_symbol_table);
206 : #if defined(__PLUMED_HAS_DLOPEN)
207 1958 : if(std::getenv("PLUMED_LOAD_SKIP_REGISTRATION")) {
208 0 : if(debug) fprintf(stderr,"+++ Skipping registration +++\n");
209 0 : return;
210 : }
211 : typedef plumed_plumedmain_function_holder* (*plumed_kernel_register_type)(const plumed_plumedmain_function_holder*);
212 : plumed_kernel_register_type plumed_kernel_register=nullptr;
213 : void* handle=nullptr;
214 : #if defined(__PLUMED_HAS_RTLD_DEFAULT)
215 1958 : if(debug) fprintf(stderr,"+++ Registering functions. Looking in RTLD_DEFAULT +++\n");
216 1958 : void* dls=dlsym(RTLD_DEFAULT,"plumed_kernel_register");
217 : #else
218 : handle=dlopen(NULL,RTLD_LOCAL);
219 : if(debug) fprintf(stderr,"+++ Registering functions. dlopen handle at %p +++\n",handle);
220 : void* dls=dlsym(handle,"plumed_kernel_register");
221 : #endif
222 1958 : *(void **)(&plumed_kernel_register)=dls;
223 1958 : if(debug) {
224 0 : if(plumed_kernel_register) {
225 0 : fprintf(stderr,"+++ plumed_kernel_register found at %p +++\n",dls);
226 : }
227 0 : else fprintf(stderr,"+++ plumed_kernel_register not found +++\n");
228 : }
229 : void*createp;
230 : void*cmdp;
231 : void*finalizep;
232 1958 : plumed_convert_fptr(createp,plumed_symbol_table.functions.create);
233 1958 : plumed_convert_fptr(cmdp,plumed_symbol_table.functions.cmd);
234 1958 : plumed_convert_fptr(finalizep,plumed_symbol_table.functions.finalize);
235 1958 : if(plumed_kernel_register && debug) fprintf(stderr,"+++ Registering functions at %p (%p,%p,%p) +++\n",
236 0 : (void*)&plumed_symbol_table.functions,createp,cmdp,finalizep);
237 1958 : if(plumed_kernel_register) (*plumed_kernel_register)(&plumed_symbol_table.functions);
238 : // Notice that handle could be null in the following cases:
239 : // - if we use RTLD_DEFAULT
240 : // - on Linux if we don't use RTLD_DEFAULT, since dlopen(NULL,RTLD_LOCAL) returns a null pointer.
241 : if(handle) dlclose(handle);
242 : #endif
243 : // I think this is a bug in cppcheck 1.87
244 : // Notice that if handle is NULL there's no point in dlclosing it.
245 : // cppcheck-suppress resourceLeak
246 : }
247 1958 : ~PlumedMainInitializer() {
248 1958 : if(debug) fprintf(stderr,"+++ Finalizing PLUMED with plumed_symbol_table at %p\n",(void*)&plumed_symbol_table);
249 1958 : }
250 1958 : } PlumedMainInitializerRegisterMe;
251 :
252 5874 : }
253 :
254 :
|