]> granicus.if.org Git - icinga2/commitdiff
Improve config compiler performance.
authorGunnar Beutner <gunnar@beutner.name>
Fri, 6 Dec 2013 20:46:50 +0000 (21:46 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Fri, 13 Dec 2013 13:07:37 +0000 (14:07 +0100)
Refs #5327

lib/base/application.cpp
lib/base/threadpool.cpp
lib/base/threadpool.h
lib/base/utility.cpp
lib/base/utility.h
lib/config/configitem.cpp
lib/config/configitem.h

index a3ee1c532d245efee676c36ab2df4d804920dbee..742384d5591b185a391f201697806dfbbae39261 100644 (file)
@@ -181,7 +181,7 @@ void Application::RunEventLoop(void) const
        GetTP().Stop();
        m_ShuttingDown = false;
 
-       GetTP().Join();
+       GetTP().Join(true);
 
        Timer::Uninitialize();
 #endif /* _DEBUG */
index f15d07c240c3504482ba2a3cf7105421ddf2fa29..e4cf9c0ced933a9ecdebdc1dff786db5e3f6ebe0 100644 (file)
@@ -33,79 +33,95 @@ using namespace icinga;
 
 int ThreadPool::m_NextID = 1;
 
-ThreadPool::ThreadPool(void)
-       : m_ID(m_NextID++), m_WaitTime(0), m_ServiceTime(0),
-         m_TaskCount(0), m_Stopped(false)
+ThreadPool::ThreadPool(int max_threads)
+       : m_ID(m_NextID++), m_Stopped(false), m_MaxThreads(max_threads)
 {
-       for (int i = 0; i < 2; i++)
-               SpawnWorker();
+       if (m_MaxThreads != -1 && m_MaxThreads < sizeof(m_Queues) / sizeof(m_Queues[0]))
+               m_MaxThreads = sizeof(m_Queues) / sizeof(m_Queues[0]);
 
-       m_ThreadGroup.create_thread(boost::bind(&ThreadPool::ManagerThreadProc, this));
-       m_ThreadGroup.create_thread(boost::bind(&ThreadPool::StatsThreadProc, this));
+       Start();
 }
 
 ThreadPool::~ThreadPool(void)
 {
        Stop();
-       Join();
+       Join(true);
+}
+
+void ThreadPool::Start(void)
+{
+       for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++)
+               m_Queues[i].SpawnWorker(m_ThreadGroup);
+
+       m_ThreadGroup.create_thread(boost::bind(&ThreadPool::ManagerThreadProc, this));
+       m_ThreadGroup.create_thread(boost::bind(&ThreadPool::StatsThreadProc, this));
 }
 
 void ThreadPool::Stop(void)
 {
-       boost::mutex::scoped_lock lock(m_Mutex);
+       for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) {
+               boost::mutex::scoped_lock lock(m_Queues[i].Mutex);
+               m_Queues[i].Stopped = true;
+               m_Queues[i].CV.notify_all();
+       }
+
+       boost::mutex::scoped_lock lock(m_MgmtMutex);
        m_Stopped = true;
-       m_WorkCV.notify_all();
        m_MgmtCV.notify_all();
 }
 
 /**
  * Waits for all worker threads to finish.
  */
-void ThreadPool::Join(void)
+void ThreadPool::Join(bool wait_for_stop)
 {
-       {
-               boost::mutex::scoped_lock lock(m_Mutex);
-
-               while (!m_Stopped || !m_WorkItems.empty()) {
-                       lock.unlock();
-                       Utility::Sleep(0.5);
-                       lock.lock();
-               }
+       if (wait_for_stop) {
+               m_ThreadGroup.join_all();
+               return;
        }
 
-       m_ThreadGroup.join_all();
+       for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) {
+               boost::mutex::scoped_lock lock(m_Queues[i].Mutex);
+
+               while (!m_Queues[i].Items.empty())
+                       m_Queues[i].CVStarved.wait(lock);
+       }
 }
 
 /**
  * Waits for work items and processes them.
  */
