From 27bb5792c99ae4ff7a7b30b52e3877a389d6720f Mon Sep 17 00:00:00 2001
From: Guillaume Pasero <guillaume.pasero@c-s.fr>
Date: Fri, 16 Oct 2015 17:22:59 +0200
Subject: [PATCH] ENH: add callback to unregister deleted applications, and
 method to release unused handles

---
 .../src/otbWrapperApplicationRegistry.cxx     | 86 +++++++++++++++++--
 1 file changed, 77 insertions(+), 9 deletions(-)

diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
index f98f9a3cbc..738f758942 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
@@ -37,6 +37,58 @@ public:
   typedef std::pair<Application*, void* > AppHandlePairType;
   typedef std::list<AppHandlePairType>    AppHandleContainerType;
 
+  /** Add a pair (application, library handle) in the private registry */
+  bool AddPair(Application *app, void *handle)
+    {
+    AppHandlePairType pair;
+    if (app && handle)
+      {
+      // mutex lock to ensure thread safety
+      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+      pair.first = app;
+      pair.second = handle;
+      m_Container.push_back(pair);
+      return true;
+      }
+    return false;
+    }
+
+  /** When an application is deleted, unregister its pointer from private registry */
+  void UnregisterApp(const Application *app)
+    {
+    if (app)
+      {
+      // mutex lock to ensure thread safety
+      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+      AppHandleContainerType::iterator it = m_Container.begin();
+      while (it != m_Container.end())
+        {
+        if ((*it).first == app)
+          {
+          (*it).first = NULL;
+          }
+        ++it;
+        }
+      }
+    }
+
+  /** Release the library handles from applications already deleted */
+  void ReleaseUnusedHandle()
+    {
+    itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+    AppHandleContainerType::iterator it;
+    for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
+      {
+      if ((*it).first == NULL)
+        {
+        itk::DynamicLoader::CloseLibrary( (*it).second);
+        (*it).second = NULL;
+        }
+      }
+    m_Container.remove(AppHandlePairType(NULL,NULL));
+    }
+
+  /** close all handles at program exit */
   ~ApplicationPrivateRegistry()
   {
   AppHandleContainerType::iterator it;
@@ -47,11 +99,25 @@ public:
   m_Container.clear();
   }
 
+private:
   AppHandleContainerType m_Container;
+
+  itk::SimpleMutexLock m_Mutex;
 };
 // static finalizer to close opened libraries
 static ApplicationPrivateRegistry m_ApplicationPrivateRegistryGlobal;
 
+// Define callbacks to unregister applications in ApplicationPrivateRegistry
+void DeleteAppCallback(itk::Object *obj,const itk::EventObject &, void *)
+  {
+  Application *appPtr = dynamic_cast<Application*>(obj);
+  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
+  }
+void DeleteAppConstCallback(const itk::Object *obj,const itk::EventObject &, void *)
+  {
+  const Application *appPtr = dynamic_cast<const Application*>(obj);
+  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
+  }
 
 ApplicationRegistry::ApplicationRegistry()
 {
@@ -69,6 +135,8 @@ ApplicationRegistry::SetApplicationPath(std::string newpath)
 
   // do NOT use putenv() directly, since the string memory must be managed carefully
   itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
+
+  // TODO  : releaseUnusedHandle() ?
 }
 
 void
@@ -186,6 +254,8 @@ ApplicationRegistry::CreateApplicationFaster(const std::string& name)
 std::vector<std::string>
 ApplicationRegistry::GetAvailableApplications(bool useFactory)
 {
+  // TODO  : releaseUnusedHandle() ?
+
   ApplicationPointer appli;
   std::set<std::string> appSet;
 
@@ -279,8 +349,6 @@ ApplicationRegistry::LoadApplicationFromPath(std::string path,std::string name)
 {
   Application::Pointer appli;
 
-  static itk::SimpleMutexLock mutex;
-
   if (itksys::SystemTools::FileExists(path.c_str(),true))
     {
     itk::LibHandle lib = itk::DynamicLoader::OpenLibrary(path.c_str());
@@ -307,13 +375,13 @@ ApplicationRegistry::LoadApplicationFromPath(std::string path,std::string name)
           if (appli.IsNotNull())
             {
             appli->Init();
-            // mutex lock to ensure thread safety
-            itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(mutex);
-
-            ApplicationPrivateRegistry::AppHandlePairType curPair;
-            curPair.first = appli.GetPointer();
-            curPair.second = (void*) lib;
-            m_ApplicationPrivateRegistryGlobal.m_Container.push_back(curPair);
+            // register library handle
+            m_ApplicationPrivateRegistryGlobal.AddPair(appli.GetPointer(), (void*) lib);
+            // set a callback on DeleteEvent
+            itk::CStyleCommand::Pointer command = itk::CStyleCommand::New();
+            command->SetCallback(&DeleteAppCallback);
+            command->SetConstCallback(&DeleteAppConstCallback);
+            appli->AddObserver(itk::DeleteEvent(),command);
             return appli;
             }
           }
-- 
GitLab