Improve config compiler performance.

Refs #5327
This commit is contained in:
Gunnar Beutner 2013-12-06 21:46:50 +01:00 committed by Gunnar Beutner
parent 9134c7fab6
commit 37179cdf32
7 changed files with 243 additions and 147 deletions

View File

@ -181,7 +181,7 @@ void Application::RunEventLoop(void) const
GetTP().Stop(); GetTP().Stop();
m_ShuttingDown = false; m_ShuttingDown = false;
GetTP().Join(); GetTP().Join(true);
Timer::Uninitialize(); Timer::Uninitialize();
#endif /* _DEBUG */ #endif /* _DEBUG */

View File

@ -33,79 +33,95 @@ using namespace icinga;
int ThreadPool::m_NextID = 1; int ThreadPool::m_NextID = 1;
ThreadPool::ThreadPool(void) ThreadPool::ThreadPool(int max_threads)
: m_ID(m_NextID++), m_WaitTime(0), m_ServiceTime(0), : m_ID(m_NextID++), m_Stopped(false), m_MaxThreads(max_threads)
m_TaskCount(0), m_Stopped(false)
{ {
for (int i = 0; i < 2; i++) if (m_MaxThreads != -1 && m_MaxThreads < sizeof(m_Queues) / sizeof(m_Queues[0]))
SpawnWorker(); m_MaxThreads = sizeof(m_Queues) / sizeof(m_Queues[0]);
m_ThreadGroup.create_thread(boost::bind(&ThreadPool::ManagerThreadProc, this)); Start();
m_ThreadGroup.create_thread(boost::bind(&ThreadPool::StatsThreadProc, this));
} }
ThreadPool::~ThreadPool(void) ThreadPool::~ThreadPool(void)
{ {
Stop(); 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) 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_Stopped = true;
m_WorkCV.notify_all();
m_MgmtCV.notify_all(); m_MgmtCV.notify_all();
} }
/** /**
* Waits for all worker threads to finish. * Waits for all worker threads to finish.
*/ */
void ThreadPool::Join(void) void ThreadPool::Join(bool wait_for_stop)
{ {
{ if (wait_for_stop) {
boost::mutex::scoped_lock lock(m_Mutex);
while (!m_Stopped || !m_WorkItems.empty()) {
lock.unlock();
Utility::Sleep(0.5);
lock.lock();
}
}
m_ThreadGroup.join_all(); m_ThreadGroup.join_all();
return;
}
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. * Waits for work items and processes them.
*/ */
void ThreadPool::QueueThreadProc(int tid) void ThreadPool::WorkerThread::ThreadProc(Queue& queue)
{ {
std::ostringstream idbuf; std::ostringstream idbuf;
idbuf << "TP #" << m_ID << " W #" << tid; idbuf << "Q #" << &queue << " W #" << this;
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
for (;;) { for (;;) {
WorkItem wi; WorkItem wi;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(queue.Mutex);
UpdateThreadUtilization(tid, ThreadIdle); UpdateUtilization(ThreadIdle);
while (m_WorkItems.empty() && !m_Stopped && !m_Threads[tid].Zombie) while (queue.Items.empty() && !queue.Stopped && !Zombie) {
m_WorkCV.wait(lock); if (queue.Items.empty())
queue.CVStarved.notify_all();
if (m_Threads[tid].Zombie) queue.CV.wait(lock);
}
if (Zombie)
break; break;
if (m_WorkItems.empty() && m_Stopped) if (queue.Items.empty() && queue.Stopped)
break; break;
wi = m_WorkItems.front(); wi = queue.Items.front();
m_WorkItems.pop_front(); queue.Items.pop_front();
UpdateThreadUtilization(tid, ThreadBusy); UpdateUtilization(ThreadBusy);
} }
double st = Utility::GetTime();; double st = Utility::GetTime();;
@ -134,14 +150,11 @@ void ThreadPool::QueueThreadProc(int tid)
double latency = st - wi.Timestamp; double latency = st - wi.Timestamp;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(queue.Mutex);
m_WaitTime += latency; queue.WaitTime += latency;
m_ServiceTime += et - st; queue.ServiceTime += et - st;
m_TaskCount++; queue.TaskCount++;
if (latency > m_MaxLatency)
m_MaxLatency = latency;
} }
#ifdef _DEBUG #ifdef _DEBUG
@ -175,9 +188,9 @@ void ThreadPool::QueueThreadProc(int tid)
#endif /* _DEBUG */ #endif /* _DEBUG */
} }
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(queue.Mutex);
UpdateThreadUtilization(tid, ThreadDead); UpdateUtilization(ThreadDead);
m_Threads[tid].Zombie = false; Zombie = false;
} }
/** /**
@ -192,14 +205,16 @@ bool ThreadPool::Post(const ThreadPool::WorkFunction& callback)
wi.Callback = callback; wi.Callback = callback;
wi.Timestamp = Utility::GetTime(); wi.Timestamp = Utility::GetTime();
{ Queue& queue = m_Queues[Utility::Random() % (sizeof(m_Queues) / sizeof(m_Queues[0]))];
boost::mutex::scoped_lock lock(m_Mutex);
if (m_Stopped) {
boost::mutex::scoped_lock lock(queue.Mutex);
if (queue.Stopped)
return false; return false;
m_WorkItems.push_back(wi); queue.Items.push_back(wi);
m_WorkCV.notify_one(); queue.CV.notify_one();
} }
return true; return true;
@ -212,34 +227,42 @@ void ThreadPool::ManagerThreadProc(void)
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
for (;;) { for (;;) {
size_t pending, alive; size_t total_pending = 0, total_alive = 0;
double avg_latency, max_latency; double total_avg_latency = 0;
double utilization = 0; double total_utilization = 0;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_MgmtMutex);
if (!m_Stopped) if (!m_Stopped)
m_MgmtCV.timed_wait(lock, boost::posix_time::seconds(5)); m_MgmtCV.timed_wait(lock, boost::posix_time::seconds(5));
if (m_Stopped) if (m_Stopped)
break; 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++) { boost::mutex::scoped_lock lock(queue.Mutex);
if (m_Threads[i].State != ThreadDead && !m_Threads[i].Zombie) {
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++; alive++;
utilization += m_Threads[i].Utilization * 100; utilization += queue.Threads[i].Utilization * 100;
} }
} }
utilization /= alive; utilization /= alive;
if (m_TaskCount > 0) if (queue.TaskCount > 0)
avg_latency = m_WaitTime / (m_TaskCount * 1.0); avg_latency = queue.WaitTime / (queue.TaskCount * 1.0);
else else
avg_latency = 0; avg_latency = 0;
@ -248,9 +271,9 @@ void ThreadPool::ManagerThreadProc(void)
int tthreads = wthreads - alive; int tthreads = wthreads - alive;
/* Don't ever kill the last 8 threads. */ /* Don't ever kill the last threads. */
if (alive + tthreads < 8) if (alive + tthreads < 2)
tthreads = 8 - alive; tthreads = 2 - alive;
/* Don't kill more than 8 threads at once. */ /* Don't kill more than 8 threads at once. */
if (tthreads < -8) if (tthreads < -8)
@ -258,33 +281,37 @@ void ThreadPool::ManagerThreadProc(void)
/* Spawn more workers if there are outstanding work items. */ /* Spawn more workers if there are outstanding work items. */
if (tthreads > 0 && pending > 0) 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; std::ostringstream msgbuf;
msgbuf << "Thread pool; current: " << alive << "; adjustment: " << tthreads; msgbuf << "Thread pool; current: " << alive << "; adjustment: " << tthreads;
Log(LogDebug, "base", msgbuf.str()); Log(LogDebug, "base", msgbuf.str());
for (int i = 0; i < -tthreads; i++) for (int i = 0; i < -tthreads; i++)
KillWorker(); queue.KillWorker(m_ThreadGroup);
for (int i = 0; i < tthreads; i++) for (int i = 0; i < tthreads; i++)
SpawnWorker(); queue.SpawnWorker(m_ThreadGroup);
} }
m_WaitTime = 0; queue.WaitTime = 0;
m_ServiceTime = 0; queue.ServiceTime = 0;
m_TaskCount = 0; queue.TaskCount = 0;
max_latency = m_MaxLatency; total_pending += pending;
m_MaxLatency = 0; total_alive += alive;
total_avg_latency += avg_latency;
total_utilization += utilization;
} }
std::ostringstream msgbuf; std::ostringstream msgbuf;
msgbuf << "Pool #" << m_ID << ": Pending tasks: " << pending << "; Average latency: " msgbuf << "Pool #" << m_ID << ": Pending tasks: " << total_pending << "; Average latency: "
<< (long)(avg_latency * 1000) << "ms" << (long)(total_avg_latency * 1000 / (sizeof(m_Queues) / sizeof(m_Queues[0]))) << "ms"
<< "; Max latency: " << (long)(max_latency * 1000) << "ms" << "; Threads: " << total_alive
<< "; Threads: " << alive << "; Pool utilization: " << (total_utilization / (sizeof(m_Queues) / sizeof(m_Queues[0]))) << "%";
<< "; Pool utilization: " << utilization << "%";
Log(LogInformation, "base", msgbuf.str()); Log(LogInformation, "base", msgbuf.str());
} }
} }
@ -292,14 +319,14 @@ void ThreadPool::ManagerThreadProc(void)
/** /**
* Note: Caller must hold m_Mutex * 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++) { for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) {
if (m_Threads[i].State == ThreadDead) { if (Threads[i].State == ThreadDead) {
Log(LogDebug, "debug", "Spawning worker thread."); Log(LogDebug, "debug", "Spawning worker thread.");
m_Threads[i] = WorkerThread(ThreadIdle); Threads[i] = WorkerThread(ThreadIdle);
m_Threads[i].Thread = m_ThreadGroup.create_thread(boost::bind(&ThreadPool::QueueThreadProc, this, i)); Threads[i].Thread = group.create_thread(boost::bind(&ThreadPool::WorkerThread::ThreadProc, boost::ref(Threads[i]), boost::ref(*this)));
break; 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++) { for (size_t i = 0; i < sizeof(Threads) / sizeof(Threads[0]); i++) {
if (m_Threads[i].State == ThreadIdle && !m_Threads[i].Zombie) { if (Threads[i].State == ThreadIdle && !Threads[i].Zombie) {
Log(LogDebug, "base", "Killing worker thread."); Log(LogDebug, "base", "Killing worker thread.");
m_ThreadGroup.remove_thread(m_Threads[i].Thread); group.remove_thread(Threads[i].Thread);
m_Threads[i].Thread->detach(); Threads[i].Thread->detach();
delete m_Threads[i].Thread; delete Threads[i].Thread;
m_Threads[i].Zombie = true; Threads[i].Zombie = true;
m_WorkCV.notify_all(); CV.notify_all();
break; break;
} }
@ -334,27 +361,35 @@ void ThreadPool::StatsThreadProc(void)
Utility::SetThreadName(idbuf.str()); Utility::SetThreadName(idbuf.str());
for (;;) { for (;;) {
boost::mutex::scoped_lock lock(m_Mutex); {
boost::mutex::scoped_lock lock(m_MgmtMutex);
if (!m_Stopped) if (!m_Stopped)
m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(250)); m_MgmtCV.timed_wait(lock, boost::posix_time::milliseconds(250));
if (m_Stopped) if (m_Stopped)
break; break;
}
for (size_t i = 0; i < sizeof(m_Threads) / sizeof(m_Threads[0]); i++) for (int i = 0; i < sizeof(m_Queues) / sizeof(m_Queues[0]); i++) {
UpdateThreadUtilization(i); Queue& queue = m_Queues[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; double utilization;
switch (m_Threads[tid].State) { switch (State) {
case ThreadDead: case ThreadDead:
return; return;
case ThreadIdle: case ThreadIdle:
@ -368,16 +403,16 @@ void ThreadPool::UpdateThreadUtilization(int tid, ThreadState state)
} }
double now = Utility::GetTime(); double now = Utility::GetTime();
double time = now - m_Threads[tid].LastUpdate; double time = now - LastUpdate;
const double avg_time = 5.0; const double avg_time = 5.0;
if (time > avg_time) if (time > avg_time)
time = avg_time; time = avg_time;
m_Threads[tid].Utilization = (m_Threads[tid].Utilization * (avg_time - time) + utilization * time) / avg_time; Utilization = (Utilization * (avg_time - time) + utilization * time) / avg_time;
m_Threads[tid].LastUpdate = now; LastUpdate = now;
if (state != ThreadUnspecified) if (state != ThreadUnspecified)
m_Threads[tid].State = state; State = state;
} }

View File

@ -40,11 +40,12 @@ class I2_BASE_API ThreadPool
public: public:
typedef boost::function<void ()> WorkFunction; typedef boost::function<void ()> WorkFunction;
ThreadPool(void); ThreadPool(int max_threads = -1);
~ThreadPool(void); ~ThreadPool(void);
void Start(void);
void Stop(void); void Stop(void);
void Join(void); void Join(bool wait_for_stop = false);
bool Post(const WorkFunction& callback); bool Post(const WorkFunction& callback);
@ -57,6 +58,14 @@ private:
ThreadBusy ThreadBusy
}; };
struct WorkItem
{
WorkFunction Callback;
double Timestamp;
};
struct Queue;
struct WorkerThread struct WorkerThread
{ {
ThreadState State; ThreadState State;
@ -68,43 +77,51 @@ private:
WorkerThread(ThreadState state = ThreadDead) WorkerThread(ThreadState state = ThreadDead)
: State(state), Zombie(false), Utilization(0), LastUpdate(0), Thread(NULL) : State(state), Zombie(false), Utilization(0), LastUpdate(0), Thread(NULL)
{ } { }
void UpdateUtilization(ThreadState state = ThreadUnspecified);
void ThreadProc(Queue& queue);
};
struct Queue
{
boost::mutex Mutex;
boost::condition_variable CV;
boost::condition_variable CVStarved;
std::deque<WorkItem> Items;
double WaitTime;
double ServiceTime;
int TaskCount;
bool Stopped;
WorkerThread Threads[256];
Queue(void)
: WaitTime(0), ServiceTime(0), TaskCount(0), Stopped(false)
{ }
void SpawnWorker(boost::thread_group& group);
void KillWorker(boost::thread_group& group);
}; };
int m_ID; int m_ID;
static int m_NextID; static int m_NextID;
int m_MaxThreads;
boost::thread_group m_ThreadGroup; boost::thread_group m_ThreadGroup;
WorkerThread m_Threads[4096];
double m_WaitTime; boost::mutex m_MgmtMutex;
double m_ServiceTime;
int m_TaskCount;
double m_MaxLatency;
boost::mutex m_Mutex;
boost::condition_variable m_WorkCV;
boost::condition_variable m_MgmtCV; boost::condition_variable m_MgmtCV;
bool m_Stopped; bool m_Stopped;
struct WorkItem Queue m_Queues[16];
{
WorkFunction Callback;
double Timestamp;
};
std::deque<WorkItem> m_WorkItems;
void QueueThreadProc(int tid);
void ManagerThreadProc(void); void ManagerThreadProc(void);
void StatsThreadProc(void); void StatsThreadProc(void);
void SpawnWorker(void);
void KillWorker(void);
void UpdateThreadUtilization(int tid, ThreadState state = ThreadUnspecified);
}; };
} }

View File

@ -40,6 +40,7 @@
using namespace icinga; using namespace icinga;
boost::thread_specific_ptr<String> Utility::m_ThreadName; boost::thread_specific_ptr<String> Utility::m_ThreadName;
boost::thread_specific_ptr<unsigned int> Utility::m_RandSeed;
/** /**
* Demangles a symbol name. * Demangles a symbol name.
@ -739,10 +740,18 @@ int Utility::CompareVersion(const String& v1, const String& v2)
int Utility::Random(void) int Utility::Random(void)
{ {
static boost::mutex mtx; #ifdef _WIN32
boost::mutex::scoped_lock lock(mtx);
return rand(); 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) tm Utility::LocalTime(time_t ts)

View File

@ -114,6 +114,7 @@ private:
Utility(void); Utility(void);
static boost::thread_specific_ptr<String> m_ThreadName; static boost::thread_specific_ptr<String> m_ThreadName;
static boost::thread_specific_ptr<unsigned int> m_RandSeed;
}; };
} }

View File

@ -178,22 +178,25 @@ DynamicObject::Ptr ConfigItem::Commit(void)
DynamicObject::Ptr dobj = dtype->CreateObject(properties); DynamicObject::Ptr dobj = dtype->CreateObject(properties);
dobj->Register(); dobj->Register();
m_Object = dobj;
return dobj; return dobj;
} }
DynamicObject::Ptr ConfigItem::GetObject(void) const
{
return m_Object;
}
/** /**
* Registers the configuration item. * Registers the configuration item.
*/ */
void ConfigItem::Register(void) void ConfigItem::Register(void)
{ {
ASSERT(!OwnsLock()); boost::mutex::scoped_lock lock(m_Mutex);
{
ObjectLock olock(this);
m_Items[std::make_pair(m_Type, m_Name)] = GetSelf(); m_Items[std::make_pair(m_Type, m_Name)] = GetSelf();
} }
}
/** /**
* Retrieves a configuration item by type and name. * Retrieves a configuration item by type and name.
@ -244,34 +247,49 @@ bool ConfigItem::ActivateItems(bool validateOnly)
Log(LogInformation, "config", "Validating config items (step 1)..."); Log(LogInformation, "config", "Validating config items (step 1)...");
ThreadPool tp(32);
BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { 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()) if (ConfigCompilerContext::GetInstance()->HasErrors())
return false; return false;
Log(LogInformation, "config", "Activating config items"); Log(LogInformation, "config", "Comitting config items");
std::vector<DynamicObject::Ptr> objects;
BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) {
DynamicObject::Ptr object = kv.second->Commit(); 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->GetObject();
if (object) if (object)
objects.push_back(object); objects.push_back(object);
} }
Log(LogInformation, "config", "Triggering OnConfigLoaded signal for config items");
BOOST_FOREACH(const DynamicObject::Ptr& object, objects) { 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)..."); Log(LogInformation, "config", "Validating config items (step 2)...");
BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { 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()) if (ConfigCompilerContext::GetInstance()->HasErrors())
return false; return false;
@ -281,6 +299,8 @@ bool ConfigItem::ActivateItems(bool validateOnly)
/* restore the previous program state */ /* restore the previous program state */
DynamicObject::RestoreObjects(Application::GetStatePath()); DynamicObject::RestoreObjects(Application::GetStatePath());
Log(LogInformation, "config", "Triggering Start signal for config items");
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) { BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) { BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
if (object->IsActive()) if (object->IsActive())
@ -289,11 +309,21 @@ bool ConfigItem::ActivateItems(bool validateOnly)
#ifdef _DEBUG #ifdef _DEBUG
Log(LogDebug, "config", "Activating object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "'"); Log(LogDebug, "config", "Activating object '" + object->GetName() + "' of type '" + object->GetType()->GetName() + "'");
#endif /* _DEBUG */ #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()); ASSERT(object->IsActive());
} }
} }
#endif /* _DEBUG */
Log(LogInformation, "config", "Activated all objects.");
return true; return true;
} }

View File

@ -61,6 +61,8 @@ public:
void ValidateItem(void); void ValidateItem(void);
DynamicObject::Ptr GetObject(void) const;
static bool ActivateItems(bool validateOnly); static bool ActivateItems(bool validateOnly);
static void DiscardItems(void); static void DiscardItems(void);
@ -80,6 +82,8 @@ private:
ExpressionList::Ptr m_LinkedExpressionList; ExpressionList::Ptr m_LinkedExpressionList;
Dictionary::Ptr m_Properties; Dictionary::Ptr m_Properties;
DynamicObject::Ptr m_Object;
static boost::mutex m_Mutex; static boost::mutex m_Mutex;
typedef std::map<std::pair<String, String>, ConfigItem::Ptr> ItemMap; typedef std::map<std::pair<String, String>, ConfigItem::Ptr> ItemMap;