-void ThreadPool::QueueThreadProc(int tid)
+void ThreadPool::WorkerThread::ThreadProc(Queue& queue)
 {
        std::ostringstream idbuf;
-       idbuf << "TP #" << m_ID << " W #" << tid;
+       idbuf << "Q #" << &queue << " W #" << this;
        Utility::SetThreadName(idbuf.str());
 
        for (;;) {
                WorkItem wi;
 
                {
-                       boost::mutex::scoped_lock lock(m_Mutex);
+                       boost::mutex::scoped_lock lock(queue.Mutex);
+
+                       UpdateUtilization(ThreadIdle);
 
-                       UpdateThreadUtilization(tid, ThreadIdle);
+                       while (queue.Items.empty() && !queue.Stopped && !Zombie) {
+                               if (queue.Items.empty())
+                                       queue.CVStarved.notify_all();
 
-                       while (m_WorkItems.empty() && !m_Stopped && !m_Threads[tid].Zombie)
-                               m_WorkCV.wait(lock);
+                               queue.CV.wait(lock);
+                       }
 
-                       if (m_Threads[tid].Zombie)
+                       if (Zombie)
                                break;
 
-                       if (m_WorkItems.empty() && m_Stopped)
+                       if (queue.Items.empty() && queue.Stopped)
                                break;
 
-                       wi = m_WorkItems.front();
-                       m_WorkItems.pop_front();
+                       wi = queue.Items.front();
+                       queue.Items.pop_front();
 
-                       UpdateThreadUtilization(tid, ThreadBusy);
+                       UpdateUtilization(ThreadBusy);
                }
 
                double st = Utility::GetTime();;
@@ -134,14 +150,11 @@ void ThreadPool::QueueThreadProc(int tid)
                double latency = st - wi.Timestamp;
 
                {
-                       boost::mutex::scoped_lock lock(m_Mutex);
-
-                       m_WaitTime += latency;
-                       m_ServiceTime += et - st;
-                       m_TaskCount++;
+                       boost::mutex::scoped_lock lock(queue.Mutex);
 
-                       if (latency > m_MaxLatency)
-                               m_MaxLatency = latency;
+                       queue.WaitTime += latency;
+                       queue.ServiceTime += et - st;
+                       queue.TaskCount++;
                }
 
 #ifdef _DEBUG
@@ -175,9 +188,9 @@ void ThreadPool::QueueThreadProc(int tid)
 #endif /* _DEBUG */
        }
 
-       boost::mutex::scoped_lock lock(m_Mutex);
-       UpdateThreadUtilization(tid, ThreadDead);
-       m_Threads[tid].Zombie = false;
+       boost::mutex::scoped_lock lock(queue.Mutex);
+       UpdateUtilization(ThreadDead);
+       Zombie = false;
 }
 
 /**
@@ -192,14 +205,16 @@ bool ThreadPool::Post(const ThreadPool::WorkFunction& callback)
        wi.Callback = callback;
        wi.Timestamp = Utility::GetTime();
 
+       Queue& queue = m_Queues[Utility::Random() % (sizeof(m_Queues) / sizeof(m_Queues[0]))];
+
        {
-               boost::mutex::scoped_lock lock(m_Mutex);
+               boost::mutex::scoped_lock lock(queue.Mutex);
 
-               if (m_Stopped)
+               if (queue.Stopped)
                        return false;
 
-               m_WorkItems.push_back(wi);
-               m_WorkCV.notify_one();
+               queue.Items.push_back(wi);
+               queue.CV.notify_one();
        }
 
        return true;
@@ -212,34 +227,42 @@ void ThreadPool::ManagerThreadProc(void)
        Utility::SetThreadName(idbuf.str());
 
        for (;;) {
-               size_t pending, alive;
-               double avg_latency, max_latency;
-               double utilization = 0;
+               size_t total_pending = 0, total_alive = 0;
+               double total_avg_latency = 0;
+               double total_utilization = 0;
 
                {
-                       boost::mutex::scoped_lock lock(m_Mutex);
+                       boost::mutex::scoped_lock lock(m_MgmtMutex);
 
                        if (!m_Stopped)
                                m_MgmtCV.timed_wait(lock, boost::posix_time::seconds(5));
 
                        if (m_Stopped)
                                break;
+               }
 
-                       pending = m_WorkItems.size();
+               for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) {
+                       size_t pending, alive = 0;
+                       double avg_latency;
+                       double utilization = 0;
 
-                       alive = 0;
+                       Queue& queue = m_Queues[i];
 
-                       for (size_t i = 0; i < sizeof(m_Threads) / sizeof(m_Threads[0]); i++) {
-                               if (m_Threads[i].State != ThreadDead && !m_Threads[i].Zombie) {
+                       boost::mutex::scoped_lock lock(queue.Mutex);
+
+                       pending = queue.Items.size();
+
+                       for (size_t i = 0; i < sizeof(queue.Threads) / sizeof(queue.Threads[0]); i++) {
+                               if (queue.Threads[i].State != ThreadDead && !queue.Threads[i].Zombie) {
                                        alive++;
-                                       utilization += m_Threads[i].Utilization * 100;
+                                       utilization += queue.Threads[i].Utilization * 100;
                                }
                        }
 
                        utilization /= alive;
 
-                       if (m_TaskCount > 0)
-                               avg_latency = m_WaitTime / (m_TaskCount * 1.0);
+                       if (queue.TaskCount > 0)
+                               avg_latency = queue.WaitTime / (queue.TaskCount * 1.0);
                        else
                                avg_latency = 0;
 
@@ -248,9 +271,9 @@ void ThreadPool::ManagerThreadProc(void)
 
                                int tthreads = wthreads - alive;
 
-                               /* Don't ever kill the last threads. */
-                               if (alive + tthreads < 8)
-                                       tthreads = 8 - alive;
+                               /* Don't ever kill the last threads. */
+                               if (alive + tthreads < 2)
+                                       tthreads = 2 - alive;
 
                                /* Don't kill more than 8 threads at once. */
                                if (tthreads < -8)
