]> granicus.if.org Git - icinga2/commitdiff
Refactored object locking code.
authorGunnar Beutner <gunnar.beutner@netways.de>
Fri, 1 Mar 2013 11:07:52 +0000 (12:07 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Fri, 1 Mar 2013 11:07:52 +0000 (12:07 +0100)
52 files changed:
components/checker/checkercomponent.cpp
components/compat/compatcomponent.cpp
components/delegation/delegationcomponent.cpp
components/delegation/delegationcomponent.h
components/notification/notificationcomponent.cpp
components/replication/replicationcomponent.cpp
lib/base/application.cpp
lib/base/application.h
lib/base/asynctask.h
lib/base/component.cpp
lib/base/dictionary.cpp
lib/base/dictionary.h
lib/base/dynamicobject.cpp
lib/base/dynamictype.cpp
lib/base/dynamictype.h
lib/base/logger.cpp
lib/base/logger.h
lib/base/object.cpp
lib/base/object.h
lib/base/objectlock.cpp
lib/base/objectlock.h
lib/base/process-unix.cpp
lib/base/process.cpp
lib/base/ringbuffer.cpp
lib/base/ringbuffer.h
lib/base/script.cpp
lib/base/scriptfunction.cpp
lib/base/scriptfunction.h
lib/base/scriptinterpreter.cpp
lib/base/scripttask.cpp
lib/base/stdiostream.cpp
lib/base/timer.cpp
lib/base/timer.h
lib/config/configitem.cpp
lib/config/configtype.cpp
lib/config/expression.cpp
lib/icinga/cib.cpp
lib/icinga/host.cpp
lib/icinga/hostgroup.cpp
lib/icinga/icingaapplication.cpp
lib/icinga/notification.cpp
lib/icinga/perfdatawriter.cpp
lib/icinga/pluginchecktask.cpp
lib/icinga/pluginnotificationtask.cpp
lib/icinga/service-check.cpp
lib/icinga/service-notification.cpp
lib/icinga/service.cpp
lib/icinga/servicegroup.cpp
lib/icinga/user.cpp
lib/icinga/usergroup.cpp
lib/remoting/endpoint.cpp
lib/remoting/endpointmanager.cpp

index 41f20d7da3c4b77bfbc9a2cff43e5a7e5d3c4fa0..75157c2b10399715bcf974b455e78657126acd4a 100644 (file)
@@ -27,9 +27,13 @@ void CheckerComponent::Start(void)
 {
        m_Endpoint = Endpoint::MakeEndpoint("checker", false);
 
-       /* dummy registration so the delegation module knows this is a checker
-          TODO: figure out a better way for this */
-       m_Endpoint->RegisterSubscription("checker");
+       {
+               ObjectLock olock(m_Endpoint);
+
+               /* dummy registration so the delegation module knows this is a checker
+                  TODO: figure out a better way for this */
+               m_Endpoint->RegisterSubscription("checker");
+       }
 
        Service::OnCheckerChanged.connect(bind(&CheckerComponent::CheckerChangedHandler, this, _1));
        Service::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1));
@@ -46,7 +50,10 @@ void CheckerComponent::Start(void)
 
 void CheckerComponent::Stop(void)
 {
-       m_Endpoint->Unregister();
+       {
+               ObjectLock olock(m_Endpoint);
+               m_Endpoint->Unregister();
+       }
 
        {
                boost::mutex::scoped_lock lock(m_Mutex);
@@ -74,12 +81,13 @@ void CheckerComponent::CheckThreadProc(void)
                CheckTimeView::iterator it = idx.begin();
                Service::Ptr service = *it;
 
+               ObjectLock olock(service); /* also required for the key extractor. */
+
                if (!service->IsRegistered()) {
                        idx.erase(it);
                        continue;
                }
 
-               ObjectLock olock(service); /* also required for the key extractor. */
                double wait;
 
                {
@@ -129,7 +137,15 @@ void CheckerComponent::CheckThreadProc(void)
 
                try {
                        olock.Unlock();
-                       Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, static_cast<CheckerComponent::Ptr>(GetSelf()), service));
+
+                       CheckerComponent::Ptr self;
+
+                       {
+                               ObjectLock olock(this);
+                               self = GetSelf();
+                       }
+
+                       Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, static_cast<CheckerComponent::Ptr>(self), service));
                } catch (const exception& ex) {
                        olock.Lock();
                        Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex));
@@ -178,7 +194,16 @@ void CheckerComponent::CheckerChangedHandler(const Service::Ptr& service)
        ObjectLock olock(service); /* also required for the key extractor */
        String checker = service->GetCurrentChecker();
 
