From 9acf5d7adbcdd5d602aea96b51586be17171e9ec Mon Sep 17 00:00:00 2001
From: Giovanni Bussi <giovanni.bussi@gmail.com>
Date: Fri, 9 Dec 2011 15:59:01 +0100
Subject: [PATCH] DLLoader class

It takes care of dynamic loading, and unload libraries when plumedMain
is destroyed. This allows for a complete memory cleanup at the
end of execution.
---
 src/ActionRegister.cpp | 14 +++++++++
 src/ActionRegister.h   |  3 ++
 src/DLLoader.cpp       | 49 ++++++++++++++++++++++++++++++
 src/DLLoader.h         | 21 +++++++++++++
 src/PlumedMain.cpp     | 67 +++++++++++++++++++-----------------------
 src/PlumedMain.h       |  3 ++
 6 files changed, 120 insertions(+), 37 deletions(-)
 create mode 100644 src/DLLoader.cpp
 create mode 100644 src/DLLoader.h

diff --git a/src/ActionRegister.cpp b/src/ActionRegister.cpp
index 695d46d7f..218064dd4 100644
--- a/src/ActionRegister.cpp
+++ b/src/ActionRegister.cpp
@@ -9,11 +9,25 @@
 using namespace std;
 using namespace PLMD;
 
+ActionRegister::~ActionRegister(){
+  if(m.size()>0)
+    for(mIterator p=m.begin();p!=m.end();++p)
+       std::cerr<<"WARNING: directive "<<p->first<<" has not been properly unregistered\n";
+}
+
 ActionRegister& PLMD::actionRegister(){
   static ActionRegister ans;
   return ans;
 }
 
+void ActionRegister::remove(creator_pointer f){
+  for(mIterator p=m.begin();p!=m.end();++p){
+    if((*p).second==f){
+      m.erase(p); break;
+    }
+  }
+}
+
 void ActionRegister::add(string key,creator_pointer f){
   if(m.count(key)){
     m.erase(key);
diff --git a/src/ActionRegister.h b/src/ActionRegister.h
index b2b83415e..f0b652abf 100644
--- a/src/ActionRegister.h
+++ b/src/ActionRegister.h
@@ -41,6 +41,8 @@ public:
 /// Create an Action of the type indicated in the options
 /// \param ao object containing information for initialization, such as the full input line, a pointer to PlumedMain, etc
   Action* create(const ActionOptions&ao);
+  void remove(creator_pointer);
+  ~ActionRegister();
 };
 
 /// Function returning a reference to the ActionRegister.
@@ -66,6 +68,7 @@ std::ostream & operator<<(std::ostream &log,const ActionRegister&ar);
     static PLMD::Action* create(const PLMD::ActionOptions&ao){return new classname(ao);} \
   public: \
     classname##RegisterMe(){PLMD::actionRegister().add(directive,create);}; \
+    ~classname##RegisterMe(){PLMD::actionRegister().remove(create);}; \
   } classname##RegisterMeObject;
 
 
diff --git a/src/DLLoader.cpp b/src/DLLoader.cpp
new file mode 100644
index 000000000..05d8db60c
--- /dev/null
+++ b/src/DLLoader.cpp
@@ -0,0 +1,49 @@
+#include "DLLoader.h"
+#ifdef __PLUMED_HAS_DLOPEN
+#include <dlfcn.h>
+#endif
+
+#include <iostream>
+
+using namespace PLMD;
+
+bool DLLoader::installed(){
+#ifdef __PLUMED_HAS_DLOPEN
+  return true;
+#else
+  return false;
+#endif
+}
+
+
+void* DLLoader::load(const std::string&s){
+#ifdef __PLUMED_HAS_DLOPEN
+  void* p=dlopen(s.c_str(),RTLD_NOW|RTLD_LOCAL);
+  if(!p){
+    lastError=dlerror();
+  } else {
+    lastError="";
+    handles.push(p);
+  }
+  return p;
+#else
+  return NULL;
+#endif
+}
+
+const std::string & DLLoader::error(){
+  return lastError;
+}
+
+DLLoader::~DLLoader(){
+#ifdef __PLUMED_HAS_DLOPEN
+  while(!handles.empty()){
+    void* p=handles.top();
+    handles.pop();
+    dlclose(p);
+  }
+#endif
+}
+
+
+
diff --git a/src/DLLoader.h b/src/DLLoader.h
new file mode 100644
index 000000000..bb30d2bea
--- /dev/null
+++ b/src/DLLoader.h
@@ -0,0 +1,21 @@
+#ifndef __PLUMED_DLLoader_h
+#define __PLUMED_DLLoader_h
+
+#include <stack>
+#include <string>
+
+namespace PLMD{
+
+class DLLoader{
+  std::stack<void*> handles;
+  std::string lastError;
+public:
+  ~DLLoader();
+  void* load(const std::string&);
+  const std::string & error();
+  static bool installed();
+};
+
+}
+
+#endif
diff --git a/src/PlumedMain.cpp b/src/PlumedMain.cpp
index 19c71b802..134071a70 100644
--- a/src/PlumedMain.cpp
+++ b/src/PlumedMain.cpp
@@ -1,7 +1,3 @@
-#ifdef __PLUMED_HAS_DLOPEN
-#include <dlfcn.h>
-#endif
-
 #include "PlumedMain.h"
 #include "Tools.h"
 #include <cstring>