@@ -258,33 +281,37 @@ void ThreadPool::ManagerThreadProc(void)
 
                                /* Spawn more workers if there are outstanding work items. */
                                if (tthreads > 0 && pending > 0)
-                                       tthreads = (Utility::GetTime() - Application::GetStartTime() < 300) ? 128 : 8;
+                                       tthreads = 8;
+
+                               if (m_MaxThreads != -1 && (alive + tthreads) * (sizeof(m_Queues) / sizeof(m_Queues[0])) > m_MaxThreads)
+                                       tthreads = m_MaxThreads / (sizeof(m_Queues) / sizeof(m_Queues[0])) - alive;
 
                                std::ostringstream msgbuf;
                                msgbuf << "Thread pool; current: " << alive << "; adjustment: " << tthreads;
                                Log(LogDebug, "base", msgbuf.str());
 
                                for (int i = 0; i < -tthreads; i++)
-                                       KillWorker();
+                                       queue.KillWorker(m_ThreadGroup);
 
                                for (int i = 0; i < tthreads; i++)
-                                       SpawnWorker();
+                                       queue.SpawnWorker(m_ThreadGroup);
                        }
 
-                       m_WaitTime = 0;
-                       m_ServiceTime = 0;
-                       m_TaskCount = 0;
+                       queue.WaitTime = 0;
+                       queue.ServiceTime = 0;
+                       queue.TaskCount = 0;
 
-                       max_latency = m_MaxLatency;
-                       m_MaxLatency = 0;
+                       total_pending += pending;
+                       total_alive += alive;
+                       total_avg_latency += avg_latency;
+                       total_utilization += utilization;
                }
 
                std::ostringstream msgbuf;
-               msgbuf << "Pool #" << m_ID << ": Pending tasks: " << pending << "; Average latency: "
-                   << (long)(avg_latency * 1000) << "ms"
-                   << "; Max latency: " << (long)(max_latency * 1000) << "ms"
-                   << "; Threads: " << alive
-                   << "; Pool utilization: " << utilization << "%";
+               msgbuf << "Pool #" << m_ID << ": Pending tasks: " << total_pending << "; Average latency: "
+                   << (long)(total_avg_latency * 1000 / (sizeof(m_Queues) / sizeof(m_Queues[0]))) << "ms"
+                   << "; Threads: " << total_alive
+                   << "; Pool utilization: " << (total_utilization / (sizeof(m_Queues) / sizeof(m_Queues[0])))  << "%";
                Log(LogInformation, "base", msgbuf.str());
        }
 }
@@ -292,14 +319,14 @@ void ThreadPool::ManagerThreadProc(void)
 /**
  * Note: Caller must hold m_Mutex
  */
