From 9f66f9def9c67854e585cbb19b1db0eae17b6dbc Mon Sep 17 00:00:00 2001 From: Andrew Pogrebennyk Date: Tue, 10 Jun 2014 12:20:14 +0200 Subject: [PATCH] MT#7347 added reference counting to plug-in interfaces. Fixes crash on restart. Included upstream commits: commit b9cda79c435fc002c259b5430e61c45d8e94aa2c Author: Raphael Coeffic Date: Sun Apr 28 14:27:27 2013 +0200 sip: add reference counting to transport sockets allows for dynamic socket creation/deletion. commit 73490566761bb0fb09a6ebd74566d7f2b789c62f Author: Raphael Coeffic Date: Tue Nov 20 15:33:35 2012 +0100 c/f: correcting some strange scope issues encountered with GCC & clang on osx. commit 0b2c8068a980058ff34655bc4928aeaedbe527d7 Author: Stefan Sayer Date: Thu Jan 5 22:10:52 2012 +0100 b/f: don't delete registered app objects, e.g. DSM apps fixes bug #68 https://bugtracker.iptel.org/view.php?id=68 --- apps/db_reg_agent/DBRegAgent.h | 5 +++++ apps/ivr/Ivr.cpp | 6 ++++-- core/AmApi.h | 8 ++------ core/AmPlugIn.cpp | 31 ++++++++++++++++--------------- core/AmPlugIn.h | 2 ++ core/atomic_types.h | 5 ++++- 6 files changed, 33 insertions(+), 24 deletions(-) diff --git a/apps/db_reg_agent/DBRegAgent.h b/apps/db_reg_agent/DBRegAgent.h index bbb0861e..c2302245 100644 --- a/apps/db_reg_agent/DBRegAgent.h +++ b/apps/db_reg_agent/DBRegAgent.h @@ -157,6 +157,11 @@ class DBRegAgent int onLoad(); + // atomic_ref_cnt interface + void on_destroy() { + onUnload(); + } + void onUnload(); RegistrationTimer registration_scheduler; diff --git a/apps/ivr/Ivr.cpp b/apps/ivr/Ivr.cpp index 7f6e215b..be21ff66 100644 --- a/apps/ivr/Ivr.cpp +++ b/apps/ivr/Ivr.cpp @@ -41,7 +41,9 @@ #include #include +#include using std::set; +using std::string; #define PYFILE_REGEX "(.+)\\.(py|pyc|pyo)$" @@ -461,7 +463,7 @@ int IvrFactory::onLoad() DBG("directory '%s' opened\n",script_path.c_str()); - set unique_entries; + std::set unique_entries; regmatch_t pmatch[2]; struct dirent* entry=0; @@ -479,7 +481,7 @@ int IvrFactory::onLoad() regfree(®); AmPlugIn* plugin = AmPlugIn::instance(); - for(set::iterator it = unique_entries.begin(); + for(std::set::iterator it = unique_entries.begin(); it != unique_entries.end(); it++) { if(loadScript(*it)){ diff --git a/core/AmApi.h b/core/AmApi.h index 4a1a6ae4..48b11de9 100644 --- a/core/AmApi.h +++ b/core/AmApi.h @@ -35,6 +35,7 @@ #include "AmConfigReader.h" #include "AmArg.h" #include "AmEventQueue.h" +#include "atomic_types.h" #include @@ -63,6 +64,7 @@ class AmDynInvoke * \brief Base interface for plugin factories */ class AmPluginFactory + : public virtual atomic_ref_cnt { string plugin_name; @@ -81,12 +83,6 @@ class AmPluginFactory * @return 1 on error. */ virtual int onLoad()=0; - - - /** - * Enables the plug-in to deinitialize once the server is stopped. - */ - virtual void onUnload() { }; }; /** diff --git a/core/AmPlugIn.cpp b/core/AmPlugIn.cpp index 682212f7..48b1fc53 100644 --- a/core/AmPlugIn.cpp +++ b/core/AmPlugIn.cpp @@ -108,26 +108,17 @@ AmPlugIn::AmPlugIn() { } -static std::set deleted_factories; -static std::set deleted_factories_names; static void delete_plugin_factory(std::pair pf) { - if ((deleted_factories.find(pf.second) == deleted_factories.end()) && - (deleted_factories_names.find(pf.first) == deleted_factories_names.end())) { - DBG("onUnload of plugin '%s'\n", pf.first.c_str()); - pf.second->onUnload(); + DBG("decreasing reference to plug-in factory: %s\n", pf.first.c_str()); + dec_ref(pf.second); - DBG("deleting plug-in factory: %s\n", pf.first.c_str()); - deleted_factories.insert(pf.second); - deleted_factories_names.insert(pf.first); - delete pf.second; - } } AmPlugIn::~AmPlugIn() { - std::for_each(name2app.begin(), name2app.end(), delete_plugin_factory); + std::for_each(module_objects.begin(), module_objects.end(), delete_plugin_factory); std::for_each(name2seh.begin(), name2seh.end(), delete_plugin_factory); std::for_each(name2base.begin(), name2base.end(), delete_plugin_factory); std::for_each(name2di.begin(), name2di.end(), delete_plugin_factory); @@ -566,6 +557,11 @@ int AmPlugIn::loadAppPlugIn(AmPluginFactory* f) name2app.insert(std::make_pair(sf->getName(),sf)); DBG("application '%s' loaded.\n",sf->getName().c_str()); + inc_ref(sf); + if(!module_objects.insert(std::make_pair(sf->getName(),sf)).second){ + // insertion failed + dec_ref(sf); + } name2app_mut.unlock(); return 0; @@ -584,7 +580,8 @@ int AmPlugIn::loadSehPlugIn(AmPluginFactory* f) ERROR("session component '%s' already loaded !\n",sf->getName().c_str()); goto error; } - + + inc_ref(sf); name2seh.insert(std::make_pair(sf->getName(),sf)); DBG("session component '%s' loaded.\n",sf->getName().c_str()); @@ -596,7 +593,11 @@ int AmPlugIn::loadSehPlugIn(AmPluginFactory* f) int AmPlugIn::loadBasePlugIn(AmPluginFactory* f) { - name2base.insert(std::make_pair(f->getName(),f)); + inc_ref(f); + if(!name2base.insert(std::make_pair(f->getName(),f)).second){ + // insertion failed + dec_ref(f); + } return 0; } @@ -812,7 +813,7 @@ AmSessionFactory* AmPlugIn::findSessionFactory(AmSipRequest& req) ERROR(comp_name "'%s' already registered !\n", param_name.c_str()); \ return false; \ } \ - \ + inc_ref(f); \ instance()->map_name.insert(std::make_pair(param_name,f)); \ DBG(comp_name " '%s' registered.\n",param_name.c_str()); \ return true; diff --git a/core/AmPlugIn.h b/core/AmPlugIn.h index 2dcd1ce8..641d0f3d 100644 --- a/core/AmPlugIn.h +++ b/core/AmPlugIn.h @@ -101,6 +101,8 @@ class AmPlugIn : public AmPayloadProviderInterface std::map name2di; std::map name2logfac; + std::map module_objects; + //AmCtrlInterfaceFactory *ctrlIface; int dynamic_pl; // range: 96->127, see RFC 1890 diff --git a/core/atomic_types.h b/core/atomic_types.h index d1bd84f9..0fadfab3 100644 --- a/core/atomic_types.h +++ b/core/atomic_types.h @@ -198,6 +198,7 @@ protected: : atomic_int() {} virtual ~atomic_ref_cnt() {} + virtual void on_destroy() {} friend void inc_ref(atomic_ref_cnt* rc); friend void dec_ref(atomic_ref_cnt* rc); @@ -212,8 +213,10 @@ inline void inc_ref(atomic_ref_cnt* rc) inline void dec_ref(atomic_ref_cnt* rc) { assert(rc); - if(rc->dec_and_test()) + if(rc->dec_and_test()){ + rc->on_destroy(); delete rc; + } }