@@ -429,39 +425,36 @@ void PlumedMain::justApply(){
 }
 
 void PlumedMain::load(std::vector<std::string> & words){
-#ifdef __PLUMED_HAS_DLOPEN
-    string s=words[1];
-    assert(words.size()==2);
-    size_t n=s.find_last_of(".");
-    string extension="";
-    string base=s;
-    if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1);
-    if(n!=std::string::npos && n<s.length())   base=s.substr(0,n);
-    if(extension=="cpp"){
-      string cmd="plumed mklib "+s;
-      log<<"Executing: "<<cmd;
-      if(comm.Get_size()>0) log<<" (only on master node)";
-      log<<"\n";
-      if(comm.Get_rank()==0) system(cmd.c_str());
-      comm.Barrier();
-      base="./"+base;
-    }
-    s=base+"."+soext;
-    void *p=dlopen(s.c_str(),RTLD_NOW|RTLD_LOCAL);
-    if(!p){
-      log<<"ERROR\n";
-      log<<"I cannot load library "<<words[1].c_str()<<"\n";
-      log<<dlerror();
-      log<<"\n";
-      this->exit(1);
-    }
-    log<<"Loading shared library "<<s.c_str()<<"\n";
-    log<<"Here is the new list of available actions\n";
-    log<<actionRegister();
-#else
-  (void) words;
-  assert(0); // Loading not enabled; please recompile with -D__PLUMED_HAS_DLOPEN
-#endif
+  if(DLLoader::installed()){
+     string s=words[1];
+     assert(words.size()==2);
+     size_t n=s.find_last_of(".");
+     string extension="";
+     string base=s;
+     if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1);
+     if(n!=std::string::npos && n<s.length())   base=s.substr(0,n);
+     if(extension=="cpp"){
+       string cmd="plumed mklib "+s;
+       log<<"Executing: "<<cmd;
+       if(comm.Get_size()>0) log<<" (only on master node)";
+       log<<"\n";
+       if(comm.Get_rank()==0) system(cmd.c_str());
+       comm.Barrier();
+       base="./"+base;
+     }
+     s=base+"."+soext;
+     void *p=dlloader.load(s);
+     if(!p){
+       log<<"ERROR\n";
+       log<<"I cannot load library "<<words[1].c_str()<<"\n";
+       log<<dlloader.error();
+       log<<"\n";
+       this->exit(1);
+     }
+     log<<"Loading shared library "<<s.c_str()<<"\n";
+     log<<"Here is the new list of available actions\n";
+     log<<actionRegister();
+  } else assert(0); // Loading not enabled; please recompile with -D__PLUMED_HAS_DLOPEN
 }
 
 double PlumedMain::getBias() const{
diff --git a/src/PlumedMain.h b/src/PlumedMain.h
index f4e0ca823..d1ddee4df 100644
--- a/src/PlumedMain.h
+++ b/src/PlumedMain.h
@@ -8,6 +8,7 @@
 #include <cstdio>
 #include <string>
 #include <vector>
+#include "DLLoader.h"
 
 
 // !!!!!!!!!!!!!!!!!!!!!!    DANGER   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
@@ -48,6 +49,8 @@ public:
   PlumedCommunicator comm;
 
 private:
+  DLLoader dlloader;
+
   WithCmd* grex;
 /// Flag to avoid double initialization
   bool  initialized;
-- 
GitLab