-void ThreadPool::SpawnWorker(void)
+void ThreadPool::Queue::SpawnWorker(boost::thread_group& group)
 {
-       for (size_t i = 0; i < sizeof(m_Threads) / sizeof(m_Threads[0]); i++) {
-               if (m_Threads[i].State == ThreadDead) {
+       for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) {
+               if (Threads[i].State == ThreadDead) {
                        Log(LogDebug, "debug", "Spawning worker thread.");
 
-                       m_Threads[i] = WorkerThread(ThreadIdle);
-                       m_Threads[i].Thread = m_ThreadGroup.create_thread(boost::bind(&ThreadPool::QueueThreadProc, this, i));
+                       Threads[i] = WorkerThread(ThreadIdle);
+                       Threads[i].Thread = group.create_thread(boost::bind(&ThreadPool::WorkerThread::ThreadProc, boost::ref(Threads[i]), boost::ref(*this)));
 
                        break;
                }
@@ -307,20 +334,20 @@ void ThreadPool::SpawnWorker(void)
 }
 
 /**
- * Note: Caller must hold m_Mutex.
+ * Note: Caller must hold Mutex.
  */
-void ThreadPool::KillWorker(void)
+void ThreadPool::Queue::KillWorker(boost::thread_group& group)
 {
-       for (size_t i = 0; i < sizeof(m_Threads) / sizeof(m_Threads[0]); i++) {
-               if (m_Threads[i].State == ThreadIdle && !m_Threads[i].Zombie) {
+       for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) {
+               if (Threads[i].State == ThreadIdle && !Threads[i].Zombie) {
                        Log(LogDebug, "base", "Killing worker thread.");
 
-                       m_ThreadGroup.remove_thread(m_Threads[i].Thread);
-                       m_Threads[i].Thread->detach();
-                       delete m_Threads[i].Thread;
+                       group.remove_thread(Threads[i].Thread);
+                       Threads[i].Thread->detach();
+                       delete Threads[i].Thread;
 
-                       m_Threads[i].Zombie = true;
-                       m_WorkCV.notify_all();
+                       Threads[i].Zombie = true;
+                       CV.notify_all();
 
                        break;
                }
@@ -334,27 +361,35 @@ void ThreadPool::StatsThreadProc(void)
        Utility::SetThreadName(idbuf.str());
 
        for (;;) {
-               boost::mutex::scoped_lock lock(m_Mutex);
+               {
+                       boost::mutex::scoped_lock lock(m_MgmtMutex);
 
-               if (!m_Stopped)
-                       m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(250));
+                       if (!m_Stopped)
+                               m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(250));
 
-               if (m_Stopped)
-                       break;
+                       if (m_Stopped)
+                               break;
+               }
+
+               for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) {
+                       Queue& queue = m_Queues[i];
 
-               for (size_t i = 0; i < sizeof(m_Threads) / sizeof(m_Threads[0]); i++)
-                       UpdateThreadUtilization(i);
+                       boost::mutex::scoped_lock lock(queue.Mutex);
+
+                       for (size_t i = 0; i < sizeof(queue.Threads) / sizeof(queue.Threads[0]); i++)
+                               queue.Threads[i].UpdateUtilization();
+               }
        }
 }
 
 /**
- * Note: Caller must hold m_Mutex.
+ * Note: Caller must hold queue Mutex.
  */
-void ThreadPool::UpdateThreadUtilization(int tid, ThreadState state)
+void ThreadPool::WorkerThread::UpdateUtilization(ThreadState state)
 {
        double utilization;
 
-       switch (m_Threads[tid].State) {
+       switch (State) {
                case ThreadDead:
                        return;
                case ThreadIdle:
@@ -368,16 +403,16 @@ void ThreadPool::UpdateThreadUtilization(int tid, ThreadState state)
        }
 
        double now = Utility::GetTime();
-       double time = now - m_Threads[tid].LastUpdate;
+       double time = now - LastUpdate;
 
        const double avg_time = 5.0;
 
        if (time > avg_time)
                time = avg_time;
 
-       m_Threads[tid].Utilization = (m_Threads[tid].Utilization * (avg_time - time) + utilization * time) / avg_time;
-       m_Threads[tid].LastUpdate = now;
+       Utilization = (Utilization * (avg_time - time) + utilization * time) / avg_time;
+       LastUpdate = now;
 
        if (state != ThreadUnspecified)
-               m_Threads[tid].State = state;
+               State = state;
 }
index 5f7650dcd2939a3a1a956f3843c6338098caa50f..848d05a5f4e46926d7ddaaf521a3a424e7f8de23 100644 (file)
@@ -40,11 +40,12 @@ class I2_BASE_API ThreadPool
 public:
        typedef boost::function<void ()> WorkFunction;
 
-       ThreadPool(void);
+       ThreadPool(int max_threads = -1);
        ~ThreadPool(void);
 
+       void Start(void);
        void Stop(void);
-       void Join(void);
+       void Join(bool wait_for_stop = false);
 
        bool Post(const WorkFunction& callback);
 
@@ -57,6 +58,14 @@ private:
                ThreadBusy
        };
 
+       struct WorkItem
+       {
+               WorkFunction Callback;
+               double Timestamp;
+       };
+
+       struct Queue;
+
        struct WorkerThread
        {
                ThreadState State;
@@ -68,43 +77,51 @@ private:
                WorkerThread(ThreadState state = ThreadDead)
                        : State(state), Zombie(false), Utilization(0), LastUpdate(0), Thread(NULL)
                { }
+
+               void UpdateUtilization(ThreadState state = ThreadUnspecified);
+
+               void ThreadProc(Queue& queue);
        };
 
-       int m_ID;
-       static int m_NextID;
+       struct Queue
+       {
+               boost::mutex Mutex;
+               boost::condition_variable CV;
+               boost::condition_variable CVStarved;
 
-       boost::thread_group m_ThreadGroup;
-       WorkerThread m_Threads[4096];
+               std::deque<WorkItem> Items;
 
-       double m_WaitTime;
-       double m_ServiceTime;
-       int m_TaskCount;
+               double WaitTime;
+               double ServiceTime;
+               int TaskCount;
 
-       double m_MaxLatency;
+               bool Stopped;
 
-       boost::mutex m_Mutex;
-       boost::condition_variable m_WorkCV;
-       boost::condition_variable m_MgmtCV;
+               WorkerThread Threads[256];
 
-       bool m_Stopped;
+               Queue(void)
+                       : WaitTime(0), ServiceTime(0), TaskCount(0), Stopped(false)
+               { }
 
-       struct WorkItem
-       {
-               WorkFunction Callback;
-               double Timestamp;
+               void SpawnWorker(boost::thread_group& group);
+               void KillWorker(boost::thread_group& group);
        };
 
+       int m_ID;
+       static int m_NextID;
 
-       std::deque<WorkItem> m_WorkItems;
+       int m_MaxThreads;
 
-       void QueueThreadProc(int tid);
-       void ManagerThreadProc(void);
-       void StatsThreadProc(void);
+       boost::thread_group m_ThreadGroup;
 
-       void SpawnWorker(void);
-       void KillWorker(void);
+       boost::mutex m_MgmtMutex;
+       boost::condition_variable m_MgmtCV;
+       bool m_Stopped;
 
-       void UpdateThreadUtilization(int tid, ThreadState state = ThreadUnspecified);
+       Queue m_Queues[16];
+
+       void ManagerThreadProc(void);
+       void StatsThreadProc(void);
 };
 
 }