-       if (checker == EndpointManager::GetInstance()->GetIdentity() || checker == m_Endpoint->GetName()) {
+       EndpointManager::Ptr em = EndpointManager::GetInstance();
+
+       String identity;
+
+       {
+               ObjectLock elock(em);
+               identity = em->GetIdentity();
+       }
+
+       if (checker == identity || Endpoint::GetByName(checker) == m_Endpoint) {
                if (m_PendingServices.find(service) != m_PendingServices.end())
                        return;
 
index 0740d60f3c887d88a771f2c1b5f732976901de06..13520301dd7c1d8d426d8dd56533b76d9013bf1c 100644 (file)
@@ -36,7 +36,11 @@ REGISTER_COMPONENT("compat", CompatComponent);
  */
 String CompatComponent::GetStatusPath(void) const
 {
-       Value statusPath = GetConfig()->Get("status_path");
+       DynamicObject::Ptr config = GetConfig();
+
+       ObjectLock olock(config);
+
+       Value statusPath = config->Get("status_path");
        if (statusPath.IsEmpty())
                return Application::GetLocalStateDir() + "/cache/icinga2/status.dat";
        else
@@ -50,7 +54,11 @@ String CompatComponent::GetStatusPath(void) const
  */
 String CompatComponent::GetObjectsPath(void) const
 {
-       Value objectsPath = GetConfig()->Get("objects_path");
+       DynamicObject::Ptr config = GetConfig();
+
+       ObjectLock olock(config);
+
+       Value objectsPath = config->Get("objects_path");
        if (objectsPath.IsEmpty())
                return Application::GetLocalStateDir() + "/cache/icinga2/objects.cache";
        else
@@ -64,7 +72,11 @@ String CompatComponent::GetObjectsPath(void) const
  */
 String CompatComponent::GetLogPath(void) const
 {
-       Value logPath = GetConfig()->Get("log_path");
+       DynamicObject::Ptr config = GetConfig();
+
+       ObjectLock olock(config);
+
+       Value logPath = config->Get("log_path");
        if (logPath.IsEmpty())
                return Application::GetLocalStateDir() + "/log/icinga2/compat";
        else
@@ -78,7 +90,11 @@ String CompatComponent::GetLogPath(void) const
  */
 String CompatComponent::GetCommandPath(void) const
 {
-       Value commandPath = GetConfig()->Get("command_path");
+       DynamicObject::Ptr config = GetConfig();
+
+       ObjectLock olock(config);
+
+       Value commandPath = config->Get("command_path");
        if (commandPath.IsEmpty())
                return Application::GetLocalStateDir() + "/run/icinga.cmd";
        else
@@ -214,31 +230,48 @@ void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, Compa
 
 void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, CompatObjectType type)
 {
-       ObjectLock olock(owner);
+       Dictionary::Ptr downtimes;
+       String short_name, host_name;
+       Host::Ptr host;
 
-       Dictionary::Ptr downtimes = owner->GetDowntimes();
+       {
+               ObjectLock olock(owner);
+
+               downtimes = owner->GetDowntimes();
+               short_name = owner->GetShortName();
+               host = owner->GetHost();
+       }
+
+       {
+               ObjectLock olock(host);
+               host_name = host->GetName();
+       }
 
        if (!downtimes)
                return;
 
+       ObjectLock dlock(downtimes);
+
        String id;
        Dictionary::Ptr downtime;
        BOOST_FOREACH(tie(id, downtime), downtimes) {
                if (Service::IsDowntimeExpired(downtime))
                        continue;
 
+               ObjectLock olock(downtime);
+
                if (type == CompatTypeHost)
                        fp << "hostdowntime {" << "\n";
                else
                        fp << "servicedowntime {" << "\n"
-                          << "\t" << "service_description=" << owner->GetShortName() << "\n";
+                          << "\t" << "service_description=" << short_name << "\n";
 
                Dictionary::Ptr triggeredByObj = Service::GetDowntimeByID(downtime->Get("triggered_by"));
                int triggeredByLegacy = 0;
                if (triggeredByObj)
                        triggeredByLegacy = triggeredByObj->Get("legacy_id");
 
-               fp << "\t" << "host_name=" << owner->GetHost()->GetName() << "\n"
+               fp << "\t" << "host_name=" << host_name << "\n"
                   << "\t" << "downtime_id=" << static_cast<String>(downtime->Get("legacy_id")) << "\n"
                   << "\t" << "entry_time=" << static_cast<double>(downtime->Get("entry_time")) << "\n"
                   << "\t" << "start_time=" << static_cast<double>(downtime->Get("start_time")) << "\n"
@@ -357,6 +390,8 @@ void CompatComponent::DumpServiceStatusAttrs(ostream& fp, const Service::Ptr& se
        }
 
        if (cr) {
+               ObjectLock olock(cr);
+
                output = cr->Get("output");
                schedule_end = cr->Get("schedule_end");
                perfdata = cr->Get("performance_data_raw");
index b62c0896d0185aaa56150e7138bc96106849b580..98a3fb0f86783e734087320a6dd1272b721400f7 100644 (file)
@@ -27,22 +27,14 @@ REGISTER_COMPONENT("delegation", DelegationComponent);
 void DelegationComponent::Start(void)
 {
        m_DelegationTimer = boost::make_shared<Timer>();
+
        // TODO: implement a handler for config changes for the delegation_interval variable
-       m_DelegationTimer->SetInterval(GetDelegationInterval());
+       m_DelegationTimer->SetInterval(30);
        m_DelegationTimer->OnTimerExpired.connect(boost::bind(&DelegationComponent::DelegationTimerHandler, this));
        m_DelegationTimer->Start();
        m_DelegationTimer->Reschedule(Utility::GetTime() + 10);
 }
 
-double DelegationComponent::GetDelegationInterval(void) const
-{
-       Value interval = GetConfig()->Get("delegation_interval");
-       if (interval.IsEmpty())
-               return 30;
-       else
-               return interval;
-}
-
 bool DelegationComponent::IsEndpointChecker(const Endpoint::Ptr& endpoint)
 {
        return (endpoint->HasSubscription("checker"));
@@ -211,6 +203,8 @@ void DelegationComponent::DelegationTimerHandler(void)
        Endpoint::Ptr endpoint;
        int count;
        BOOST_FOREACH(tie(endpoint, count), histogram) {
+               ObjectLock olock(endpoint);
+
                stringstream msgbuf;
                msgbuf << "histogram: " << endpoint->GetName() << " - " << count;
                Logger::Write(LogInformation, "delegation", msgbuf.str());
index 655feb1924de732d612d5ae073b39c8b74153827..c42556df5a836eb99b8d12cc9092400e8c8ce1ec 100644 (file)
@@ -39,8 +39,6 @@ private:
        set<Endpoint::Ptr> GetCheckerCandidates(const Service::Ptr& service) const;
 
        static bool IsEndpointChecker(const Endpoint::Ptr& endpoint);
-
-       double GetDelegationInterval(void) const;
 };
 
 }
index 0d5b44dd8497b4c038e019fb79810660562c4836..f8f6018d5adc0e6b272f5e45f940ec23d4c90fd5 100644 (file)
@@ -30,10 +30,12 @@ void NotificationComponent::Start(void)
 {
        m_Endpoint = Endpoint::MakeEndpoint("notification", false);
 
-       ObjectLock olock(m_Endpoint);
-       m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
-           boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
-           _3));
+       {
+               ObjectLock olock(m_Endpoint);
+               m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
+                   boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
+                   _3));
+       }
 
        m_NotificationTimer = boost::make_shared<Timer>();
        m_NotificationTimer->SetInterval(5);
index 70dd403e46c7b6af3f2baf5ec86757abe1f1e181..935c3301e087af54f87ccb82bdb00a4fcf854438 100644 (file)
@@ -222,7 +222,7 @@ void ReplicationComponent::RemoteObjectUpdateHandler(const RequestMessage& reque
        // TODO: sanitize update, disallow __local
 
        if (!object) {
-               object = dtype->CreateObject(update);
+               object = DynamicType::CreateObject(dtype, update);
 
                if (source == EndpointManager::GetInstance()->GetIdentity()) {
                        /* the peer sent us an object that was originally created by us -
index 75d234acd3b96a0377b72c2039a9027821be42b8..3ccf0e32be2804b857f5d4c6fa103756654664f9 100644 (file)
@@ -79,12 +79,9 @@ Application::~Application(void)
  *
  * @returns The application object.
  */
-Application::Ptr Application::GetInstance(void)
+Application *Application::GetInstance(void)
 {
-       if (m_Instance)
-               return m_Instance->GetSelf();
-       else
-               return Application::Ptr();
+       return m_Instance;
 }
 
 int Application::GetArgC(void)
@@ -110,6 +107,7 @@ void Application::SetArgV(char **argv)
 void Application::ShutdownTimerHandler(void)
 {
        if (m_ShuttingDown) {
+               Logger::Write(LogInformation, "base", "Shutting down Icinga...");
                Application::GetInstance()->OnShutdown();
                DynamicObject::DeactivateObjects();
                GetEQ().Stop();
@@ -177,14 +175,6 @@ void Application::RequestShutdown(void)
        m_ShuttingDown = true;
 }
 
-/**
- * Terminates the application.
- */
-void Application::Terminate(int exitCode)
-{
-       _exit(exitCode);
-}
-
 /**
  * Retrieves the full path of the executable.
  *
@@ -295,7 +285,7 @@ void Application::SigIntHandler(int signum)
 {
        assert(signum == SIGINT);
 
-       Application::Ptr instance = Application::GetInstance();
+       Application *instance = Application::GetInstance();
 
        if (!instance)
                return;
@@ -330,12 +320,12 @@ void Application::SigAbrtHandler(int signum)
  */
 BOOL WINAPI Application::CtrlHandler(DWORD type)
 {
-       Application::Ptr instance = Application::GetInstance();
+       Application *instance = Application::GetInstance();
 
        if (!instance)
                return TRUE;
 
-       instance->GetInstance()->RequestShutdown();
+       instance->RequestShutdown();
 
        SetConsoleCtrlHandler(NULL, FALSE);
        return TRUE;
index a8a7c1c792d28f8d4dbc2fbe8d4cedd92b8eafb1..ddfc2c322e9aafa3fe160bb2d4610e9ac1b6f6de 100644 (file)
@@ -37,7 +37,7 @@ public:
        Application(const Dictionary::Ptr& serializedUpdate);
        ~Application(void);
 
-       static Application::Ptr GetInstance(void);
+       static Application *GetInstance(void);
 
        int Run(void);
 
@@ -57,7 +57,6 @@ public:
        static void InstallExceptionHandlers(void);
 
        static void RequestShutdown(void);
-       static void Terminate(int exitCode);
 
        static void SetDebugging(bool debug);
        static bool IsDebugging(void);
index af2f4ca8ab5a76590181aec056e2599032b1ad51..ecaf6efc6560ca95d825a189b960f61c916f38e4 100644 (file)
@@ -62,32 +62,44 @@ public:
        /**
         * Starts the async task. The caller must hold a reference to the AsyncTask
         * object until the completion callback is invoked.
+        *
+        * @threadsafety Always.
         */
        void Start(const CompletionCallback& completionCallback = CompletionCallback())
        {
+               assert(!OwnsLock());
+               boost::mutex::scoped_lock lock(m_Mutex);
+
                m_CompletionCallback = completionCallback;
                Utility::QueueAsyncCallback(boost::bind(&AsyncTask<TClass, TResult>::RunInternal, this));
        }
 
        /**
         * Checks whether the task is finished.
+        *
+        * @threadsafety Always.
         */
        bool IsFinished(void) const
        {
+               assert(!OwnsLock());
                boost::mutex::scoped_lock lock(m_Mutex);
                return m_Finished;
        }
 
        /**
-        * Retrieves the result of the task. Throws an exception if one is stored in
+        * Blocks until the task is completed and retrieves the result. Throws an exception if one is stored in
         * the AsyncTask object.
         *
         * @returns The task's result.
+        * @threadsafety Always.
         */
        TResult GetResult(void)
        {
-               if (!m_Finished)
-                       BOOST_THROW_EXCEPTION(runtime_error("GetResult called on an unfinished AsyncTask"));
+               assert(!OwnsLock());
+               boost::mutex::scoped_lock lock(m_Mutex);
+
+               while (!m_Finished)
+                       m_CV.wait(lock);
 
                if (m_ResultRetrieved)
                        BOOST_THROW_EXCEPTION(runtime_error("GetResult called on an AsyncTask whose result was already retrieved."));
@@ -106,9 +118,13 @@ public:
         * Finishes the task using an exception.
         *
         * @param ex The exception.
+        * @threadsafety Always.
         */
        void FinishException(const boost::exception_ptr& ex)
        {
+               assert(!OwnsLock());
+               boost::mutex::scoped_lock lock(m_Mutex);
+
                m_Exception = ex;
                FinishInternal();
        }
@@ -117,23 +133,17 @@ public:
         * Finishes the task using an ordinary result.
         *
         * @param result The result.
+        * @threadsafety Always.
         */
        void FinishResult(const TResult& result)
        {
+               assert(!OwnsLock());
+               boost::mutex::scoped_lock lock(m_Mutex);
+
                m_Result = result;
                FinishInternal();
        }
 
-       /**
-        * Blocks until the task is completed.
-        */
-       void Wait(void)
-       {
-               boost::mutex::scoped_lock lock(m_Mutex);
-               while (!m_Finished)
-                       m_CV.wait(lock);
-       }
-
 protected:
        /**
         * Begins executing the task. The Run method must ensure
@@ -146,24 +156,22 @@ private:
        /**
         * Finishes the task and causes the completion callback to be invoked. This
         * function must be called before the object is destroyed.
+        *
+        * @threadsafety Caller must hold m_Mutex.
         */
        void FinishInternal(void)
        {
-               CompletionCallback callback;
-
-               {
-                       boost::mutex::scoped_lock lock(m_Mutex);
-                       assert(!m_Finished);
+               assert(!m_Finished);
+               m_Finished = true;
+               m_CV.notify_all();
 
-                       m_Finished = true;
-
-                       m_CV.notify_all();
 
+               if (!m_CompletionCallback.empty()) {
+                       CompletionCallback callback;
                        m_CompletionCallback.swap(callback);
-               }
 
-               if (!callback.empty())
                        Utility::QueueAsyncCallback(boost::bind(callback, GetSelf()));
+               }
        }
 
        /**
index bc503d67b7780b49cdf84d94b2d141ad7fd07fe5..f72a35cc4523290ea8d70eab7afe660e2f9821f9 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Component, NULL);
+REGISTER_TYPE(Component);
 
 map<String, Component::Factory> Component::m_Factories;
 
index 6657959d2844a963e0c00b4ae0d04edfd46121de..c6bf399b8bd905a025b3c0ce140e0c4e6457893f 100644 (file)
@@ -152,6 +152,8 @@ String Dictionary::Add(const Value& value)
  */
 Dictionary::Iterator Dictionary::Begin(void)
 {
+       assert(OwnsLock());
+
        return m_Data.begin();
 }
 
@@ -162,6 +164,8 @@ Dictionary::Iterator Dictionary::Begin(void)
  */
 Dictionary::Iterator Dictionary::End(void)
 {
+       assert(OwnsLock());
+
        return m_Data.end();
 }
 
@@ -218,6 +222,8 @@ void Dictionary::Remove(const String& key)
  */
 void Dictionary::Remove(Dictionary::Iterator it)
 {
+       ObjectLock olock(this);
+
        String key = it->first;
        m_Data.erase(it);
 }
@@ -228,9 +234,23 @@ void Dictionary::Remove(Dictionary::Iterator it)
  */
 void Dictionary::Seal(void)
 {
+       ObjectLock olock(this);
+
        m_Sealed = true;
 }
 
+/**
+ * Checks whether the dictionary is sealed.
+ *
+ * @returns true if the dictionary is sealed, false otherwise.
+ */
+bool Dictionary::IsSealed(void) const
+{
+       ObjectLock olock(this);
+
+       return m_Sealed;
+}
+
 /**
  * Makes a shallow copy of a dictionary.
  *
@@ -270,6 +290,8 @@ Dictionary::Ptr Dictionary::FromJson(cJSON *json)
                dictionary->Set(i->string, Value::FromJson(i));
        }
 
+       dictionary->Seal();
+
        return dictionary;
 }
 
index d2921df22fbf9eace5ef0fb662bf9a154b66d771..ffe6c49adb835fbcd4d0d921a3b5546dd0e67fae 100644 (file)
@@ -46,7 +46,9 @@ public:
        void Set(const String& key, const Value& value);
        String Add(const Value& value);
        bool Contains(const String& key) const;
+
        void Seal(void);
+       bool IsSealed(void) const;
 
        Iterator Begin(void);
        Iterator End(void);
index e7ae7bd21011c6035071999180bf9b392d72b009..374423b1fe55d3c0752f240dc4ca299dde03b99e 100644 (file)
@@ -42,20 +42,13 @@ DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
        RegisterAttribute("__source", Attribute_Local, &m_Source);
        RegisterAttribute("methods", Attribute_Config, &m_Methods);
 
-       {
-               ObjectLock olock(serializedObject);
-
-               if (!serializedObject->Contains("configTx"))
-                       BOOST_THROW_EXCEPTION(invalid_argument("Serialized object must contain a config snapshot."));
-       }
+       if (!serializedObject->Contains("configTx"))
+               BOOST_THROW_EXCEPTION(invalid_argument("Serialized object must contain a config snapshot."));
 
        /* apply config state from the config item/remote update;
         * The DynamicType::CreateObject function takes care of restoring
         * non-config state after the object has been fully constructed */
-       {
-               ObjectLock olock(this);
-               ApplyUpdate(serializedObject, Attribute_Config);
-       }
+       ApplyUpdate(serializedObject, Attribute_Config);
 
        boost::call_once(m_TransactionOnce, &DynamicObject::Initialize);
 }
@@ -77,6 +70,8 @@ void DynamicObject::Initialize(void)
 
 Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) const
 {
+       assert(OwnsLock());
+
        DynamicObject::AttributeConstIterator it;
 
        Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
@@ -120,23 +115,22 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
 void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
     int allowedTypes)
 {
-       Dictionary::Ptr attrs;
+       assert(OwnsLock());
+       assert(serializedUpdate->IsSealed());
 
-       {
-               ObjectLock olock(serializedUpdate);
+       Value configTxValue = serializedUpdate->Get("configTx");
 
-               double configTx = 0;
-               if ((allowedTypes & Attribute_Config) != 0 &&
-                   serializedUpdate->Contains("configTx")) {
-                       configTx = serializedUpdate->Get("configTx");
-
-                       if (configTx > m_ConfigTx)
-                               ClearAttributesByType(Attribute_Config);
-               }
+       if ((allowedTypes & Attribute_Config) != 0 && !configTxValue.IsEmpty()) {
+               double configTx = configTxValue;
 
-               attrs = serializedUpdate->Get("attrs");
+               if (configTx > m_ConfigTx)
+                       ClearAttributesByType(Attribute_Config);
        }
 
+       Dictionary::Ptr attrs = serializedUpdate->Get("attrs");
+
+       assert(attrs->IsSealed());
+
        {
                ObjectLock olock(attrs);
 
@@ -146,7 +140,8 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
                                continue;
 
                        Dictionary::Ptr attr = it->second;
-                       ObjectLock alock(attr);
+
+                       assert(attr->IsSealed());
 
                        int type = attr->Get("type");
 
@@ -170,6 +165,8 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
 void DynamicObject::RegisterAttribute(const String& name,
     AttributeType type, AttributeBase *boundAttribute)
 {
+       assert(OwnsLock());
+
        AttributeHolder attr(type, boundAttribute);
 
        pair<DynamicObject::AttributeIterator, bool> tt;
@@ -183,24 +180,38 @@ void DynamicObject::RegisterAttribute(const String& name,
        }
 }
 
+/**
+ * @threadsafety Always.
+ */
 void DynamicObject::Set(const String& name, const Value& data)
 {
        InternalSetAttribute(name, data, GetCurrentTx());
 }
 
+/**
+ * @threadsafety Always.
+ */
 void DynamicObject::Touch(const String& name)
 {
        InternalSetAttribute(name, InternalGetAttribute(name), GetCurrentTx());
 }
 
+/**
+ * @threadsafety Always.
+ */
 Value DynamicObject::Get(const String& name) const
 {
        return InternalGetAttribute(name);
 }
 
+/**
+ * @threadsafety Always.
+ */
 void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
     double tx, bool allowEditConfig)
 {
+       ObjectLock olock(this);
+
        DynamicObject::AttributeIterator it;
        it = m_Attributes.find(name);
 
@@ -242,8 +253,13 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
        m_ModifiedAttributes.insert(make_pair(name, oldValue));
 }
 
+/**
+ * @threadsafety Always.
+ */
 Value DynamicObject::InternalGetAttribute(const String& name) const
 {
+       ObjectLock olock(this);
+
        DynamicObject::AttributeConstIterator it;
        it = m_Attributes.find(name);
 
@@ -253,13 +269,20 @@ Value DynamicObject::InternalGetAttribute(const String& name) const
        return it->second.GetValue();
 }
 
+/**
+ * @threadsafety Always.
+ */
 bool DynamicObject::HasAttribute(const String& name) const
 {
+       ObjectLock olock(this);
+
        return (m_Attributes.find(name) != m_Attributes.end());
 }
 
 void DynamicObject::ClearAttributesByType(AttributeType type)
 {
+       assert(OwnsLock());
+
        DynamicObject::AttributeIterator at;
        for (at = m_Attributes.begin(); at != m_Attributes.end(); at++) {
                if (at->second.GetType() != type)
@@ -269,44 +292,81 @@ void DynamicObject::ClearAttributesByType(AttributeType type)
        }
 }
 
+/**
+ * @threadsafety Always.
+ */
 DynamicType::Ptr DynamicObject::GetType(void) const
 {
+       ObjectLock olock(this);
+
        return DynamicType::GetByName(m_Type);
 }
 
+/**
+ * @threadsafety Always.
+ */
 String DynamicObject::GetName(void) const
 {
+       ObjectLock olock(this);
+
        return m_Name;
 }
 
+/**
+ * @threadsafety Always.
+ */
 bool DynamicObject::IsLocal(void) const
 {
+       ObjectLock olock(this);
+
        return m_Local;
 }
 
+/**
+ * @threadsafety Always.
+ */
 bool DynamicObject::IsAbstract(void) const
 {
+       ObjectLock olock(this);
+
        return m_Abstract;
 }
 
+/**
+ * @threadsafety Always.
+ */
 bool DynamicObject::IsRegistered(void) const
 {
+       ObjectLock olock(this);
+
        return m_Registered;
 }
 
+/**
+ * @threadsafety Always.
+ */
 void DynamicObject::SetSource(const String& value)
 {
+       ObjectLock olock(this);
+
        m_Source = value;
        Touch("__source");
 }
 
+/**
+ * @threadsafety Always.
+ */
 String DynamicObject::GetSource(void) const
 {
+       ObjectLock olock(this);
+
        return m_Source;
 }
 
 void DynamicObject::Register(void)
 {
+       assert(OwnsLock());
+
        /* It's now safe to send us attribute events. */
        SetEventSafe(true);
 
@@ -352,11 +412,15 @@ void DynamicObject::OnRegistrationCompleted(void)
 
 void DynamicObject::Start(void)
 {
+       assert(OwnsLock());
+
        /* Nothing to do here. */
 }
 
 void DynamicObject::Unregister(void)
 {
+       assert(OwnsLock());
+
        DynamicType::Ptr dtype = GetType();
        ObjectLock olock(dtype);
 
@@ -371,17 +435,14 @@ void DynamicObject::Unregister(void)
 ScriptTask::Ptr DynamicObject::MakeMethodTask(const String& method,
     const vector<Value>& arguments)
 {
-       String funcName;
+       assert(OwnsLock());
 
        Dictionary::Ptr methods = m_Methods;
 
-       {
-               ObjectLock olock(methods);
-               if (!methods->Contains(method))
-                       return ScriptTask::Ptr();
+       String funcName = methods->Get(method);
 
-               funcName = methods->Get(method);
-       }
+       if (funcName.IsEmpty())
+               return ScriptTask::Ptr();
 
        ScriptFunction::Ptr func = ScriptFunction::GetByName(funcName);
 
@@ -409,15 +470,23 @@ void DynamicObject::DumpObjects(const String& filename)
        StdioStream::Ptr sfp = boost::make_shared<StdioStream>(&fp, false);
        sfp->Start();
 
-       ;
        BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
+               String type_name;
+
+               {
+                       ObjectLock olock(type);
+                       type_name = type->GetName();
+               }
+
                BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
+                       ObjectLock olock(object);
+
                        if (object->IsLocal())
                                continue;
 
                        Dictionary::Ptr persistentObject = boost::make_shared<Dictionary>();
 
-                       persistentObject->Set("type", object->GetType()->GetName());
+                       persistentObject->Set("type", type_name);
                        persistentObject->Set("name", object->GetName());
 
                        int types = Attribute_Local | Attribute_Replicated;
@@ -472,6 +541,8 @@ void DynamicObject::RestoreObjects(const String& filename)
        while (NetString::ReadStringFromStream(sfp, &message)) {
                Dictionary::Ptr persistentObject = Value::Deserialize(message);
 
+               assert(persistentObject->IsSealed());
+
                String type = persistentObject->Get("type");
                String name = persistentObject->Get("name");
                Dictionary::Ptr update = persistentObject->Get("update");
@@ -479,7 +550,6 @@ void DynamicObject::RestoreObjects(const String& filename)
                bool hasConfig = update->Contains("configTx");
 
                DynamicType::Ptr dt = DynamicType::GetByName(type);
-               ObjectLock dlock(dt);
 
                if (!dt)
                        BOOST_THROW_EXCEPTION(invalid_argument("Invalid type: " + type));
@@ -487,9 +557,11 @@ void DynamicObject::RestoreObjects(const String& filename)
                DynamicObject::Ptr object = dt->GetObject(name);
 
                if (hasConfig && !object) {
-                       object = dt->CreateObject(update);
+                       object = DynamicType::CreateObject(dt, update);
+                       ObjectLock olock(object);
                        object->Register();
                } else if (object) {
+                       ObjectLock olock(object);
                        object->ApplyUpdate(update, Attribute_All);
                }
 
@@ -506,14 +578,7 @@ void DynamicObject::RestoreObjects(const String& filename)
 void DynamicObject::DeactivateObjects(void)
 {
        BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
-               set<DynamicObject::Ptr> objects;
-
-               {
-                       ObjectLock olock(dt);
-                       objects = dt->GetObjects();
-               }
-
-               BOOST_FOREACH(const DynamicObject::Ptr& object, objects) {
+               BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
                        ObjectLock olock(object);
                        object->Unregister();
                }
@@ -563,14 +628,16 @@ void DynamicObject::NewTx(void)
                        continue;
 
                map<String, Value, string_iless> attrs;
+               bool event_safe;
 
                {
                        ObjectLock olock(object);
                        attrs.swap(object->m_ModifiedAttributes);
+                       event_safe = object->GetEventSafe();
                }
 
-               /* Check if it's safe to send events. */
-               if (object->GetEventSafe()) {
+               /* Send attribute events if it's safe to do so. */
+               if (event_safe) {
                        map<String, Value, string_iless>::iterator it;
                        for (it = attrs.begin(); it != attrs.end(); it++)
                                object->OnAttributeChanged(it->first, it->second);
@@ -589,24 +656,26 @@ void DynamicObject::OnAttributeChanged(const String&, const Value&)
 DynamicObject::Ptr DynamicObject::GetObject(const String& type, const String& name)
 {
        DynamicType::Ptr dtype = DynamicType::GetByName(type);
-
-       {
-               ObjectLock olock(dtype);
-               return dtype->GetObject(name);
-       }
+       return dtype->GetObject(name);
 }
 
 const DynamicObject::AttributeMap& DynamicObject::GetAttributes(void) const
 {
+       assert(OwnsLock());
+
        return m_Attributes;
 }
 
 void DynamicObject::SetEventSafe(bool safe)
 {
+       assert(OwnsLock());
+
        m_EventSafe = safe;
 }
 
 bool DynamicObject::GetEventSafe(void) const
 {
+       assert(OwnsLock());
+
        return m_EventSafe;
 }
index 8d3a23158c9e3ccb1c6f2394d3a5fca4e7b2f7a8..1cf5f21f1bc958dd7346a2fb305f35600c3741d1 100644 (file)
@@ -64,29 +64,28 @@ DynamicType::TypeSet DynamicType::GetTypes(void)
 set<DynamicObject::Ptr> DynamicType::GetObjects(const String& type)
 {
        DynamicType::Ptr dt = GetByName(type);
-       ObjectLock olock(dt);
        return dt->GetObjects();
 }
 
 set<DynamicObject::Ptr> DynamicType::GetObjects(void) const
 {
+       ObjectLock olock(this);
+
        return m_ObjectSet; /* Making a copy of the set here. */
 }
 
 String DynamicType::GetName(void) const
 {
+       ObjectLock olock(this);
+
        return m_Name;
 }
 
 void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
 {
-       String name;
-
-       {
-               ObjectLock olock(object);
-               name = object->GetName();
-       }
+       String name = object->GetName();
 
+       assert(OwnsLock());
        ObjectMap::iterator it = m_ObjectMap.find(name);
 
        if (it != m_ObjectMap.end()) {
@@ -107,12 +106,18 @@ void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
        ObjectLock olock(object);
        object->SetEventSafe(false);
 
+       assert(OwnsLock());
        m_ObjectMap.erase(object->GetName());
        m_ObjectSet.erase(object);
 }
 
+/**
+ * @threadsafety Always.
+ */
 DynamicObject::Ptr DynamicType::GetObject(const String& name) const
 {
+       ObjectLock olock(this);
+
        DynamicType::ObjectMap::const_iterator nt = m_ObjectMap.find(name);
 
        if (nt == m_ObjectMap.end())
@@ -138,18 +143,19 @@ void DynamicType::RegisterType(const DynamicType::Ptr& type)
        InternalGetTypeSet().insert(type);
 }
 
-DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) const
+DynamicObject::Ptr DynamicType::CreateObject(const DynamicType::Ptr& self, const Dictionary::Ptr& serializedUpdate)
 {
-       DynamicObject::Ptr object = m_ObjectFactory(serializedUpdate);
+       ObjectFactory factory;
 
        {
-               ObjectLock olock(object);
+               ObjectLock olock(self);
+               factory = self->m_ObjectFactory;
+       }
+
+       DynamicObject::Ptr object = factory(serializedUpdate);
 
-               /* register attributes */
-               String name;
-               AttributeType type;
-               BOOST_FOREACH(tuples::tie(name, type), m_Attributes)
-                       object->RegisterAttribute(name, type);
+       {
+               ObjectLock olock(object);
 
                /* apply the object's non-config attributes */
                object->ApplyUpdate(serializedUpdate, Attribute_All & ~Attribute_Config);
@@ -158,35 +164,6 @@ DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUp
        return object;
 }
 
-/**
- * @threadsafety Always.
- */
-bool DynamicType::TypeExists(const String& name)
-{
-       return (GetByName(name));
-}
-
-void DynamicType::AddAttribute(const String& name, AttributeType type)
-{
-       m_Attributes[name] = type;
-}
-
-void DynamicType::RemoveAttribute(const String& name)
-{
-       m_Attributes.erase(name);
-}
-
-bool DynamicType::HasAttribute(const String& name)
-{
-       return (m_Attributes.find(name) != m_Attributes.end());
-}
-
-void DynamicType::AddAttributes(const AttributeDescription *attributes, int attributeCount)
-{
-       for (int i = 0; i < attributeCount; i++)
-               AddAttribute(attributes[i].Name, attributes[i].Type);
-}
-
 boost::mutex& DynamicType::GetStaticMutex(void)
 {
        static boost::mutex mutex;
index 5db714be42712824c13f571d9a303f5f6c9f7ae8..97d5371ff588d5053f69fa0785175cdd71015a15 100644 (file)
 namespace icinga
 {
 
-struct AttributeDescription
-{
-       String Name;
-       AttributeType Type;
-};
-
 class I2_BASE_API DynamicType : public Object
 {
 public:
@@ -44,9 +38,8 @@ public:
        static DynamicType::Ptr GetByName(const String& name);
 
        static void RegisterType(const DynamicType::Ptr& type);
-       static bool TypeExists(const String& name);
 
-       DynamicObject::Ptr CreateObject(const Dictionary::Ptr& serializedUpdate) const;
+       static DynamicObject::Ptr CreateObject(const DynamicType::Ptr& self, const Dictionary::Ptr& serializedUpdate);
        DynamicObject::Ptr GetObject(const String& name) const;
 
        void RegisterObject(const DynamicObject::Ptr& object);
@@ -57,16 +50,9 @@ public:
 
        static set<DynamicObject::Ptr> GetObjects(const String& type);
 
-       void AddAttribute(const String& name, AttributeType type);
-       void RemoveAttribute(const String& name);
-       bool HasAttribute(const String& name);
-
-       void AddAttributes(const AttributeDescription *attributes, int attributeCount);
-
 private:
        String m_Name;
        ObjectFactory m_ObjectFactory;
-       map<String, AttributeType> m_Attributes;
 
        typedef map<String, DynamicObject::Ptr, string_iless> ObjectMap;
        typedef set<DynamicObject::Ptr> ObjectSet;
@@ -90,13 +76,10 @@ private:
 class RegisterTypeHelper
 {
 public:
-       RegisterTypeHelper(const String& name, const DynamicType::ObjectFactory& factory, const AttributeDescription* attributes, int attributeCount)
+       RegisterTypeHelper(const String& name, const DynamicType::ObjectFactory& factory)
        {
-               if (!DynamicType::TypeExists(name)) {
-                       DynamicType::Ptr type = boost::make_shared<DynamicType>(name, factory);
-                       type->AddAttributes(attributes, attributeCount);
-                       DynamicType::RegisterType(type);
-               }
+               DynamicType::Ptr type = boost::make_shared<DynamicType>(name, factory);
+               DynamicType::RegisterType(type);
        }
 };
 
@@ -111,11 +94,11 @@ shared_ptr<T> DynamicObjectFactory(const Dictionary::Ptr& serializedUpdate)
        return boost::make_shared<T>(serializedUpdate);
 }
 
-#define REGISTER_TYPE_ALIAS(type, alias, attributeDesc) \
-       static RegisterTypeHelper g_RegisterDT_ ## type(alias, DynamicObjectFactory<type>, attributeDesc, (attributeDesc == NULL) ? 0 : sizeof(attributeDesc) / sizeof((static_cast<AttributeDescription *>(attributeDesc))[0]))
+#define REGISTER_TYPE_ALIAS(type, alias) \
+       static RegisterTypeHelper g_RegisterDT_ ## type(alias, DynamicObjectFactory<type>)
 
-#define REGISTER_TYPE(type, attributeDesc) \
-       REGISTER_TYPE_ALIAS(type, #type, attributeDesc)
+#define REGISTER_TYPE(type) \
+       REGISTER_TYPE_ALIAS(type, #type)
 
 }
 
index 8fa1329ed7300e77b148f2b6dfd09f6360811b84..af0eb742d426b278e5b167947fb84bfc06363026 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Logger, NULL);
+REGISTER_TYPE(Logger);
 
 /**
  * Constructor for the Logger class.
@@ -37,7 +37,10 @@ Logger::Logger(const Dictionary::Ptr& properties)
 
        if (!IsLocal())
                BOOST_THROW_EXCEPTION(runtime_error("Logger objects must be local."));
+}
 
+void Logger::Start(void)
+{
        String type = m_Type;
        if (type.IsEmpty())
                BOOST_THROW_EXCEPTION(runtime_error("Logger objects must have a 'type' property."));
@@ -65,8 +68,9 @@ Logger::Logger(const Dictionary::Ptr& properties)
                BOOST_THROW_EXCEPTION(runtime_error("Unknown log type: " + type));
        }
 
-       impl->m_Config = this;
+       impl->m_Config = GetSelf();
        m_Impl = impl;
+
 }
 
 /**
@@ -185,5 +189,5 @@ LogSeverity Logger::StringToSeverity(const String& severity)
  */
 DynamicObject::Ptr ILogger::GetConfig(void) const
 {
-       return m_Config->GetSelf();
+       return m_Config.lock();
 }
index 2a99877cee0ace72b6bc0e10e35a1d6d67c8e8f2..5b43a88198b6aa4d4f03838e4e78c56464c4c32c 100644 (file)
@@ -71,7 +71,7 @@ protected:
        DynamicObject::Ptr GetConfig(void) const;
 
 private:
-       DynamicObject *m_Config;
+       DynamicObject::WeakPtr m_Config;
 
        friend class Logger;
 };
@@ -97,6 +97,9 @@ public:
 
        LogSeverity GetMinSeverity(void) const;
 
+protected:
+       virtual void Start(void);
+
 private:
        Attribute<String> m_Type;
        Attribute<String> m_Path;
index c409d87a032a02eb59b26f4d523fc73203a8c752..8acfba85bda1fdeda5312f592c830619cebb0463 100644 (file)
 
 using namespace icinga;
 
+boost::mutex Object::m_DebugMutex;
+
 /**
  * Default constructor for the Object class.
  */
 Object::Object(void)
+       : m_LockCount(0)
 { }
 
 /**
@@ -41,17 +44,32 @@ Object::~Object(void)
  */
 Object::SharedPtrHolder Object::GetSelf(void)
 {
+       ObjectLock olock(this);
+
        return Object::SharedPtrHolder(shared_from_this());
 }
 
 /**
- * Returns the mutex that must be held while calling non-static methods
- * which have not been explicitly marked as thread-safe.
+ * Checks if the calling thread owns the lock on this object or is currently
+ * in the constructor or destructor and therefore implicitly owns the lock.
  *
- * @returns The object's mutex.
- * @threadsafety Always.
+ * @returns True if the calling thread owns the lock, false otherwise.
  */
-recursive_mutex& Object::GetMutex(void) const
+bool Object::OwnsLock(void) const
 {
-       return m_Mutex;
+       boost::mutex::scoped_lock lock(m_DebugMutex);
+
+       if (m_LockCount == 0 || m_LockOwner != boost::this_thread::get_id()) {
+               try {
+                       shared_from_this();
+               } catch (const boost::bad_weak_ptr& ex) {
+                       /* There's no shared_ptr to this object. Either someone created the object
+                        * directly (e.g. on the stack) or we're in the constructor or destructor. Not holding the lock is ok here. */
+                       return true;
+               }
+
+               return false;
+       }
+
+       return true;
 }
index 923c208266a99169efbb3524222efd7f2f0ee54e..c200ad9d4a3fadcdede745c860b2ab1ed2c4c223 100644 (file)
@@ -91,19 +91,28 @@ public:
                                           holder instance */
        };
 
-       SharedPtrHolder GetSelf(void);
-
-       recursive_mutex& GetMutex(void) const;
+       void VerifyLocked(void) const;
+       void WarnIfLocked(void) const;
 
 protected:
        Object(void);
        virtual ~Object(void);
 
+       SharedPtrHolder GetSelf(void);
+
+       bool OwnsLock(void) const;
+
 private:
        Object(const Object& other);
        Object& operator=(const Object& rhs);
 
        mutable recursive_mutex m_Mutex;
+       mutable unsigned int m_LockCount;
+       mutable boost::thread::id m_LockOwner;
+
+       static boost::mutex m_DebugMutex;
+
+       friend class ObjectLock;
 };
 
 /**
index c51171853b06f2031314c7ef256ebfacffb6d68f..eb9b96483f02e3724bae0406e80efc3bacd341ac 100644 (file)
@@ -25,6 +25,11 @@ ObjectLock::ObjectLock(void)
        : m_Object(NULL), m_Lock()
 { }
 
+ObjectLock::~ObjectLock(void)
+{
+       Unlock();
+}
+
 ObjectLock::ObjectLock(const Object::Ptr& object)
        : m_Object(object.get()), m_Lock()
 {
@@ -43,10 +48,23 @@ void ObjectLock::Lock(void)
 {
        assert(!m_Lock.owns_lock() && m_Object != NULL);
 
-       m_Lock = recursive_mutex::scoped_lock(m_Object->GetMutex());
+       m_Lock = recursive_mutex::scoped_lock(m_Object->m_Mutex);
+
+       {
+               boost::mutex::scoped_lock lock(Object::m_DebugMutex);
+               m_Object->m_LockCount++;
+               m_Object->m_LockOwner = boost::this_thread::get_id();
+       }
 }
 
 void ObjectLock::Unlock(void)
 {
+       {
+               boost::mutex::scoped_lock lock(Object::m_DebugMutex);
+
+               if (m_Lock.owns_lock())
+                       m_Object->m_LockCount--;
+       }
+
        m_Lock = recursive_mutex::scoped_lock();
 }
index 580439bd731b00c1b2f39b015038f7fb01908e46..34aa38fa781edabc41b92ca3b5986b08709f04e7 100644 (file)
@@ -31,6 +31,7 @@ public:
        ObjectLock(void);
        ObjectLock(const Object::Ptr& object);
        ObjectLock(const Object *object);
+       ~ObjectLock(void);
 
        void Lock(void);
        void Unlock(void);
index b08b0521487a2b6f402e63ab1e57531443a9b431..a00d53f229f62930e96a4b08199a555d45a79406 100644 (file)
@@ -140,7 +140,6 @@ void Process::WorkerThreadProc(int taskFd)
                                        if (fd >= 0)
                                                tasks[fd] = task;
                                } catch (...) {
-                                       ObjectLock olock(task);
                                        task->FinishException(boost::current_exception());
                                }
                        }
@@ -156,7 +155,6 @@ void Process::WorkerThreadProc(int taskFd)
                                prev = it;
                                tasks.erase(prev);
 
-                               ObjectLock olock(task);
                                task->FinishResult(task->m_Result);
                        }
                }
@@ -218,6 +216,8 @@ void Process::InitTask(void)
                envp[i] = strdup(environ[i]);
 
        if (m_ExtraEnvironment) {
+               ObjectLock olock(m_ExtraEnvironment);
+
                String key;
                Value value;
                int index = envc;
index 3197dcda2ebd2832ccaf3c336bc37f1c4eec70b1..843602f598c55e1a33bade1435a82207951c9c23 100644 (file)
@@ -44,6 +44,8 @@ vector<String> Process::SplitCommand(const Value& command)
 
        if (command.IsObjectType<Dictionary>()) {
                Dictionary::Ptr dict = command;
+               ObjectLock olock(dict);
+
                Value arg;
                BOOST_FOREACH(tie(tuples::ignore, arg), dict) {
                        args.push_back(arg);
index 15a8449718686809554e551f8dc91cb3900f7ef9..c5993d9e167cb854189bf2e4e3c0185047c665eb 100644 (file)
 using namespace icinga;
 
 RingBuffer::RingBuffer(RingBuffer::SizeType slots)
-       : m_Slots(slots, 0), m_TimeValue(0)
+       : Object(), m_Slots(slots, 0), m_TimeValue(0)
 { }
 
+/**
+ * @threadsafety Always.
+ */
 RingBuffer::SizeType RingBuffer::GetLength(void) const
 {
+       ObjectLock olock(this);
+
        return m_Slots.size();
 }
 
+/**
+ * @threadsafety Always.
+ */
 void RingBuffer::InsertValue(RingBuffer::SizeType tv, int num)
 {
+       ObjectLock olock(this);
+
        vector<int>::size_type offsetTarget = tv % m_Slots.size();
 
        if (tv > m_TimeValue) {
@@ -53,8 +63,13 @@ void RingBuffer::InsertValue(RingBuffer::SizeType tv, int num)
        m_Slots[offsetTarget] += num;
 }
 
+/**
+ * @threadsafety Always.
+ */
 int RingBuffer::GetValues(RingBuffer::SizeType span) const
 {
+       ObjectLock olock(this);
+
        if (span > m_Slots.size())
                span = m_Slots.size();
 
index 392d6a1d5686f86c42d29ab649471a42359a09f6..8be88e74d72ef70612d8fb353587bfaff710629f 100644 (file)
@@ -28,9 +28,12 @@ namespace icinga
  *
  * @ingroup base
  */
-class I2_BASE_API RingBuffer
+class I2_BASE_API RingBuffer : public Object
 {
 public:
+       typedef shared_ptr<RingBuffer> Ptr;
+       typedef weak_ptr<RingBuffer> WeakPtr;
+
        typedef vector<int>::size_type SizeType;
 
        RingBuffer(SizeType slots);
index 740028dacc8e7056ebf3c46b88eaee9521b9ddb7..4db0837c35cc2a95b1005d4767eb6bd8b6c267c2 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Script, NULL);
+REGISTER_TYPE(Script);
 
 /**
  * Constructor for the Script class.
@@ -37,16 +37,22 @@ Script::Script(const Dictionary::Ptr& properties)
 
 void Script::Start(void)
 {
+       assert(OwnsLock());
+
        SpawnInterpreter();
 }
 
 String Script::GetLanguage(void) const
 {
+       ObjectLock olock(this);
+
        return m_Language;
 }
 
 String Script::GetCode(void) const
 {
+       ObjectLock olock(this);
+
        return m_Code;
 }
 
index 06ac2429466771ea10dcc919848e84404d0482c7..f401e1027062d2cbe6c4cf346afc2ee21492d87d 100644 (file)
@@ -30,13 +30,15 @@ ScriptFunction::ScriptFunction(const Callback& function)
 
 void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
 {
-       GetFunctions()[name] = function;
+       boost::mutex::scoped_lock lock(GetMutex());
+       InternalGetFunctions()[name] = function;
        OnRegistered(name, function);
 }
 
 void ScriptFunction::Unregister(const String& name)
 {
-       GetFunctions().erase(name);
+       boost::mutex::scoped_lock lock(GetMutex());
+       InternalGetFunctions().erase(name);
        OnUnregistered(name);
 }
 
@@ -44,9 +46,10 @@ ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
 {
        map<String, ScriptFunction::Ptr>::iterator it;
 
-       it = GetFunctions().find(name);
+       boost::mutex::scoped_lock lock(GetMutex());
+       it = InternalGetFunctions().find(name);
 
-       if (it == GetFunctions().end())
+       if (it == InternalGetFunctions().end())
                return ScriptFunction::Ptr();
 
        return it->second;
@@ -54,11 +57,28 @@ ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
 
 void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& arguments)
 {
+       ObjectLock olock(this);
+
        m_Callback(task, arguments);
 }
 
-map<String, ScriptFunction::Ptr>& ScriptFunction::GetFunctions(void)
+map<String, ScriptFunction::Ptr> ScriptFunction::GetFunctions(void)
+{
+       boost::mutex::scoped_lock lock(GetMutex());
+       return InternalGetFunctions(); /* makes a copy of the map */
+}
+
+/**
+ * @threadsafety Caller must hold the mutex returned by GetMutex().
+ */
+map<String, ScriptFunction::Ptr>& ScriptFunction::InternalGetFunctions(void)
 {
        static map<String, ScriptFunction::Ptr> functions;
        return functions;
 }
+
+boost::mutex& ScriptFunction::GetMutex(void)
+{
+       static boost::mutex mtx;
+       return mtx;
+}
index babb62f4acd3bbaf2dca8e7b23531c89404f3450..74c450b9d1286ad40362fd941802e12642b162a7 100644 (file)
@@ -46,13 +46,16 @@ public:
 
        void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
 
-       /* TODO(thread) make private */ static map<String, ScriptFunction::Ptr>& GetFunctions(void);
+       static map<String, ScriptFunction::Ptr> GetFunctions(void);
 
        static signals2::signal<void (const String&, const ScriptFunction::Ptr&)> OnRegistered;
        static signals2::signal<void (const String&)> OnUnregistered;
 
 private:
        Callback m_Callback;
+
+       static map<String, ScriptFunction::Ptr>& InternalGetFunctions(void);
+       static boost::mutex& GetMutex(void);
 };
 
 /**
index df1ce9c35b955e628ad8e4eaa2cf3d538829c045..edb6b7adf6738057cc55c7798fe33a8144452bcd 100644 (file)
@@ -33,6 +33,8 @@ ScriptInterpreter::~ScriptInterpreter(void)
 
 void ScriptInterpreter::SubscribeFunction(const String& name)
 {
+       ObjectLock olock(this);
+
        m_SubscribedFunctions.insert(name);
 
        ScriptFunction::Ptr sf = boost::make_shared<ScriptFunction>(boost::bind(&ScriptInterpreter::ProcessCall, this, _1, name, _2));
@@ -41,6 +43,8 @@ void ScriptInterpreter::SubscribeFunction(const String& name)
 
 void ScriptInterpreter::UnsubscribeFunction(const String& name)
 {
+       ObjectLock olock(this);
+
        m_SubscribedFunctions.erase(name);
        ScriptFunction::Unregister(name);
 }
index 5ef9030b5542e3c6cdcfea87f3ed50b1bbf6875f..4f0420d7cf384954765a35c3d158c250184409d0 100644 (file)
@@ -29,5 +29,12 @@ ScriptTask::ScriptTask(const ScriptFunction::Ptr& function,
 
 void ScriptTask::Run(void)
 {
-       m_Function->Invoke(GetSelf(), m_Arguments);
+       ScriptTask::Ptr self;
+
+       {
+               ObjectLock olock(this);
+               self = GetSelf();
+       }
+
+       m_Function->Invoke(self, m_Arguments);
 }
index 6e7bbcb8fd42c0628b066dec121df8f6aae61744..efa0cc15d5ca680d3311a6f4984e66cb07289f32 100644 (file)
@@ -52,6 +52,8 @@ void StdioStream::Start(void)
 
 size_t StdioStream::GetAvailableBytes(void) const
 {
+       ObjectLock olock(this);
+
        if (m_InnerStream->eof() && m_ReadAheadBuffer->GetAvailableBytes() == 0)
                return 0;
        else
@@ -60,6 +62,8 @@ size_t StdioStream::GetAvailableBytes(void) const
 
 size_t StdioStream::Read(void *buffer, size_t size)
 {
+       ObjectLock olock(this);
+
        size_t peek_len, read_len;
 
        peek_len = m_ReadAheadBuffer->GetAvailableBytes();
@@ -73,6 +77,8 @@ size_t StdioStream::Read(void *buffer, size_t size)
 
 size_t StdioStream::Peek(void *buffer, size_t size)
 {
+       ObjectLock olock(this);
+
        size_t peek_len, read_len;
 
        peek_len = m_ReadAheadBuffer->GetAvailableBytes();
@@ -87,11 +93,15 @@ size_t StdioStream::Peek(void *buffer, size_t size)
 
 void StdioStream::Write(const void *buffer, size_t size)
 {
+       ObjectLock olock(this);
+
        m_InnerStream->write(static_cast<const char *>(buffer), size);
 }
 
 void StdioStream::Close(void)
 {
+       ObjectLock olock(this);
+
        if (m_OwnsStream)
                delete m_InnerStream;
 
index 704d28c34ff8f54748b9b5d1af2a570fb5219f03..01a8d33baa0d9ae63a470b22eee26005ad6f5b78 100644 (file)
@@ -86,13 +86,12 @@ void Timer::Uninitialize(void)
  *
  * @threadsafety Always.
  */
-void Timer::Call(void)
+void Timer::Call(const Timer::Ptr& self)
 {
-       OnTimerExpired(GetSelf());
+       self->OnTimerExpired(self);
 
        /* Re-enable the timer so it can be called again. */
-       m_Started = true;
-       Reschedule();
+       self->Start();
 }
 
 /**
@@ -103,6 +102,8 @@ void Timer::Call(void)
  */
 void Timer::SetInterval(double interval)
 {
+       assert(!OwnsLock());
+
        boost::mutex::scoped_lock lock(m_Mutex);
        m_Interval = interval;
 }
@@ -115,6 +116,8 @@ void Timer::SetInterval(double interval)
  */
 double Timer::GetInterval(void) const
 {
+       assert(!OwnsLock());
+
        boost::mutex::scoped_lock lock(m_Mutex);
        return m_Interval;
 }
@@ -126,7 +129,12 @@ double Timer::GetInterval(void) const
  */
 void Timer::Start(void)
 {
-       m_Started = true;
+       assert(!OwnsLock());
+
+       {
+               boost::mutex::scoped_lock lock(m_Mutex);
+               m_Started = true;
+       }
 
        Reschedule();
 }
@@ -138,6 +146,8 @@ void Timer::Start(void)
  */
 void Timer::Stop(void)
 {
+       assert(!OwnsLock());
+
        boost::mutex::scoped_lock lock(m_Mutex);
 
        m_Started = false;
@@ -156,6 +166,8 @@ void Timer::Stop(void)
  */
 void Timer::Reschedule(double next)
 {
+       assert(!OwnsLock());
+
        boost::mutex::scoped_lock lock(m_Mutex);
 
        if (next < 0) {
@@ -188,6 +200,8 @@ void Timer::Reschedule(double next)
  */
 double Timer::GetNext(void) const
 {
+       assert(!OwnsLock());
+
        boost::mutex::scoped_lock lock(m_Mutex);
        return m_Next;
 }
index e06ad26a1d6c0a1771d562072b4babd854cf6515..bc458641976d9898577d9bd164163b05babc0725 100644 (file)
@@ -86,7 +86,7 @@ private:
        static bool m_StopThread;
        static TimerSet m_Timers;
 
-       void Call(void);
+       static void Call(const Timer::Ptr& self);
 
        static void TimerThreadProc(void);
 
index bccb661b1be8d83226c9f603c0c0d5d8c6405433..7eafa0afe39221683e1cda4448f47983eda59c39 100644 (file)
@@ -144,6 +144,7 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
                        BOOST_THROW_EXCEPTION(domain_error(message.str()));
                }
 
+               ObjectLock olock(parent);
                parent->InternalLink(dictionary);
        }
 
@@ -208,10 +209,8 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
                m_Items[ikey] = self;
        }
 
-       if (!dobj) {
-               ObjectLock olock(dtype);
+       if (!dobj)
                dobj = dtype->GetObject(name);
-       }
 
        /* Register this item with its parents. */
        BOOST_FOREACH(const String& parentName, parents) {
@@ -224,26 +223,36 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
         * DynamicObject::ApplyUpdate expects. */
        Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
 
-       String key;
-       Value data;
-       BOOST_FOREACH(tie(key, data), properties) {
-               Dictionary::Ptr attr = boost::make_shared<Dictionary>();
-               attr->Set("data", data);
-               attr->Set("type", Attribute_Config);
-               attr->Set("tx", DynamicObject::GetCurrentTx());
-               attrs->Set(key, attr);
+       double tx = DynamicObject::GetCurrentTx();
+
+       {
+               ObjectLock olock(properties);
+
+               String key;
+               Value data;
+               BOOST_FOREACH(tie(key, data), properties) {
+                       Dictionary::Ptr attr = boost::make_shared<Dictionary>();
+                       attr->Set("data", data);
+                       attr->Set("type", Attribute_Config);
+                       attr->Set("tx", tx);
+                       attr->Seal();
+
+                       attrs->Set(key, attr);
+               }
        }
 
+       attrs->Seal();
+
        Dictionary::Ptr update = boost::make_shared<Dictionary>();
        update->Set("attrs", attrs);
        update->Set("configTx", DynamicObject::GetCurrentTx());
+       update->Seal();
 
        /* Update or create the object and apply the configuration settings. */
        bool was_null = false;
 
        if (!dobj) {
-               ObjectLock dlock(dtype);
-               dobj = dtype->CreateObject(update);
+               dobj = DynamicType::CreateObject(dtype, update);
                was_null = true;
        }
 
index 3ea192c1c848e2b5173b1188a7afabd17037510e..20668ea0b1d717778700b0da412bea4c497a2297 100644 (file)
@@ -52,14 +52,24 @@ DebugInfo ConfigType::GetDebugInfo(void) const
 
 void ConfigType::ValidateItem(const ConfigItem::Ptr& item) const
 {
-       Dictionary::Ptr attrs = item->Link();
+       String type, name;
+       Dictionary::Ptr attrs;
+
+       {
+               ObjectLock olock(item);
+               attrs = item->Link();
+               type = item->GetType();
+               name = item->GetName();
+       }
+
+       ObjectLock olock(attrs);
 
        /* Don't validate abstract items. */
        if (attrs->Get("__abstract"))
                return;
 
        vector<String> locations;
-       locations.push_back("Object '" + item->GetName() + "' (Type: '" + item->GetType() + "')");
+       locations.push_back("Object '" + name + "' (Type: '" + type + "')");
 
        ConfigType::Ptr parent;
        if (m_Parent.IsEmpty()) {
@@ -70,8 +80,10 @@ void ConfigType::ValidateItem(const ConfigItem::Ptr& item) const
        }
 
        vector<TypeRuleList::Ptr> ruleLists;
-       if (parent)
+       if (parent) {
+               ObjectLock plock(parent);
                ruleLists.push_back(parent->m_RuleList);
+       }
 
        ruleLists.push_back(m_RuleList);
 
@@ -131,15 +143,12 @@ void ConfigType::ValidateDictionary(const Dictionary::Ptr& dictionary,
 
                        ScriptTask::Ptr task = boost::make_shared<ScriptTask>(func, arguments);
                        task->Start();
-                       task->Wait();
-
-                       {
-                               ObjectLock olock(task);
-                               task->GetResult();
-                       }
+                       task->GetResult();
                }
        }
 
+       ObjectLock olock(dictionary);
+
        String key;
        Value value;
        BOOST_FOREACH(tie(key, value), dictionary) {
index 8b48f40b253ac914a26a188ac01cd4335e6714f7..f177c7a99a2f1393626a8ad7b7254bb1a8280e6a 100644 (file)
@@ -54,6 +54,7 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const
 
                case OperatorSet:
                        if (valueExprl) {
+                               ObjectLock olock(valueExprl);
                                dict = boost::make_shared<Dictionary>();
                                valueExprl->Execute(dict);
                                newValue = dict;
@@ -62,7 +63,10 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const
                        break;
 
                case OperatorPlus:
-                       oldValue = dictionary->Get(m_Key);
+                       {
+                               ObjectLock olock(dictionary);
+                               oldValue = dictionary->Get(m_Key);
+                       }
 
                        if (oldValue.IsObjectType<Dictionary>())
                                dict = oldValue;
@@ -83,8 +87,13 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const
                        newValue = dict;
 
                        if (valueExprl) {
+                               ObjectLock olock(valueExprl);
+
                                valueExprl->Execute(dict);
                        } else if (valueDict) {
+                               ObjectLock olock(valueDict);
+                               ObjectLock dlock(dict);
+
                                String key;
                                Value value;
                                BOOST_FOREACH(tie(key, value), valueDict) {
@@ -103,6 +112,7 @@ void Expression::Execute(const Dictionary::Ptr& dictionary) const
                        BOOST_THROW_EXCEPTION(runtime_error("Not yet implemented."));
        }
 
+       ObjectLock olock(dictionary);
        if (m_Key.IsEmpty())
                dictionary->Add(newValue);
        else
index 3d1f94a5c97fd9806b112c5caf52e20896ea3d8a..1f91d8d60a4575b738356de6dc82a7e5ac23c715 100644 (file)
@@ -21,7 +21,6 @@
 
 using namespace icinga;
 
-boost::mutex CIB::m_Mutex;
 RingBuffer CIB::m_ActiveChecksStatistics(15 * 60);
 RingBuffer CIB::m_PassiveChecksStatistics(15 * 60);
 
@@ -30,7 +29,6 @@ RingBuffer CIB::m_PassiveChecksStatistics(15 * 60);
  */
 void CIB::UpdateActiveChecksStatistics(long tv, int num)
 {
-       boost::mutex::scoped_lock lock(m_Mutex);
        m_ActiveChecksStatistics.InsertValue(tv, num);
 }
 
@@ -39,7 +37,6 @@ void CIB::UpdateActiveChecksStatistics(long tv, int num)
  */
 int CIB::GetActiveChecksStatistics(long timespan)
 {
-       boost::mutex::scoped_lock lock(m_Mutex);
        return m_ActiveChecksStatistics.GetValues(timespan);
 }
 
@@ -48,7 +45,6 @@ int CIB::GetActiveChecksStatistics(long timespan)
  */
 void CIB::UpdatePassiveChecksStatistics(long tv, int num)
 {
-       boost::mutex::scoped_lock lock(m_Mutex);
        m_PassiveChecksStatistics.InsertValue(tv, num);
 }
 
@@ -57,6 +53,5 @@ void CIB::UpdatePassiveChecksStatistics(long tv, int num)
  */
 int CIB::GetPassiveChecksStatistics(long timespan)
 {
-       boost::mutex::scoped_lock lock(m_Mutex);
        return m_PassiveChecksStatistics.GetValues(timespan);
 }
index c2c72d62d5dcd33e03922f34d35b41506bbd5261..70dde422f7ebdc2813e0b18a6003174a6e1252eb 100644 (file)
@@ -27,7 +27,7 @@ bool Host::m_ServicesCacheValid = true;
 
 REGISTER_SCRIPTFUNCTION("ValidateServiceDictionary", &Host::ValidateServiceDictionary);
 
-REGISTER_TYPE(Host, NULL);
+REGISTER_TYPE(Host);
 
 Host::Host(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
@@ -146,6 +146,8 @@ bool Host::IsReachable(const Host::Ptr& self)
 template<bool copyServiceAttrs, typename TDict>
 static void CopyServiceAttributes(TDict serviceDesc, const ConfigItemBuilder::Ptr& builder)
 {
+       ObjectLock olock(serviceDesc);
+
        /* TODO: we only need to copy macros if this is an inline definition,
         * i.e. "typeid(serviceDesc)" != Service, however for now we just
         * copy them anyway. */
@@ -211,6 +213,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
        }
 
        newServices = boost::make_shared<Dictionary>();
+       ObjectLock nlock(newServices);
 
        DebugInfo debug_info;
 
@@ -220,6 +223,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
        }
 
        if (serviceDescs) {
+               ObjectLock olock(serviceDescs);
                String svcname;
                Value svcdesc;
                BOOST_FOREACH(tie(svcname, svcdesc), serviceDescs) {
@@ -244,9 +248,16 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
                        } else if (svcdesc.IsObjectType<Dictionary>()) {
                                Dictionary::Ptr service = svcdesc;
 
-                               Dictionary::Ptr templates = service->Get("templates");
+                               Dictionary::Ptr templates;
+
+                               {
+                                       ObjectLock olock(service);
+                                       templates = service->Get("templates");
+                               }
 
                                if (templates) {
+                                       ObjectLock olock(templates);
+
                                        String tmpl;
                                        BOOST_FOREACH(tie(tuples::ignore, tmpl), templates) {
                                                builder->AddParent(tmpl);
@@ -268,6 +279,8 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
        }
 
        if (oldServices) {
+               ObjectLock olock(oldServices);
+
                ConfigItem::Ptr service;
                BOOST_FOREACH(tie(tuples::ignore, service), oldServices) {
                        if (!service)
@@ -280,6 +293,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
 
        newServices->Seal();
 
+       ObjectLock olock(self);
        self->Set("slave_services", newServices);
 }
 
@@ -288,7 +302,14 @@ void Host::OnAttributeChanged(const String& name, const Value&)
        if (name == "hostgroups")
                HostGroup::InvalidateMembersCache();
        else if (name == "services") {
-               UpdateSlaveServices(GetSelf());
+               Host::Ptr self;
+
+               {
+                       ObjectLock olock(this);
+                       self = GetSelf();
+               }
+
+               UpdateSlaveServices(self);
        } else if (name == "notifications") {
                set<Service::Ptr> services;
 
@@ -388,6 +409,7 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
 
        String location = arguments[0];
        Dictionary::Ptr attrs = arguments[1];
+       ObjectLock olock(attrs);
 
        String key;
        Value value;
@@ -399,9 +421,9 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
                } else if (value.IsObjectType<Dictionary>()) {
                        Dictionary::Ptr serviceDesc = value;
 
-                       if (serviceDesc->Contains("service"))
-                               name = serviceDesc->Get("service");
-                       else
+                       name = serviceDesc->Get("service");
+
+                       if (name.IsEmpty())
                                name = key;
                } else {
                        continue;
@@ -538,6 +560,7 @@ set<Service::Ptr> Host::GetParentServices(const Host::Ptr& self)
 Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
 {
        Dictionary::Ptr macros = boost::make_shared<Dictionary>();
+       ObjectLock mlock(macros);
 
        {
                ObjectLock olock(self);
index 7b38fd1c110ff1d0a303f7f69dc6866a5c42c5c2..094b2f52b88409bc60d5e8a655816466e9d26619 100644 (file)
@@ -25,7 +25,7 @@ boost::mutex HostGroup::m_Mutex;
 map<String, vector<Host::WeakPtr> > HostGroup::m_MembersCache;
 bool HostGroup::m_MembersCacheValid = true;
 
-REGISTER_TYPE(HostGroup, NULL);
+REGISTER_TYPE(HostGroup);
 
 HostGroup::HostGroup(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
index 66b6e0952ea5b565e632a2d01ade09b30c3b9702..287c77ee379d26c113d17b121c67523899f8298d 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(IcingaApplication, NULL);
+REGISTER_TYPE(IcingaApplication);
 
 #ifndef _WIN32
 #      include "icinga-version.h"
@@ -156,6 +156,7 @@ shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const
 Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(const IcingaApplication::Ptr& self)
 {
        Dictionary::Ptr macros = boost::make_shared<Dictionary>();
+       ObjectLock mlock(macros);
 
        double now = Utility::GetTime();
 
index 7cb4543c7d4ce49aa329adda6c76fd186ee3b55f..a59688976483bcda703dbd19efaaec13e673bf35 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Notification, NULL);
+REGISTER_TYPE(Notification);
 
 Notification::Notification(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
@@ -76,6 +76,8 @@ set<User::Ptr> Notification::GetUsers(void) const
        Dictionary::Ptr users = m_Users;
 
        if (users) {
+               ObjectLock olock(users);
+
                String name;
                BOOST_FOREACH(tie(tuples::ignore, name), users) {
                        User::Ptr user = User::GetByName(name);
@@ -97,6 +99,8 @@ set<UserGroup::Ptr> Notification::GetGroups(void) const
        Dictionary::Ptr groups = m_Groups;
 
        if (groups) {
+               ObjectLock olock(groups);
+
                String name;
                BOOST_FOREACH(tie(tuples::ignore, name), groups) {
                        UserGroup::Ptr ug = UserGroup::GetByName(name);
@@ -256,10 +260,7 @@ void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
        m_Tasks.erase(task);
 
        try {
-               {
-                       ObjectLock tlock(task);
-                       (void) task->GetResult();
-               }
+               task->GetResult();
 
                Logger::Write(LogInformation, "icinga", "Completed sending notification for service '" + GetService()->GetName() + "'");
        } catch (const exception& ex) {
index 70a8701d14a8572366dafc0704029338e40395db..845d753d228d8d22d9b453ddd465cb7181f25780 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(PerfdataWriter, NULL);
+REGISTER_TYPE(PerfdataWriter);
 
 PerfdataWriter::PerfdataWriter(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
@@ -49,6 +49,7 @@ void PerfdataWriter::Start(void)
 
        {
                ObjectLock olock(m_Endpoint);
+
                m_Endpoint->RegisterTopicHandler("checker::CheckResult",
                    boost::bind(&PerfdataWriter::CheckResultRequestHandler, this, _3));
        }
index f3ab963d6236e9e113db619483f2bb5e8436cbd2..6fd969ab6abd321876d481c032884c76b9b0d44d 100644 (file)
@@ -59,10 +59,8 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
        ProcessResult pr;
 
        try {
-               ObjectLock olock(ct.m_Process);
                pr = ct.m_Process->GetResult();
        } catch (...) {
-               ObjectLock olock(ct.m_Task);
                ct.m_Task->FinishException(boost::current_exception());
 
                return;
@@ -76,7 +74,6 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
        result->Set("execution_start", pr.ExecutionStart);
        result->Set("execution_end", pr.ExecutionEnd);
 
-       ObjectLock olock(ct.m_Task);
        ct.m_Task->FinishResult(result);
 }
 
index 4c0a35862abdcf7bad19e207539829ba696b300b..0b5fba893b90c65f19376e96e610d55264d26903 100644 (file)
@@ -79,7 +79,6 @@ void PluginNotificationTask::ProcessFinishedHandler(PluginNotificationTask ct)
 
        try {
                {
-                       ObjectLock tlock(ct.m_Process);
                        pr = ct.m_Process->GetResult();
                }
 
@@ -91,15 +90,9 @@ void PluginNotificationTask::ProcessFinishedHandler(PluginNotificationTask ct)
                        Logger::Write(LogWarning, "icinga", msgbuf.str());
                }
 
-               {
-                       ObjectLock olock(ct.m_Task);
-                       ct.m_Task->FinishResult(Empty);
-               }
+               ct.m_Task->FinishResult(Empty);
        } catch (...) {
-               {
-                       ObjectLock olock(ct.m_Task);
-                       ct.m_Task->FinishException(boost::current_exception());
-               }
+               ct.m_Task->FinishException(boost::current_exception());
 
                return;
        }
index da7cf179a25ae6e1cdce62cc60ff872f687d1c3c..57b6f1a87c4dd7c42e38ea22defca8af155c03c6 100644 (file)
@@ -407,8 +407,12 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
 
        /* keep track of scheduling info in case the check type doesn't provide its own information */
        Dictionary::Ptr checkInfo = boost::make_shared<Dictionary>();
-       checkInfo->Set("schedule_start", self->GetNextCheck());
-       checkInfo->Set("execution_start", Utility::GetTime());
+
+       {
+               ObjectLock olock(checkInfo);
+               checkInfo->Set("schedule_start", self->GetNextCheck());
+               checkInfo->Set("execution_start", Utility::GetTime());
+       }
 
        vector<Dictionary::Ptr> macroDicts;
        macroDicts.push_back(self->GetMacros());
@@ -460,16 +464,12 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
 {
        checkInfo->Set("execution_end", Utility::GetTime());
        checkInfo->Set("schedule_end", Utility::GetTime());
+       checkInfo->Seal();
 
        Dictionary::Ptr result;
 
        try {
-               Value vresult;
-
-               {
-                       ObjectLock tlock(task);
-                       vresult = task->GetResult();
-               }
+               Value vresult = task->GetResult();
 
                if (vresult.IsObjectType<Dictionary>())
                        result = vresult;
@@ -511,6 +511,8 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
 
                        result->Set("current_checker", em->GetIdentity());
                }
+
+               result->Seal();
        }
 
        {
index e066d180b10f325b1913f176aecd7dbb54ff78d9..63ee72335219c33baf1eed38d37aa4ba41607290 100644 (file)
@@ -158,6 +158,8 @@ set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self)
 template<typename TDict>
 static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemBuilder::Ptr& builder)
 {
+       ObjectLock olock(notificationDesc);
+
        /* TODO: we only need to copy macros if this is an inline definition,
         * i.e. "typeid(notificationDesc)" != Notification, however for now we just
         * copy them anyway. */
@@ -214,6 +216,8 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
        Dictionary::Ptr newNotifications;
        newNotifications = boost::make_shared<Dictionary>();
 
+       ObjectLock nlock(newNotifications);
+
        String host_name;
 
        {
@@ -256,6 +260,8 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
                                Dictionary::Ptr templates = notification->Get("templates");
 
                                if (templates) {
+                                       ObjectLock tlock(templates);
+
                                        String tmpl;
                                        BOOST_FOREACH(tie(tuples::ignore, tmpl), templates) {
                                                builder->AddParent(tmpl);
@@ -277,6 +283,8 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
        }
 
        if (oldNotifications) {
+               ObjectLock olock(oldNotifications);
+
                ConfigItem::Ptr notification;
                BOOST_FOREACH(tie(tuples::ignore, notification), oldNotifications) {
                        if (!notification)
index c90499802f4ffceac0a0798611fe5e23410e2cf3..cc40a1d93b9cc3b6aa3b7cb3d86f32070bb0d6f9 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Service, NULL);
+REGISTER_TYPE(Service);
 
 Service::Service(const Dictionary::Ptr& serializedObject)
        : DynamicObject(serializedObject)
@@ -274,28 +274,39 @@ void Service::ClearAcknowledgement(void)
 
 void Service::OnAttributeChanged(const String& name, const Value& oldValue)
 {
+       Service::Ptr self;
+       String service_name;
+       bool abstract;
+
+       {
+               ObjectLock olock(this);
+               self = GetSelf();
+               service_name = GetName();
+               abstract = IsAbstract();
+       }
+
        if (name == "current_checker")
-               OnCheckerChanged(GetSelf(), oldValue);
+               OnCheckerChanged(self, oldValue);
        else if (name == "next_check")
-               OnNextCheckChanged(GetSelf(), oldValue);
+               OnNextCheckChanged(self, oldValue);
        else if (name == "servicegroups")
                ServiceGroup::InvalidateMembersCache();
        else if (name == "host_name" || name == "short_name") {
                Host::InvalidateServicesCache();
 
-               UpdateSlaveNotifications(GetSelf());
+               UpdateSlaveNotifications(self);
        } else if (name == "downtimes")
                Service::InvalidateDowntimesCache();
        else if (name == "comments")
                Service::InvalidateCommentsCache();
        else if (name == "notifications")
-               UpdateSlaveNotifications(GetSelf());
+               UpdateSlaveNotifications(self);
        else if (name == "check_interval") {
-               ObjectLock(this);
-               ConfigItem::Ptr item = ConfigItem::GetObject("Service", GetName());
+               ObjectLock olock(this);
+               ConfigItem::Ptr item = ConfigItem::GetObject("Service", service_name);
 
                /* update the next check timestamp if we're the owner of this service */
-               if (item && !IsAbstract())
+               if (item && !abstract)
                        UpdateNextCheck();
        }
 }
@@ -366,6 +377,7 @@ set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self)
 Dictionary::Ptr Service::CalculateDynamicMacros(const Service::Ptr& self)
 {
        Dictionary::Ptr macros = boost::make_shared<Dictionary>();
+       ObjectLock mlock(macros);
 
        Dictionary::Ptr cr;
 
index f807046dd2354a9bb5de642e54bc62dec3033a3e..e01b4e89ad576a5a895cd853c094848dae8ce41c 100644 (file)
@@ -25,7 +25,7 @@ boost::mutex ServiceGroup::m_Mutex;
 map<String, vector<Service::WeakPtr> > ServiceGroup::m_MembersCache;
 bool ServiceGroup::m_MembersCacheValid = true;
 
-REGISTER_TYPE(ServiceGroup, NULL);
+REGISTER_TYPE(ServiceGroup);
 
 ServiceGroup::ServiceGroup(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
index 6624c2fe70240112eabcc5fca6609dcaa17ebb05..517cc81886ce8e2eb8e2fa8b191385bf6f3fd227 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(User, NULL);
+REGISTER_TYPE(User);
 
 User::User(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
index 99a5cdf08dbb04677892cac9a3d5e20975421ab6..350ec30effaad8f0f598aefc1a5642b45007098c 100644 (file)
@@ -25,7 +25,7 @@ boost::mutex UserGroup::m_Mutex;
 map<String, vector<User::WeakPtr> > UserGroup::m_MembersCache;
 bool UserGroup::m_MembersCacheValid = true;
 
-REGISTER_TYPE(UserGroup, NULL);
+REGISTER_TYPE(UserGroup);
 
 UserGroup::UserGroup(const Dictionary::Ptr& properties)
        : DynamicObject(properties)
index 9ec040375c06cabd11747cddf74f7aad67ce0a95..82d03ee3595a97995d970c32f1529c39f191e193 100644 (file)
@@ -21,7 +21,7 @@
 
 using namespace icinga;
 
-REGISTER_TYPE(Endpoint, NULL);
+REGISTER_TYPE(Endpoint);
 
 signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnConnected;
 signals2::signal<void (const Endpoint::Ptr&)> Endpoint::OnDisconnected;
@@ -128,8 +128,11 @@ void Endpoint::RegisterSubscription(const String& topic)
        if (!subscriptions)
                subscriptions = boost::make_shared<Dictionary>();
 
+       ObjectLock olock(subscriptions);
+
        if (!subscriptions->Contains(topic)) {
                Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
+               ObjectLock nlock(newSubscriptions);
                newSubscriptions->Set(topic, topic);
                SetSubscriptions(newSubscriptions);
        }
@@ -144,8 +147,14 @@ void Endpoint::UnregisterSubscription(const String& topic)
 {
        Dictionary::Ptr subscriptions = GetSubscriptions();
 
-       if (subscriptions && subscriptions->Contains(topic)) {
+       if (!subscriptions)
+               return;
+
+       ObjectLock olock(subscriptions);
+
+       if (subscriptions->Contains(topic)) {
                Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
+               ObjectLock nlock(newSubscriptions);
                newSubscriptions->Remove(topic);
                SetSubscriptions(newSubscriptions);
        }
@@ -222,6 +231,9 @@ void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
 
                newSubscriptions = GetSubscriptions();
 
+               ObjectLock olock(oldSubscriptions);
+               ObjectLock nlock(newSubscriptions);
+
                if (oldSubscriptions) {
                        String subscription;
                        BOOST_FOREACH(tie(tuples::ignore, subscription), oldSubscriptions) {
index af96a8153df13f4aac3e06e061e1bed149a08a52..eaa8d9cb26a1c928eaa7c0383ee2431d0905abb6 100644 (file)
@@ -331,7 +331,11 @@ void EndpointManager::SubscriptionTimerHandler(void)
                if (!endpoint->IsLocalEndpoint() || endpoint == m_Endpoint)
                        continue;
 
-               if (endpoint->GetSubscriptions()) {
+               Dictionary::Ptr endpointSubscriptions = endpoint->GetSubscriptions();
+
+               if (endpointSubscriptions) {
+                       ObjectLock olock(endpointSubscriptions);
+
                        String topic;
                        BOOST_FOREACH(tie(tuples::ignore, topic), endpoint->GetSubscriptions()) {
                                subscriptions->Set(topic, topic);