From 5024c51379a143e78866a1c15299cab7194c4a15 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Thu, 23 Oct 2014 22:17:39 +0200 Subject: [PATCH] [DEBUG] signal error when removing signal in signal calling --- build | 2 +- external/egami | 2 +- external/ejson | 2 +- external/etk | 2 +- external/exml | 2 +- sources/ewol/object/Signal.h | 181 +++++++++++++++++++++++++---- sources/ewol/object/SignalBase.cpp | 13 ++- sources/ewol/object/SignalBase.h | 6 +- 8 files changed, 179 insertions(+), 31 deletions(-) diff --git a/build b/build index dd03e468..288207e4 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit dd03e468326f087e3becf1f497ca7aa87d3c521b +Subproject commit 288207e4e1fdcee746b587a9ac644cfdf6ed17f5 diff --git a/external/egami b/external/egami index aa66ac17..ff1239ee 160000 --- a/external/egami +++ b/external/egami @@ -1 +1 @@ -Subproject commit aa66ac176f625abf61122e0a71a608adab43fca2 +Subproject commit ff1239ee266d14d380d53cc7407d4e60c75b0db2 diff --git a/external/ejson b/external/ejson index ad2d06e4..226d9513 160000 --- a/external/ejson +++ b/external/ejson @@ -1 +1 @@ -Subproject commit ad2d06e4361d9b37074433e5da1481237049c105 +Subproject commit 226d95135ccb49de2427a38256212b5020a090d1 diff --git a/external/etk b/external/etk index 63c9ff74..45c4fbb9 160000 --- a/external/etk +++ b/external/etk @@ -1 +1 @@ -Subproject commit 63c9ff74c23a52aa8fd718a0c6d26fc6c88fab01 +Subproject commit 45c4fbb98db6b5b50599dfaef5903d3a78e63f08 diff --git a/external/exml b/external/exml index a4c544e9..479921d3 160000 --- a/external/exml +++ b/external/exml @@ -1 +1 @@ -Subproject commit a4c544e916ed9d9519adedeb53d2f023e53aa360 +Subproject commit 479921d3475fe3fd7a72bbd9e1772f70d284f774 diff --git a/sources/ewol/object/Signal.h b/sources/ewol/object/Signal.h index 638ea87d..836bd61b 100644 --- a/sources/ewol/object/Signal.h +++ b/sources/ewol/object/Signal.h @@ -23,7 +23,9 @@ namespace ewol { template class Signal : public SignalBase { private: std::vector, - std::function>> m_callerList; + std::function>> m_callerList; // current list of binded element + std::vector, + std::function>> m_callerListInCallback; // temporaty list (when add one in call process) public: /** * @brief Create a parameter with a specific type. @@ -68,7 +70,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1))); + } } // TODO : Rework this when I understand the use of variadic template with std::function template @@ -78,7 +84,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1))); + } } template void bind2(std::shared_ptr _obj, void (TYPE::*_func)(const T&, const TYPE2&, const TYPE3&), TYPE2 _param1, TYPE3 _param2) { @@ -87,7 +97,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1, _param2))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1, _param2))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), std::placeholders::_1, _param1, _param2))); + } } /** * @brief Advanced binding a callback function to the current signal. @@ -96,17 +110,44 @@ namespace ewol { * @example signalXXXX.connect(shared_from_this(), std::bind(&ClassName::onCallbackXXX, this, std::placeholders::_1)); */ void connect(std::shared_ptr _obj, std::function _function ) { - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + } } /** * @brief remove link on the signal. * @param[in] _obj shared pointer on the removing object */ void release(std::shared_ptr _obj) { - auto it(m_callerList.begin()); - while(it != m_callerList.end()) { + if (m_callInProgress == 0) { + // Remove from the list : + auto it(m_callerList.begin()); + while(it != m_callerList.end()) { + if (it->first.lock() == _obj) { + it = m_callerList.erase(it); + } else { + ++it; + } + } + } else { + // just remove weak poointer + auto it(m_callerList.begin()); + while(it != m_callerList.end()) { + if (it->first.lock() == _obj) { + it->first.reset(); + } else { + ++it; + } + } + m_someOneRemoveInCall = true; + } + // remove from add list in callback progress + auto it = m_callerListInCallback.begin(); + while(it != m_callerListInCallback.end()) { if (it->first.lock() == _obj) { - it = m_callerList.erase(it); + it = m_callerListInCallback.erase(it); } else { ++it; } @@ -117,31 +158,55 @@ namespace ewol { * @param[in] _data data to emit */ void emit(const T& _data) { + m_signalCallLeval++; + m_callInProgress++; #ifdef DEBUG int32_t tmpID = m_uidSignal++; ewol::Object* srcObject = dynamic_cast(&m_objectLink); if (srcObject != nullptr) { - EWOL_VERBOSE("emit signal{" << tmpID << "} : " << srcObject->getObjectType() << " signal='" << m_name << "' data='" << etk::to_string(_data) << "' to:"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << "emit signal{" << tmpID << "} : " << srcObject->getObjectType() << " signal='" << m_name << "' data='" << etk::to_string(_data) << "' to: " << m_callerList.size() << " element(s)"); } else { - EWOL_VERBOSE("emit signal{" << tmpID << "} : signal='" << m_name << "' data='" << etk::to_string(_data) << "' to:"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << "emit signal{" << tmpID << "} : signal='" << m_name << "' data='" << etk::to_string(_data) << "' to: " << m_callerList.size() << " element(s)"); } #endif for (auto &it : m_callerList) { std::shared_ptr destObject = it.first.lock(); if (destObject == nullptr) { // TODO : Remove instance ... - EWOL_VERBOSE(" nullptr dest"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " nullptr dest"); continue; } #ifdef DEBUG if (srcObject != nullptr) { - EWOL_VERBOSE(" signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); } else { - EWOL_VERBOSE(" signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); } #endif it.second(_data); } + m_callInProgress--; + m_signalCallLeval--; + // Remove element in call phase: + if (m_someOneRemoveInCall == true) { + m_someOneRemoveInCall = false; + // Remove from the list : + auto it(m_callerList.begin()); + while(it != m_callerList.end()) { + if (it->first.expired() == true) { + it = m_callerList.erase(it); + } else { + ++it; + } + } + } + // add element in call phase: + if (m_callerListInCallback.size() > 0) { + for (auto &it : m_callerListInCallback) { + m_callerList.push_back(it); + } + m_callerListInCallback.clear(); + } } }; #undef __class__ @@ -149,6 +214,7 @@ namespace ewol { template<> class Signal : public SignalBase { private: std::vector, std::function>> m_callerList; + std::vector, std::function>> m_callerListInCallback; public: /** * @brief Create a parameter with a specific type. @@ -183,7 +249,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get()))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get()))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get()))); + } } template void bind1(std::shared_ptr _obj, void (TYPE::*_func)(TYPE2), TYPE2 _param1) { @@ -192,7 +262,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1))); + } } template void bind2(std::shared_ptr _obj, void (TYPE::*_func)(TYPE2, TYPE2), TYPE2 _param1, TYPE3 _param2) { @@ -201,7 +275,11 @@ namespace ewol { EWOL_ERROR("Can not bind signal ..."); return; } - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1, _param2))); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1, _param2))); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), std::bind(_func, obj2.get(), _param1, _param2))); + } } /** * @brief Advanced binding a callback function to the current signal. @@ -210,7 +288,11 @@ namespace ewol { * @example signalXXXX.connect(shared_from_this(), std::bind(&ClassName::onCallbackXXX, this, std::placeholders::_1)); */ void connect(std::shared_ptr _obj, std::function _function ) { - m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + if (m_callInProgress == 0) { + m_callerList.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + } else { + m_callerListInCallback.push_back(std::make_pair(std::weak_ptr(_obj), _function)); + } } /** * @brief remove link on the signal. @@ -218,40 +300,91 @@ namespace ewol { */ void release(std::shared_ptr _obj) { auto it(m_callerList.begin()); - while(it != m_callerList.end()) { + if (m_callInProgress == 0) { + // Remove from the list : + while(it != m_callerList.end()) { + if (it->first.lock() == _obj) { + EWOL_DEBUG(" unbind : " << _obj->getObjectType() << " signal='" << m_name << "'"); + it = m_callerList.erase(it); + } else { + ++it; + } + } + } else { + // just remove weak poointer + while(it != m_callerList.end()) { + if (it->first.lock() == _obj) { + EWOL_DEBUG(" unbind : " << _obj->getObjectType() << " signal='" << m_name << "' (delayed)"); + it->first.reset(); + } else { + ++it; + } + } + m_someOneRemoveInCall = true; + } + // remove from add list in callback progress + it = m_callerListInCallback.begin(); + while(it != m_callerListInCallback.end()) { if (it->first.lock() == _obj) { - it = m_callerList.erase(it); + EWOL_DEBUG(" unbind : " << _obj->getObjectType() << " signal='" << m_name << "' (notActive)"); + it = m_callerListInCallback.erase(it); } else { ++it; } } } void emit() { + m_callInProgress++; + m_signalCallLeval++; #ifdef DEBUG int32_t tmpID = m_uidSignal++; ewol::Object* srcObject = dynamic_cast(&m_objectLink); if (srcObject != nullptr) { - EWOL_VERBOSE("emit signal{" << tmpID << "} : " << srcObject->getObjectType() << " signal='" << m_name << "' BANG!!! to:"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << "emit signal{" << tmpID << "} : " << srcObject->getObjectType() << " signal='" << m_name << "' BANG!!! to: " << m_callerList.size() << " element(s)"); } else { - EWOL_VERBOSE("emit signal{" << tmpID << "} : signal='" << m_name << "' to:"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << "emit signal{" << tmpID << "} : signal='" << m_name << "' to: " << m_callerList.size() << " element(s)"); } #endif for (auto &it : m_callerList) { std::shared_ptr destObject = it.first.lock(); if (destObject == nullptr) { // TODO : Remove instance ... - EWOL_VERBOSE(" nullptr dest"); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " nullptr dest"); continue; } #ifdef DEBUG if (srcObject != nullptr) { - EWOL_VERBOSE(" signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); } else { - EWOL_VERBOSE(" signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); + EWOL_DEBUG(ewol::object::logIndent(m_signalCallLeval-1) << " signal{" << tmpID << "} : [" << destObject->getId() << "]" << destObject->getObjectType()); } #endif it.second(); } + m_callInProgress--; + m_signalCallLeval--; + // Remove element in call phase: + if (m_someOneRemoveInCall == true) { + m_someOneRemoveInCall = false; + // Remove from the list : + auto it(m_callerList.begin()); + while(it != m_callerList.end()) { + if (it->first.expired() == true) { + it = m_callerList.erase(it); + } else { + ++it; + } + } + } + // add element in call phase: + if (m_callerListInCallback.size() > 0) { + for (auto &it : m_callerListInCallback) { + if (it.first.expired() == false) { + m_callerList.push_back(it); + } + } + m_callerListInCallback.clear(); + } } }; #undef __class__ diff --git a/sources/ewol/object/SignalBase.cpp b/sources/ewol/object/SignalBase.cpp index 87b1b101..90e1e821 100644 --- a/sources/ewol/object/SignalBase.cpp +++ b/sources/ewol/object/SignalBase.cpp @@ -13,12 +13,15 @@ #include int32_t ewol::object::SignalBase::m_uidSignal = 0; +int32_t ewol::object::SignalBase::m_signalCallLeval = 0; ewol::object::SignalBase::SignalBase(ewol::object::SignalList& _objectLink, const std::string& _name, const std::string& _description) : m_objectLink(_objectLink), m_name(_name), - m_description(_description) { + m_description(_description), + m_callInProgress(0), + m_someOneRemoveInCall(false) { // add a reference on the current signal ... m_objectLink.signalAdd(this); } @@ -28,3 +31,11 @@ std::ostream& ewol::object::operator <<(std::ostream& _os, const ewol::object::S return _os; } + +const char* ewol::object::logIndent(int32_t _iii) { + static const char g_val[] = " "; + if (_iii > 5) { + return g_val; + } + return g_val + (5-_iii)*4; +} \ No newline at end of file diff --git a/sources/ewol/object/SignalBase.h b/sources/ewol/object/SignalBase.h index 5e60ddea..ed277468 100644 --- a/sources/ewol/object/SignalBase.h +++ b/sources/ewol/object/SignalBase.h @@ -18,10 +18,13 @@ namespace ewol { namespace object { class SignalBase { protected: + static int32_t m_uidSignal; + static int32_t m_signalCallLeval; ewol::object::SignalList& m_objectLink; std::string m_name; std::string m_description; - static int32_t m_uidSignal; + int32_t m_callInProgress; + bool m_someOneRemoveInCall; public: /** * @brief Create a parameter with a specific type. @@ -46,6 +49,7 @@ namespace ewol { virtual void release(std::shared_ptr _obj) = 0; }; std::ostream& operator <<(std::ostream& _os, const SignalBase& _obj); + const char* logIndent(int32_t _iii); }; }; #endif