index 9ae1af45946a57371ee35ad1ae5d8fa257a89f96..f60e6771830a0b9e745e637739dd34b23796dde8 100644 (file)
@@ -40,6 +40,7 @@
 using namespace icinga;
 
 boost::thread_specific_ptr<String> Utility::m_ThreadName;
+boost::thread_specific_ptr<unsigned int> Utility::m_RandSeed;
 
 /**
  * Demangles a symbol name.
@@ -739,10 +740,18 @@ int Utility::CompareVersion(const String& v1, const String& v2)
 
 int Utility::Random(void)
 {
-       static boost::mutex mtx;
-       boost::mutex::scoped_lock lock(mtx);
-
+#ifdef _WIN32
        return rand();
+#else /* _WIN32 */
+       unsigned int *seed = m_RandSeed.get();
+
+       if (!seed) {
+               seed = new unsigned int(Utility::GetTime());
+               m_RandSeed.reset(seed);
+       }
+
+       return rand_r(seed);
+#endif /* _WIN32 */
 }
 
 tm Utility::LocalTime(time_t ts)
index 07e56edec06d0522167a00dccf7ecf268c28c8e8..6fef1d6081b94541997da6889247771d012c54c2 100644 (file)
@@ -114,6 +114,7 @@ private:
        Utility(void);
 
        static boost::thread_specific_ptr<String> m_ThreadName;
+       static boost::thread_specific_ptr<unsigned int> m_RandSeed;
 };
 
 }
