diff options
author | Juergen Gehring <juergen.gehring@bmw.de> | 2017-04-07 01:32:39 -0700 |
---|---|---|
committer | Juergen Gehring <juergen.gehring@bmw.de> | 2017-04-07 01:32:39 -0700 |
commit | 44103948d4b052603c0b361448ecb4ef7d954f79 (patch) | |
tree | f7c95861a4128e0f1cb058eff73ff2911a37f468 | |
parent | fad59c73675aea115d0c292b5743de2591bdf6b3 (diff) | |
download | genivi-common-api-dbus-runtime-44103948d4b052603c0b361448ecb4ef7d954f79.tar.gz |
CommonAPI-D-Bus 3.1.11.13.1.11.1
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rw-r--r-- | include/CommonAPI/DBus/DBusConnection.hpp | 21 | ||||
-rw-r--r-- | include/CommonAPI/DBus/DBusFactory.hpp | 2 | ||||
-rw-r--r-- | include/CommonAPI/DBus/DBusProxyConnection.hpp | 7 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusConnection.cpp | 491 | ||||
-rw-r--r-- | src/CommonAPI/DBus/DBusFactory.cpp | 14 | ||||
-rw-r--r-- | src/dbus-patches/capi-dbus-1-pc.patch | 9 |
8 files changed, 391 insertions, 164 deletions
@@ -1,5 +1,8 @@ Changes ======= +v3.1.11.1 +- Support deployment for anonymous arrays +- Fixed concurrency problem / segfault in unregisterStub() v3.1.11 - Fixed availability problem of proxies that connect to legacy managed services by changing the way of resolving object paths and available interfaces diff --git a/CMakeLists.txt b/CMakeLists.txt index 350a1ed..b40aa56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,8 +177,12 @@ include_directories( ${DBus_INCLUDE_DIRS} ) -if ("${USE_INSTALLED_DBUS}" STREQUAL "OFF") - set (DBus_LIBRARIES dbus-1) +if ("${USE_INSTALLED_DBUS}" STREQUAL "ON") + link_directories( + ${DBus_LIBRARY_DIRS} + ) +else() + set (DBus_LIBRARIES dbus-1) link_directories( ${DBus_INCLUDE_DIRS}/dbus/.libs ) diff --git a/include/CommonAPI/DBus/DBusConnection.hpp b/include/CommonAPI/DBus/DBusConnection.hpp index e88eab6..a382bae 100644 --- a/include/CommonAPI/DBus/DBusConnection.hpp +++ b/include/CommonAPI/DBus/DBusConnection.hpp @@ -226,6 +226,7 @@ public: typedef std::tuple<std::string, std::string, std::string> DBusSignalMatchRuleTuple; typedef std::pair<uint32_t, std::string> DBusSignalMatchRuleMapping; typedef std::unordered_map<DBusSignalMatchRuleTuple, DBusSignalMatchRuleMapping> DBusSignalMatchRulesMap; + typedef std::unordered_map<std::string, size_t> DBusOMSignalMatchRulesMap; private: struct PendingCallNotificationData { @@ -310,10 +311,13 @@ public: void deleteAsyncHandlers(); + uint32_t getNumberOfSignalMemberHandlers(DBusSignalHandlerPath handlerPath); + ::DBusConnection* connection_; mutable std::recursive_mutex connectionGuard_; - std::mutex signalGuard_; + std::mutex signalHandlersGuard_; + std::mutex objectManagerGuard_; std::mutex serviceRegistryGuard_; @@ -325,12 +329,17 @@ public: DBusSignalMatchRulesMap dbusSignalMatchRulesMap_; - DBusSignalHandlerTable dbusSignalHandlerTable_; + DBusSignalHandlerTable dbusSignalHandlers_; + DBusSignalHandlerTable dbusSignalHandlersToAdd_; + DBusSignalHandlerTable dbusSignalHandlersToRemove_; + + std::mutex dbusOMSignalHandlersGuard_; + + DBusOMSignalMatchRulesMap dbusOMSignalMatchRulesMap_; - std::unordered_map<std::string, size_t> dbusObjectManagerSignalMatchRulesMap_; - std::unordered_multimap<std::string, std::pair<DBusSignalHandler*, - std::weak_ptr<DBusSignalHandler>>> dbusObjectManagerSignalHandlerTable_; - std::mutex dbusObjectManagerSignalGuard_; + DBusOMSignalHandlerTable dbusOMSignalHandlers_; + DBusOMSignalHandlerTable dbusOMSignalHandlersToAdd_; + DBusOMSignalHandlerTable dbusOMSignalHandlersToRemove_; COMMONAPI_EXPORT bool addObjectManagerSignalMatchRule(const std::string& dbusBusName); COMMONAPI_EXPORT bool removeObjectManagerSignalMatchRule(const std::string& dbusBusName); diff --git a/include/CommonAPI/DBus/DBusFactory.hpp b/include/CommonAPI/DBus/DBusFactory.hpp index 157382d..9654a94 100644 --- a/include/CommonAPI/DBus/DBusFactory.hpp +++ b/include/CommonAPI/DBus/DBusFactory.hpp @@ -109,7 +109,6 @@ private: // Managed services typedef std::unordered_map<std::string, std::shared_ptr<DBusStubAdapter>> ServicesMap; - COMMONAPI_EXPORT bool unregisterManagedService(const ServicesMap::iterator &); private: static std::shared_ptr<Factory> theFactory; @@ -121,6 +120,7 @@ private: std::map<std::string, StubAdapterCreateFunction> stubAdapterCreateFunctions_; ServicesMap services_; + std::recursive_mutex servicesMutex_; std::list<InterfaceInitFunction> initializers_; std::mutex initializerMutex_; diff --git a/include/CommonAPI/DBus/DBusProxyConnection.hpp b/include/CommonAPI/DBus/DBusProxyConnection.hpp index ec02082..41797e0 100644 --- a/include/CommonAPI/DBus/DBusProxyConnection.hpp +++ b/include/CommonAPI/DBus/DBusProxyConnection.hpp @@ -62,9 +62,10 @@ class DBusProxyConnection { // objectPath, interfaceName, interfaceMemberName, interfaceMemberSignature typedef std::tuple<std::string, std::string, std::string, std::string> DBusSignalHandlerPath; typedef std::unordered_map<DBusSignalHandlerPath, - std::pair<std::shared_ptr<std::recursive_mutex>, - std::map<DBusSignalHandler*, - std::weak_ptr<DBusProxyConnection::DBusSignalHandler>>>> DBusSignalHandlerTable; + std::map<DBusSignalHandler*, + std::weak_ptr<DBusProxyConnection::DBusSignalHandler>>> DBusSignalHandlerTable; + typedef std::unordered_multimap<std::string, std::pair<DBusSignalHandler*, + std::weak_ptr<DBusSignalHandler>>> DBusOMSignalHandlerTable; typedef DBusSignalHandlerPath DBusSignalHandlerToken; class DBusSignalHandler { diff --git a/src/CommonAPI/DBus/DBusConnection.cpp b/src/CommonAPI/DBus/DBusConnection.cpp index 589b5f4..0ce70bc 100644 --- a/src/CommonAPI/DBus/DBusConnection.cpp +++ b/src/CommonAPI/DBus/DBusConnection.cpp @@ -1143,49 +1143,58 @@ DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandl interfaceMemberName, interfaceMemberSignature); - std::unique_lock<std::mutex> dbusSignalLock(signalGuard_); + std::lock_guard<std::mutex> dbusSignalHandlersLock(signalHandlersGuard_); - auto signalEntry = dbusSignalHandlerTable_.find(dbusSignalHandlerPath); - const bool isFirstSignalMemberHandler = (signalEntry == dbusSignalHandlerTable_.end()); - - auto itsHandler = dbusSignalHandler.lock(); + if(auto itsHandler = dbusSignalHandler.lock()) { - if (itsHandler && isFirstSignalMemberHandler) { - addLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName, justAddFilter); + uint32_t lastNumOfSignalMemberHandlers = getNumberOfSignalMemberHandlers(dbusSignalHandlerPath); - std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; - handlerList[itsHandler.get()] = dbusSignalHandler; + //check if signal handler is already added + auto signalHandlerPathIt = dbusSignalHandlers_.find(dbusSignalHandlerPath); + if(signalHandlerPathIt == dbusSignalHandlers_.end() || + signalHandlerPathIt->second.find(itsHandler.get()) == signalHandlerPathIt->second.end()) { - dbusSignalHandlerTable_.insert( { - dbusSignalHandlerPath, - std::make_pair(std::make_shared<std::recursive_mutex>(), std::move(handlerList)) - } ); - } else if (itsHandler && !isFirstSignalMemberHandler) { + // the signal handler is not added yet for the 'dbusSignalHandlerPath' --> needs to be added + auto signalHandlerPathToAddIt = dbusSignalHandlersToAdd_.find(dbusSignalHandlerPath); + if(signalHandlerPathToAddIt == dbusSignalHandlersToAdd_.end()) { - //get mutex for signal entry - auto signalEntryMutex = signalEntry->second.first; + // is first signal member handler for this 'dbusSignalHandlerPath' --> add + std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + handlerList[itsHandler.get()] = dbusSignalHandler; - // mutex of signal entry must be locked first to avoid potential deadlock - dbusSignalLock.unlock(); - signalEntryMutex->lock(); + dbusSignalHandlersToAdd_.insert( { + dbusSignalHandlerPath, + std::move(handlerList) + } ); + } else { + // add further signal handler + signalHandlerPathToAddIt->second[itsHandler.get()] = dbusSignalHandler; + } - dbusSignalLock.lock(); - signalEntry = dbusSignalHandlerTable_.find(dbusSignalHandlerPath); - if(signalEntry != dbusSignalHandlerTable_.end()) { - signalEntry->second.second[itsHandler.get()] = dbusSignalHandler; } else { - //is first signal member handler again - addLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName, justAddFilter); + // signal handler is already added + // check if handler is going to be removed + auto signalHandlerPathToRemoveIt = dbusSignalHandlersToRemove_.find(dbusSignalHandlerPath); + if(signalHandlerPathToRemoveIt != dbusSignalHandlersToRemove_.end()) { + + auto handlerToRemoveEntry = signalHandlerPathToRemoveIt->second.find(itsHandler.get()); + if(handlerToRemoveEntry != signalHandlerPathToRemoveIt->second.end()) { + + // signal handler is going to be removed --> erase + signalHandlerPathToRemoveIt->second.erase(handlerToRemoveEntry); + if(signalHandlerPathToRemoveIt->second.empty()) { + dbusSignalHandlersToRemove_.erase(signalHandlerPathToRemoveIt); + } + } + } + } - std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; - handlerList[itsHandler.get()] = dbusSignalHandler; + uint32_t numOfSignalMemberHandlers = getNumberOfSignalMemberHandlers(dbusSignalHandlerPath); - dbusSignalHandlerTable_.insert( { - dbusSignalHandlerPath, - std::make_pair(std::make_shared<std::recursive_mutex>(), std::move(handlerList)) - } ); + if(lastNumOfSignalMemberHandlers == 0 && numOfSignalMemberHandlers == 1) { + // a new signal handler for the 'dbusSignalHandlerPath' was added --> add match rule + addLibdbusSignalMatchRule(objectPath, interfaceName, interfaceMemberName, justAddFilter); } - signalEntryMutex->unlock(); } return dbusSignalHandlerPath; @@ -1193,38 +1202,72 @@ DBusProxyConnection::DBusSignalHandlerToken DBusConnection::addSignalMemberHandl bool DBusConnection::removeSignalMemberHandler(const DBusSignalHandlerToken &dbusSignalHandlerToken, const DBusSignalHandler* dbusSignalHandler) { - bool lastHandlerRemoved = false; - std::unique_lock<std::mutex> itsLock(signalGuard_); - auto signalEntry = dbusSignalHandlerTable_.find(dbusSignalHandlerToken); - if (signalEntry != dbusSignalHandlerTable_.end()) { + std::lock_guard<std::mutex> itsLock(signalHandlersGuard_); + + uint32_t lastNumOfSignalMemberHandlers = getNumberOfSignalMemberHandlers(dbusSignalHandlerToken); + + //check if signal handler is already added + auto signalHandlerPathIt = dbusSignalHandlers_.find(dbusSignalHandlerToken); + if(signalHandlerPathIt != dbusSignalHandlers_.end() && + signalHandlerPathIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)) != + signalHandlerPathIt->second.end()) { + + // signal handler is already added + // check if handler is going to be removed + auto signalHandlerPathToRemoveIt = dbusSignalHandlersToRemove_.find(dbusSignalHandlerToken); + if(signalHandlerPathToRemoveIt != dbusSignalHandlersToRemove_.end()) { - auto signalEntryMutex = signalEntry->second.first; + auto it = signalHandlerPathToRemoveIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)); - // mutex of signal entry must be locked first to avoid potential deadlock - itsLock.unlock(); - signalEntryMutex->lock(); + if(it == signalHandlerPathToRemoveIt->second.end()) { + + // handler is not going to be removed yet --> remove + signalHandlerPathToRemoveIt->second[const_cast<DBusSignalHandler*>(dbusSignalHandler)] = + std::weak_ptr<DBusSignalHandler>(); + } + + } else { + // handler is not going to be removed yet. No dbus signal handler token found --> insert with handler to remove + std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + handlerList[const_cast<DBusSignalHandler*>(dbusSignalHandler)] = + std::weak_ptr<DBusSignalHandler>(); - itsLock.lock(); - signalEntry = dbusSignalHandlerTable_.find(dbusSignalHandlerToken); - if(signalEntry != dbusSignalHandlerTable_.end()) { - auto selectedHandler = signalEntry->second.second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)); - if (selectedHandler != signalEntry->second.second.end()) { - signalEntry->second.second.erase(selectedHandler); - lastHandlerRemoved = (signalEntry->second.second.empty()); + dbusSignalHandlersToRemove_.insert( { + dbusSignalHandlerToken, + std::move(handlerList) + } ); + } + + } else { + // signal handler not added yet + // check if handler is going to be added + auto signalHandlerPathToAddIt = dbusSignalHandlersToAdd_.find(dbusSignalHandlerToken); + if(signalHandlerPathToAddIt != dbusSignalHandlersToAdd_.end()) { + + auto handlersToAddEntry = signalHandlerPathToAddIt->second.find(const_cast<DBusSignalHandler*>(dbusSignalHandler)); + if(handlersToAddEntry != signalHandlerPathToAddIt->second.end()) { + + // handler is planned to be added --> erase + signalHandlerPathToAddIt->second.erase(handlersToAddEntry); + if(signalHandlerPathToAddIt->second.empty()) { + dbusSignalHandlersToAdd_.erase(signalHandlerPathToAddIt); + } } } - signalEntryMutex->unlock(); } - if (lastHandlerRemoved) { - dbusSignalHandlerTable_.erase(signalEntry); + uint32_t numOfSignalMemberHandlers = getNumberOfSignalMemberHandlers(dbusSignalHandlerToken); + + if(lastNumOfSignalMemberHandlers == 1 && numOfSignalMemberHandlers == 0) { + // the last signal handler for the 'dbusSignalHandlerToken' was removed --> remove match rule removeLibdbusSignalMatchRule(std::get<0>(dbusSignalHandlerToken), - std::get<1>(dbusSignalHandlerToken), - std::get<2>(dbusSignalHandlerToken)); + std::get<1>(dbusSignalHandlerToken), + std::get<2>(dbusSignalHandlerToken)); + return true; } - return lastHandlerRemoved; + return false; } bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbusBusName, @@ -1234,37 +1277,46 @@ bool DBusConnection::addObjectManagerSignalMemberHandler(const std::string& dbus } if(auto itsHandler = dbusSignalHandler.lock()) { - std::lock_guard<std::mutex> dbusSignalLock(dbusObjectManagerSignalGuard_); + std::lock_guard<std::mutex> dbusSignalLock(dbusOMSignalHandlersGuard_); - auto dbusSignalMatchRuleIterator = dbusObjectManagerSignalMatchRulesMap_.find(dbusBusName); - const bool isDBusSignalMatchRuleFound = (dbusSignalMatchRuleIterator != dbusObjectManagerSignalMatchRulesMap_.end()); + auto signalHandlerPathIt = dbusOMSignalHandlers_.find(dbusBusName); + if(signalHandlerPathIt == dbusOMSignalHandlers_.end()) { - if (!isDBusSignalMatchRuleFound) { - if (isConnected() && !addObjectManagerSignalMatchRule(dbusBusName)) { - return false; - } + // the signal handler is not added yet --> add + auto signalHandlerPathToAddIt = dbusOMSignalHandlersToAdd_.find(dbusBusName); + if(signalHandlerPathToAddIt == dbusOMSignalHandlersToAdd_.end()) { - auto insertResult = dbusObjectManagerSignalMatchRulesMap_.insert({ dbusBusName, 0 }); - const bool isInsertSuccessful = insertResult.second; + // is first signal member handler --> add to list and add match rule + std::pair<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = + std::make_pair(itsHandler.get(), dbusSignalHandler); - if (!isInsertSuccessful) { - if (isConnected()) { - const bool isRemoveSignalMatchRuleSuccessful = removeObjectManagerSignalMatchRule(dbusBusName); - if (!isRemoveSignalMatchRuleSuccessful) { - COMMONAPI_ERROR(std::string(__FUNCTION__), " removeObjectManagerSignalMatchRule", dbusBusName, " failed"); - } + dbusOMSignalHandlersToAdd_.insert( { + dbusBusName, + std::move(handler) + } ); + + if (!addObjectManagerSignalMatchRule(dbusBusName)) { + return false; + } + } else { + // signal handler is already going to be added + COMMONAPI_WARNING(std::string(__FUNCTION__), " a signal handler is already added for ", dbusBusName); + return true; + } + } else { + // signal handler is added + // check if handler is going to be removed + auto signalHandlerPathToRemoveIt= dbusOMSignalHandlersToRemove_.find(dbusBusName); + if(signalHandlerPathToRemoveIt != dbusOMSignalHandlersToRemove_.end()) { + + // signal handler is going to be removed --> erase + dbusOMSignalHandlersToRemove_.erase(signalHandlerPathToRemoveIt); + if(isConnected() && !addObjectManagerSignalMatchRule(dbusBusName)) { + return false; } - return false; } - - dbusSignalMatchRuleIterator = insertResult.first; } - - size_t &dbusSignalMatchRuleReferenceCount = dbusSignalMatchRuleIterator->second; - dbusSignalMatchRuleReferenceCount++; - dbusObjectManagerSignalHandlerTable_.insert( { dbusBusName, std::make_pair(itsHandler.get(), dbusSignalHandler) } ); } - return true; } @@ -1275,53 +1327,93 @@ bool DBusConnection::removeObjectManagerSignalMemberHandler(const std::string& d return false; } - std::lock_guard<std::mutex> dbusSignalLock(dbusObjectManagerSignalGuard_); + std::lock_guard<std::mutex> itsLock(signalHandlersGuard_); - auto dbusSignalMatchRuleIterator = dbusObjectManagerSignalMatchRulesMap_.find(dbusBusName); - const bool isDBusSignalMatchRuleFound = (dbusSignalMatchRuleIterator != dbusObjectManagerSignalMatchRulesMap_.end()); + auto signalHandlerPathIt = dbusOMSignalHandlers_.find(dbusBusName); + if(signalHandlerPathIt != dbusOMSignalHandlers_.end()) { - if (!isDBusSignalMatchRuleFound) { - return true; - } + // signal handler is added + // check if handler is already going to be removed + auto signalHandlerPathToRemoveIt = dbusOMSignalHandlersToRemove_.find(dbusBusName); + if(signalHandlerPathToRemoveIt != dbusOMSignalHandlersToRemove_.end()) { - auto dbusObjectManagerSignalHandlerRange = dbusObjectManagerSignalHandlerTable_.equal_range(dbusBusName); - auto dbusObjectManagerSignalHandlerIterator = std::find_if( - dbusObjectManagerSignalHandlerRange.first, - dbusObjectManagerSignalHandlerRange.second, - [&](decltype(*dbusObjectManagerSignalHandlerRange.first)& it) { return it.second.first == dbusSignalHandler; }); - const bool isDBusSignalHandlerFound = (dbusObjectManagerSignalHandlerIterator != dbusObjectManagerSignalHandlerRange.second); - if (!isDBusSignalHandlerFound) { - return false; - } + if(signalHandlerPathToRemoveIt->second.first == dbusSignalHandler) { + COMMONAPI_WARNING(std::string(__FUNCTION__), " the signal handler is already removed for ", dbusBusName); + return true; + } else { + COMMONAPI_ERROR(std::string(__FUNCTION__), " the signal handler is not found for ", dbusBusName); + return false; + } + } else { + // no dbus signal handler found for 'dbusBusName' --> insert with handler + std::pair<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handler = + std::make_pair(dbusSignalHandler, std::weak_ptr<DBusSignalHandler>()); - size_t& dbusSignalMatchRuleReferenceCount = dbusSignalMatchRuleIterator->second; + dbusOMSignalHandlersToRemove_.insert( { + dbusBusName, + std::move(handler) + } ); - if (0 == dbusSignalMatchRuleReferenceCount) { - COMMONAPI_ERROR(std::string(__FUNCTION__), "ref count == 0"); + if (isConnected() && !removeObjectManagerSignalMatchRule(dbusBusName)) { + return false; + } + } } else { - dbusSignalMatchRuleReferenceCount--; - } - - const bool isLastDBusSignalMatchRuleReference = (dbusSignalMatchRuleReferenceCount == 0); - if (isLastDBusSignalMatchRuleReference) { - if (isConnected() && !removeObjectManagerSignalMatchRule(dbusBusName)) { - return false; + // signal handler not added + // check if handler is going to be added + auto signalHandlerPathToAddIt = dbusOMSignalHandlersToAdd_.find(dbusBusName); + if(signalHandlerPathToAddIt != dbusOMSignalHandlersToAdd_.end()) { + + if(signalHandlerPathToAddIt->second.first == dbusSignalHandler) { + // handler is planned to be added --> erase + dbusOMSignalHandlersToAdd_.erase(signalHandlerPathToAddIt); + if (isConnected() && !removeObjectManagerSignalMatchRule(dbusBusName)) { + return false; + } + } else { + COMMONAPI_ERROR(std::string(__FUNCTION__), " the signal handler is not found for ", dbusBusName); + return false; + } } - - dbusObjectManagerSignalMatchRulesMap_.erase(dbusSignalMatchRuleIterator); } - - dbusObjectManagerSignalHandlerTable_.erase(dbusObjectManagerSignalHandlerIterator); - return true; } bool DBusConnection::addObjectManagerSignalMatchRule(const std::string& dbusBusName) { + std::ostringstream dbusMatchRuleStringStream; dbusMatchRuleStringStream << "type='signal'" << ",sender='" << dbusBusName << "'" << ",interface='org.freedesktop.DBus.ObjectManager'"; - return addLibdbusSignalMatchRule(dbusMatchRuleStringStream.str()); + + auto dbusSignalMatchRuleIterator = dbusOMSignalMatchRulesMap_.find(dbusBusName); + const bool isDBusSignalMatchRuleFound = (dbusSignalMatchRuleIterator != dbusOMSignalMatchRulesMap_.end()); + + if (!isDBusSignalMatchRuleFound) { + + if(isConnected() && !addLibdbusSignalMatchRule(dbusMatchRuleStringStream.str())) { + return false; + } + + auto insertResult = dbusOMSignalMatchRulesMap_.insert({ dbusBusName, 0 }); + const bool isInsertSuccessful = insertResult.second; + + if (!isInsertSuccessful) { + if (isConnected()) { + if (!removeObjectManagerSignalMatchRule(dbusBusName)) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " removeObjectManagerSignalMatchRule", dbusBusName, " failed"); + } + } + return false; + } + + dbusSignalMatchRuleIterator = insertResult.first; + } + + size_t &dbusSignalMatchRuleReferenceCount = dbusSignalMatchRuleIterator->second; + dbusSignalMatchRuleReferenceCount++; + + return true; } bool DBusConnection::removeObjectManagerSignalMatchRule(const std::string& dbusBusName) { @@ -1329,7 +1421,30 @@ bool DBusConnection::removeObjectManagerSignalMatchRule(const std::string& dbusB dbusMatchRuleStringStream << "type='signal'" << ",sender='" << dbusBusName << "'" << ",interface='org.freedesktop.DBus.ObjectManager'"; - return removeLibdbusSignalMatchRule(dbusMatchRuleStringStream.str()); + + auto dbusSignalMatchRuleIterator = dbusOMSignalMatchRulesMap_.find(dbusBusName); + const bool isDBusSignalMatchRuleFound = (dbusSignalMatchRuleIterator != dbusOMSignalMatchRulesMap_.end()); + + if (!isDBusSignalMatchRuleFound) { + return true; + } + + size_t& dbusSignalMatchRuleReferenceCount = dbusSignalMatchRuleIterator->second; + + if (0 == dbusSignalMatchRuleReferenceCount) { + COMMONAPI_ERROR(std::string(__FUNCTION__), "ref count == 0"); + } else { + dbusSignalMatchRuleReferenceCount--; + } + + const bool isLastDBusSignalMatchRuleReference = (dbusSignalMatchRuleReferenceCount == 0); + if (isLastDBusSignalMatchRuleReference) { + if (isConnected() && !removeLibdbusSignalMatchRule(dbusBusName)) { + return false; + } + dbusOMSignalMatchRulesMap_.erase(dbusSignalMatchRuleIterator); + } + return true; } /** @@ -1607,7 +1722,7 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { } // object manager match rules (see DBusServiceRegistry) - for (const auto& dbusObjectManagerSignalMatchRuleIterator : dbusObjectManagerSignalMatchRulesMap_) { + for (const auto& dbusObjectManagerSignalMatchRuleIterator : dbusOMSignalMatchRulesMap_) { const std::string& dbusBusName = dbusObjectManagerSignalMatchRuleIterator.first; const bool libdbusSuccess = addObjectManagerSignalMatchRule(dbusBusName); if (!libdbusSuccess) { @@ -1634,44 +1749,72 @@ void DBusConnection::initLibdbusSignalFilterAfterConnect() { void DBusConnection::notifyDBusSignalHandlers(DBusSignalHandlerPath handlerPath, const DBusMessage& dbusMessage, ::DBusHandlerResult& dbusHandlerResult) { - - // mutex of signal entry must be locked first to avoid potential deadlock - DBusSignalHandlerTable::iterator signalEntry; - bool entryFound = false; - std::shared_ptr<std::recursive_mutex> signalEntryMutex; { - std::lock_guard<std::mutex> itsLock(signalGuard_); - signalEntry = dbusSignalHandlerTable_.find(handlerPath); + std::lock_guard<std::mutex> dbusSignalHandlersLock(signalHandlersGuard_); - if(signalEntry != dbusSignalHandlerTable_.end()) { - signalEntryMutex = signalEntry->second.first; - entryFound = true; + // remove signal handlers + auto signalHandlerPathToRemoveIt = dbusSignalHandlersToRemove_.find(handlerPath); + if(signalHandlerPathToRemoveIt != dbusSignalHandlersToRemove_.end()) { + + for(auto handlerToRemoveIt = signalHandlerPathToRemoveIt->second.begin(); + handlerToRemoveIt != signalHandlerPathToRemoveIt->second.end(); + ++handlerToRemoveIt) { + + auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); + if(signalHandlerPathIt != dbusSignalHandlers_.end()) { + auto signalHandlerIt = signalHandlerPathIt->second.find(handlerToRemoveIt->first); + if(signalHandlerIt != signalHandlerPathIt->second.end()) { + signalHandlerPathIt->second.erase(signalHandlerIt); + } + } + } + auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); + if(signalHandlerPathIt != dbusSignalHandlers_.end() && + signalHandlerPathIt->second.empty()) { + dbusSignalHandlers_.erase(handlerPath); + } + dbusSignalHandlersToRemove_.erase(signalHandlerPathToRemoveIt); } - } - if(entryFound) { - signalEntryMutex->lock(); - std::lock_guard<std::mutex> itsLock(signalGuard_); - signalEntry = dbusSignalHandlerTable_.find(handlerPath); + // add signal handlers + auto signalHandlerPathToAddIt = dbusSignalHandlersToAdd_.find(handlerPath); + if(signalHandlerPathToAddIt != dbusSignalHandlersToAdd_.end()) { + + for(auto handlerToAddIt = signalHandlerPathToAddIt->second.begin(); + handlerToAddIt != signalHandlerPathToAddIt->second.end(); + ++handlerToAddIt) { + + auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); + if(signalHandlerPathIt == dbusSignalHandlers_.end()) { + + std::map<DBusSignalHandler*, std::weak_ptr<DBusSignalHandler>> handlerList; + handlerList[handlerToAddIt->first] = handlerToAddIt->second; + + dbusSignalHandlers_.insert( { + handlerPath, + std::move(handlerList) + } ); + } else { + signalHandlerPathIt->second[handlerToAddIt->first] = handlerToAddIt->second; + } + } + dbusSignalHandlersToAdd_.erase(signalHandlerPathToAddIt); + } } // ensure, the registry survives std::shared_ptr<DBusServiceRegistry> itsRegistry_ = DBusServiceRegistry::get(shared_from_this()); - if(entryFound && - signalEntry != dbusSignalHandlerTable_.end() && - !signalEntry->second.second.empty()) { - - // copy signal handlers - auto dbusSignalhandlers = signalEntry->second.second; - signalEntryMutex->unlock(); - - auto handlerEntry = dbusSignalhandlers.begin(); - while (handlerEntry != dbusSignalhandlers.end()) { - std::weak_ptr<DBusProxyConnection::DBusSignalHandler> dbusSignalHandler = handlerEntry->second; - if(auto itsHandler = dbusSignalHandler.lock()) + // notify + auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); + if(signalHandlerPathIt != dbusSignalHandlers_.end()) { + for(auto handlerIt = signalHandlerPathIt->second.begin(); + handlerIt != signalHandlerPathIt->second.end(); + ++handlerIt) { + std::weak_ptr<DBusProxyConnection::DBusSignalHandler> dbusSignalHandler = handlerIt->second; + if(auto itsHandler = dbusSignalHandler.lock()) { itsHandler->onSignalDBusMessage(dbusMessage); - handlerEntry++; + } } } dbusHandlerResult = DBUS_HANDLER_RESULT_HANDLED; @@ -1680,23 +1823,63 @@ void DBusConnection::notifyDBusSignalHandlers(DBusSignalHandlerPath handlerPath, void DBusConnection::notifyDBusOMSignalHandlers(const char* dbusSenderName, const DBusMessage& dbusMessage, ::DBusHandlerResult& dbusHandlerResult) { - std::vector<std::weak_ptr<DBusProxyConnection::DBusSignalHandler>> dbusOMSignalHandlers; { - std::lock_guard<std::mutex> itsLock(dbusObjectManagerSignalGuard_); - auto equalRange = dbusObjectManagerSignalHandlerTable_.equal_range(dbusSenderName); + std::lock_guard<std::mutex> dbusOMSignalHandlersLock(dbusOMSignalHandlersGuard_); + + // remove signal handlers + auto signalHandlerPathToRemoveIt = dbusOMSignalHandlersToRemove_.find(dbusSenderName); + if(signalHandlerPathToRemoveIt != dbusOMSignalHandlersToRemove_.end()) { - if (equalRange.first != equalRange.second) { - dbusHandlerResult = DBUS_HANDLER_RESULT_HANDLED; + auto signalHandlerPathIt = dbusOMSignalHandlers_.find(dbusSenderName); + if(signalHandlerPathIt != dbusOMSignalHandlers_.end()) { + + if(signalHandlerPathToRemoveIt->second.first == + signalHandlerPathIt->second.first) { + dbusOMSignalHandlers_.erase(signalHandlerPathIt); + dbusOMSignalHandlersToRemove_.erase(signalHandlerPathToRemoveIt); + } else { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signal handler can not be removed ", dbusSenderName); + return; + } + } } - while (equalRange.first != equalRange.second) { - dbusOMSignalHandlers.push_back(equalRange.first->second.second); - equalRange.first++; + + // add signal handlers + auto signalHandlerPathToAddIt = dbusOMSignalHandlersToAdd_.find(dbusSenderName); + if(signalHandlerPathToAddIt != dbusOMSignalHandlersToAdd_.end()) { + + auto signalHandlerPathIt = dbusOMSignalHandlers_.find(dbusSenderName); + if(signalHandlerPathIt == dbusOMSignalHandlers_.end()) { + + dbusOMSignalHandlers_.insert( { + dbusSenderName, + std::move(signalHandlerPathToAddIt->second) + } ); + + } else { + if(signalHandlerPathToAddIt->second.first == + signalHandlerPathIt->second.first) { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signal handler already added for ", dbusSenderName); + return; + } else { + COMMONAPI_ERROR(std::string(__FUNCTION__), " signal handler is trying to be added but " + "a signal handler is already added for", dbusSenderName); + return; + } + } + dbusOMSignalHandlersToAdd_.erase(signalHandlerPathToAddIt); } } - for(auto it = dbusOMSignalHandlers.begin(); it != dbusOMSignalHandlers.end(); ++it) { - if(auto itsHandler = it->lock()) + dbusHandlerResult = DBUS_HANDLER_RESULT_HANDLED; + + // notify + auto signalHandlerPathIt = dbusOMSignalHandlers_.find(dbusSenderName); + if(signalHandlerPathIt != dbusOMSignalHandlers_.end()) { + std::weak_ptr<DBusProxyConnection::DBusSignalHandler> dbusSignalHandler = signalHandlerPathIt->second.second; + if(auto itsHandler = dbusSignalHandler.lock()) { itsHandler->onSignalDBusMessage(dbusMessage); + } } } @@ -1844,5 +2027,19 @@ void DBusConnection::deleteAsyncHandlers() { } } +uint32_t DBusConnection::getNumberOfSignalMemberHandlers(DBusSignalHandlerPath handlerPath) { + uint32_t handlers, handlersToAdd, handlersToRemove; + + auto signalHandlerPathIt = dbusSignalHandlers_.find(handlerPath); + auto signalHandlerPathToAddIt = dbusSignalHandlersToAdd_.find(handlerPath); + auto signalHandlerPathToRemoveIt = dbusSignalHandlersToRemove_.find(handlerPath); + + (signalHandlerPathIt != dbusSignalHandlers_.end()) ? handlers = (uint32_t)signalHandlerPathIt->second.size() : handlers = 0; + (signalHandlerPathToAddIt != dbusSignalHandlersToAdd_.end()) ? handlersToAdd = (uint32_t)signalHandlerPathToAddIt->second.size() : handlersToAdd = 0; + (signalHandlerPathToRemoveIt != dbusSignalHandlersToRemove_.end()) ? handlersToRemove = (uint32_t)signalHandlerPathToRemoveIt->second.size() : handlersToRemove = 0; + + return handlers - handlersToRemove + handlersToAdd; +} + } // namespace DBus } // namespace CommonAPI diff --git a/src/CommonAPI/DBus/DBusFactory.cpp b/src/CommonAPI/DBus/DBusFactory.cpp index 99f7e8e..0d10c61 100644 --- a/src/CommonAPI/DBus/DBusFactory.cpp +++ b/src/CommonAPI/DBus/DBusFactory.cpp @@ -182,6 +182,7 @@ Factory::registerStub( bool Factory::unregisterStub(const std::string &_domain, const std::string &_interface, const std::string &_instance) { CommonAPI::Address address(_domain, _interface, _instance); + std::unique_lock<std::recursive_mutex> itsLock(servicesMutex_); const auto &adapterResult = services_.find(address.getAddress()); if (adapterResult != services_.end()) { const auto _adapter = adapterResult->second; @@ -202,6 +203,8 @@ Factory::unregisterStub(const std::string &_domain, const std::string &_interfac services_.erase(adapterResult->first); + itsLock.unlock(); + decrementConnection(connection); return true; @@ -215,6 +218,7 @@ Factory::registerStubAdapter(std::shared_ptr<DBusStubAdapter> _adapter) { CommonAPI::Address address; DBusAddress dbusAddress = _adapter->getDBusAddress(); if (DBusAddressTranslator::get()->translate(dbusAddress, address)) { + std::lock_guard<std::recursive_mutex> itsLock(servicesMutex_); const auto &insertResult = services_.insert( { address.getAddress(), _adapter } ); const auto &connection = _adapter->getDBusConnection(); @@ -338,6 +342,7 @@ Factory::getConnection(std::shared_ptr<MainLoopContext> _context) { /////////////////////////////////////////////////////////////////////////////// std::shared_ptr<DBusStubAdapter> Factory::getRegisteredService(const std::string &_address) { + std::lock_guard<std::recursive_mutex> itsLock(servicesMutex_); auto serviceIterator = services_.find(_address); if (serviceIterator != services_.end()) { return serviceIterator->second; @@ -370,6 +375,7 @@ bool Factory::registerManagedService(const std::shared_ptr<DBusStubAdapter> &_stubAdapter) { auto itsAddress = _stubAdapter->getAddress().getAddress(); + std::lock_guard<std::recursive_mutex> itsLock(servicesMutex_); const auto &insertResult = services_.insert( { itsAddress, _stubAdapter} ); if (insertResult.second) { const auto &connection = _stubAdapter->getDBusConnection(); @@ -401,11 +407,8 @@ Factory::registerManagedService(const std::shared_ptr<DBusStubAdapter> &_stubAda bool Factory::unregisterManagedService(const std::string &_address) { - return unregisterManagedService(services_.find(_address)); -} - -bool -Factory::unregisterManagedService(const ServicesMap::iterator &iterator) { + std::unique_lock<std::recursive_mutex> itsLock(servicesMutex_); + const ServicesMap::iterator iterator = services_.find(_address); if (iterator == services_.end()) return true; @@ -419,6 +422,7 @@ Factory::unregisterManagedService(const ServicesMap::iterator &iterator) { if (isUnregistered) { connection->releaseServiceName(serviceName); services_.erase(iterator); + itsLock.unlock(); decrementConnection(connection); } // TODO: log error diff --git a/src/dbus-patches/capi-dbus-1-pc.patch b/src/dbus-patches/capi-dbus-1-pc.patch new file mode 100644 index 0000000..c49a791 --- /dev/null +++ b/src/dbus-patches/capi-dbus-1-pc.patch @@ -0,0 +1,9 @@ +diff --git a/dbus-1.pc.in b/dbus-1.pc.in +index f93d156..2e137cf 100644 +--- a/dbus-1.pc.in ++++ b/dbus-1.pc.in +@@ -18,3 +18,4 @@ Version: @VERSION@ + Libs: -L${libdir} -ldbus-1 + Libs.private: @LIBDBUS_LIBS@ + Cflags: -I${includedir}/dbus-1.0 -I${libdir}/dbus-1.0/include @DBUS_STATIC_BUILD_CPPFLAGS@ ++Ldflags: -L${libdir} |