index 26720749de88ce659b8536c0964ae67971d24efb..4dc6eae7ec790c58900696f7d34781c99d9fc915 100644 (file)
@@ -178,21 +178,24 @@ DynamicObject::Ptr ConfigItem::Commit(void)
        DynamicObject::Ptr dobj = dtype->CreateObject(properties);
        dobj->Register();
 
+       m_Object = dobj;
+       
        return dobj;
 }
 
+DynamicObject::Ptr ConfigItem::GetObject(void) const
+{
+       return m_Object;
+}
+
 /**
  * Registers the configuration item.
  */
 void ConfigItem::Register(void)
 {
-       ASSERT(!OwnsLock());
-
-       {
-               ObjectLock olock(this);
+       boost::mutex::scoped_lock lock(m_Mutex);
 
-               m_Items[std::make_pair(m_Type, m_Name)] = GetSelf();
-       }
+       m_Items[std::make_pair(m_Type, m_Name)] = GetSelf();
 }
 
 /**
@@ -244,34 +247,49 @@ bool ConfigItem::ActivateItems(bool validateOnly)
 
        Log(LogInformation, "config", "Validating config items (step 1)...");
 
+       ThreadPool tp(32);
+       
        BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
-               kv.second->ValidateItem();
+               tp.Post(boost::bind(&ConfigItem::ValidateItem, kv.second));
        }
+       
+       tp.Join();
 
        if (ConfigCompilerContext::GetInstance()->HasErrors())
                return false;
 
-       Log(LogInformation, "config", "Activating config items");
+       Log(LogInformation, "config", "Comitting config items");
 
+       BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
+               tp.Post(boost::bind(&ConfigItem::Commit, kv.second));
+       }
+       
+       tp.Join();
+       
        std::vector<DynamicObject::Ptr> objects;
-
        BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
-               DynamicObject::Ptr object = kv.second->Commit();
+               DynamicObject::Ptr object = kv.second->GetObject();
 
                if (object)
                        objects.push_back(object);
        }
-
+       
+       Log(LogInformation, "config", "Triggering OnConfigLoaded signal for config items");
+       
        BOOST_FOREACH(const DynamicObject::Ptr& object, objects) {
-               object->OnConfigLoaded();
+               tp.Post(boost::bind(&DynamicObject::OnConfigLoaded, object));
        }
+       
+       tp.Join();
 
        Log(LogInformation, "config", "Validating config items (step 2)...");
 
        BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
-               kv.second->ValidateItem();
+               tp.Post(boost::bind(&ConfigItem::ValidateItem, kv.second));
        }
 
+       tp.Join();
+       
        if (ConfigCompilerContext::GetInstance()->HasErrors())
                return false;
 
@@ -281,6 +299,8 @@ bool ConfigItem::ActivateItems(bool validateOnly)
        /* restore the previous program state */
        DynamicObject::RestoreObjects(Application::GetStatePath());
 
+       Log(LogInformation, "config", "Triggering Start signal for config items");
+       
        BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
                BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
                        if (object->IsActive())
@@ -289,11 +309,21 @@ bool ConfigItem::ActivateItems(bool validateOnly)
 #ifdef _DEBUG
                        Log(LogDebug, "config", "Activating object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "'");
 #endif /* _DEBUG */
-                       object->Start();
-
+                       tp.Post(boost::bind(&DynamicObject::Start, object));
+               }
+       }
+       
+       tp.Join();
+       
+#ifdef _DEBUG
+       BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
+               BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
                        ASSERT(object->IsActive());
                }
        }
+#endif /* _DEBUG */
+
+       Log(LogInformation, "config", "Activated all objects.");
 
        return true;
 }
index 98a65fdf28a483a803cd9516fa73b40b9c5dbb33..b16353f671b88ae525fe1f9568b0fbe2b13a9907 100644 (file)
@@ -61,6 +61,8 @@ public:
 
        void ValidateItem(void);
 
+        DynamicObject::Ptr GetObject(void) const;
+        
        static bool ActivateItems(bool validateOnly);
        static void DiscardItems(void);
 
@@ -79,6 +81,8 @@ private:
 
        ExpressionList::Ptr m_LinkedExpressionList;
        Dictionary::Ptr m_Properties;
+        
+        DynamicObject::Ptr m_Object;
 
        static boost::mutex m_Mutex;