More lock refactoring. Yay.

This commit is contained in:
Gunnar Beutner 2013-03-02 09:07:47 +01:00
parent 572a477da3
commit 48485c5f26
67 changed files with 1741 additions and 1041 deletions

View File

@ -27,13 +27,9 @@ void CheckerComponent::Start(void)
{ {
m_Endpoint = Endpoint::MakeEndpoint("checker", false); m_Endpoint = Endpoint::MakeEndpoint("checker", false);
{ /* dummy registration so the delegation module knows this is a checker
ObjectLock olock(m_Endpoint); TODO: figure out a better way for this */
m_Endpoint->RegisterSubscription("checker");
/* 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::OnCheckerChanged.connect(bind(&CheckerComponent::CheckerChangedHandler, this, _1));
Service::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1)); Service::OnNextCheckChanged.connect(bind(&CheckerComponent::NextCheckChangedHandler, this, _1));
@ -50,10 +46,7 @@ void CheckerComponent::Start(void)
void CheckerComponent::Stop(void) void CheckerComponent::Stop(void)
{ {
{ m_Endpoint->Unregister();
ObjectLock olock(m_Endpoint);
m_Endpoint->Unregister();
}
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
@ -81,24 +74,14 @@ void CheckerComponent::CheckThreadProc(void)
CheckTimeView::iterator it = idx.begin(); CheckTimeView::iterator it = idx.begin();
Service::Ptr service = *it; Service::Ptr service = *it;
ObjectLock olock(service); /* also required for the key extractor. */
if (!service->IsRegistered()) { if (!service->IsRegistered()) {
idx.erase(it); idx.erase(it);
continue; continue;
} }
double wait; double wait = service->GetNextCheck() - Utility::GetTime();
{
ObjectLock olock(service);
wait = service->GetNextCheck() - Utility::GetTime();
}
if (wait > 0) { if (wait > 0) {
/* Release the object lock. */
olock.Unlock();
/* Make sure the service we just examined can be destroyed while we're waiting. */ /* Make sure the service we just examined can be destroyed while we're waiting. */
service.reset(); service.reset();
@ -113,19 +96,17 @@ void CheckerComponent::CheckThreadProc(void)
/* reschedule the service if checks are currently disabled /* reschedule the service if checks are currently disabled
* for it and this is not a forced check */ * for it and this is not a forced check */
if (!service->GetEnableActiveChecks()) { if (!service->GetEnableActiveChecks() && !service->GetForceNextCheck()) {
if (!service->GetForceNextCheck()) { Logger::Write(LogDebug, "checker", "Ignoring service check for disabled service: " + service->GetName());
Logger::Write(LogDebug, "checker", "Ignoring service check for disabled service: " + service->GetName());
service->UpdateNextCheck(); service->UpdateNextCheck();
typedef nth_index<ServiceSet, 1>::type CheckTimeView; typedef nth_index<ServiceSet, 1>::type CheckTimeView;
CheckTimeView& idx = boost::get<1>(m_IdleServices); CheckTimeView& idx = boost::get<1>(m_IdleServices);
idx.insert(service); idx.insert(service);
continue; continue;
}
} }
service->SetForceNextCheck(false); service->SetForceNextCheck(false);
@ -136,18 +117,9 @@ void CheckerComponent::CheckThreadProc(void)
m_PendingServices.insert(service); m_PendingServices.insert(service);
try { try {
olock.Unlock(); CheckerComponent::Ptr self = GetSelf();
Service::BeginExecuteCheck(service, boost::bind(&CheckerComponent::CheckCompletedHandler, self, 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) { } catch (const exception& ex) {
olock.Lock();
Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex)); Logger::Write(LogCritical, "checker", "Exception occured while checking service '" + service->GetName() + "': " + diagnostic_information(ex));
} }
} }
@ -156,7 +128,6 @@ void CheckerComponent::CheckThreadProc(void)
void CheckerComponent::CheckCompletedHandler(const Service::Ptr& service) void CheckerComponent::CheckCompletedHandler(const Service::Ptr& service)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* required for the key extractor */
/* remove the service from the list of pending services; if it's not in the /* remove the service from the list of pending services; if it's not in the
* list this was a manual (i.e. forced) check and we must not re-add the * list this was a manual (i.e. forced) check and we must not re-add the
@ -191,19 +162,9 @@ void CheckerComponent::CheckerChangedHandler(const Service::Ptr& service)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* also required for the key extractor */
String checker = service->GetCurrentChecker(); String checker = service->GetCurrentChecker();
EndpointManager::Ptr em = EndpointManager::GetInstance(); if (checker == EndpointManager::GetInstance()->GetIdentity() || Endpoint::GetByName(checker) == m_Endpoint) {
String identity;
{
ObjectLock elock(em);
identity = em->GetIdentity();
}
if (checker == identity || Endpoint::GetByName(checker) == m_Endpoint) {
if (m_PendingServices.find(service) != m_PendingServices.end()) if (m_PendingServices.find(service) != m_PendingServices.end())
return; return;
@ -220,8 +181,6 @@ void CheckerComponent::NextCheckChangedHandler(const Service::Ptr& service)
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
ObjectLock olock(service); /* required for the key extractor */
/* remove and re-insert the service from the set in order to force an index update */ /* remove and re-insert the service from the set in order to force an index update */
typedef nth_index<ServiceSet, 0>::type ServiceView; typedef nth_index<ServiceSet, 0>::type ServiceView;
ServiceView& idx = boost::get<0>(m_IdleServices); ServiceView& idx = boost::get<0>(m_IdleServices);

View File

@ -31,7 +31,7 @@ struct ServiceNextCheckExtractor
typedef double result_type; typedef double result_type;
/** /**
* @threadsafety Caller must hold the mutex for the service. * @threadsafety Always.
*/ */
double operator()(const Service::Ptr& service) double operator()(const Service::Ptr& service)
{ {

View File

@ -38,8 +38,6 @@ String CompatComponent::GetStatusPath(void) const
{ {
DynamicObject::Ptr config = GetConfig(); DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value statusPath = config->Get("status_path"); Value statusPath = config->Get("status_path");
if (statusPath.IsEmpty()) if (statusPath.IsEmpty())
return Application::GetLocalStateDir() + "/cache/icinga2/status.dat"; return Application::GetLocalStateDir() + "/cache/icinga2/status.dat";
@ -56,8 +54,6 @@ String CompatComponent::GetObjectsPath(void) const
{ {
DynamicObject::Ptr config = GetConfig(); DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value objectsPath = config->Get("objects_path"); Value objectsPath = config->Get("objects_path");
if (objectsPath.IsEmpty()) if (objectsPath.IsEmpty())
return Application::GetLocalStateDir() + "/cache/icinga2/objects.cache"; return Application::GetLocalStateDir() + "/cache/icinga2/objects.cache";
@ -74,8 +70,6 @@ String CompatComponent::GetLogPath(void) const
{ {
DynamicObject::Ptr config = GetConfig(); DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value logPath = config->Get("log_path"); Value logPath = config->Get("log_path");
if (logPath.IsEmpty()) if (logPath.IsEmpty())
return Application::GetLocalStateDir() + "/log/icinga2/compat"; return Application::GetLocalStateDir() + "/log/icinga2/compat";
@ -92,8 +86,6 @@ String CompatComponent::GetCommandPath(void) const
{ {
DynamicObject::Ptr config = GetConfig(); DynamicObject::Ptr config = GetConfig();
ObjectLock olock(config);
Value commandPath = config->Get("command_path"); Value commandPath = config->Get("command_path");
if (commandPath.IsEmpty()) if (commandPath.IsEmpty())
return Application::GetLocalStateDir() + "/run/icinga.cmd"; return Application::GetLocalStateDir() + "/run/icinga.cmd";
@ -107,7 +99,7 @@ String CompatComponent::GetCommandPath(void) const
void CompatComponent::Start(void) void CompatComponent::Start(void)
{ {
m_StatusTimer = boost::make_shared<Timer>(); m_StatusTimer = boost::make_shared<Timer>();
m_StatusTimer->SetInterval(5); m_StatusTimer->SetInterval(15);
m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this)); m_StatusTimer->OnTimerExpired.connect(boost::bind(&CompatComponent::StatusTimerHandler, this));
m_StatusTimer->Start(); m_StatusTimer->Start();
m_StatusTimer->Reschedule(0); m_StatusTimer->Reschedule(0);
@ -170,31 +162,24 @@ void CompatComponent::CommandPipeThread(const String& commandPath)
String command = line; String command = line;
ProcessCommand(command); try {
Logger::Write(LogInformation, "compat", "Executing external command: " + command);
ExternalCommandProcessor::Execute(command);
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "External command failed: " << diagnostic_information(ex);
Logger::Write(LogWarning, "compat", msgbuf.str());
}
} }
fclose(fp); fclose(fp);
} }
} }
void CompatComponent::ProcessCommand(const String& command)
{
try {
Logger::Write(LogInformation, "compat", "Executing external command: " + command);
ExternalCommandProcessor::Execute(command);
} catch (const exception& ex) {
stringstream msgbuf;
msgbuf << "External command failed: " << diagnostic_information(ex);
Logger::Write(LogWarning, "compat", msgbuf.str());
}
}
#endif /* _WIN32 */ #endif /* _WIN32 */
void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, CompatObjectType type) void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, CompatObjectType type)
{ {
ObjectLock olock(owner);
Service::Ptr service; Service::Ptr service;
Host::Ptr host; Host::Ptr host;
Dictionary::Ptr comments = owner->GetComments(); Dictionary::Ptr comments = owner->GetComments();
@ -202,6 +187,8 @@ void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, Compa
if (!comments) if (!comments)
return; return;
ObjectLock olock(comments);
String id; String id;
Dictionary::Ptr comment; Dictionary::Ptr comment;
BOOST_FOREACH(tie(id, comment), comments) { BOOST_FOREACH(tie(id, comment), comments) {
@ -230,27 +217,17 @@ void CompatComponent::DumpComments(ostream& fp, const Service::Ptr& owner, Compa
void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, CompatObjectType type) void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, CompatObjectType type)
{ {
Dictionary::Ptr downtimes; Host::Ptr host = owner->GetHost();
String short_name, host_name;
Host::Ptr host;
{ if (!host)
ObjectLock olock(owner); return;
downtimes = owner->GetDowntimes(); Dictionary::Ptr downtimes = owner->GetDowntimes();
short_name = owner->GetShortName();
host = owner->GetHost();
}
{
ObjectLock olock(host);
host_name = host->GetName();
}
if (!downtimes) if (!downtimes)
return; return;
ObjectLock dlock(downtimes); ObjectLock olock(downtimes);
String id; String id;
Dictionary::Ptr downtime; Dictionary::Ptr downtime;
@ -264,14 +241,14 @@ void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, Comp
fp << "hostdowntime {" << "\n"; fp << "hostdowntime {" << "\n";
else else
fp << "servicedowntime {" << "\n" fp << "servicedowntime {" << "\n"
<< "\t" << "service_description=" << short_name << "\n"; << "\t" << "service_description=" << owner->GetShortName() << "\n";
Dictionary::Ptr triggeredByObj = Service::GetDowntimeByID(downtime->Get("triggered_by")); Dictionary::Ptr triggeredByObj = Service::GetDowntimeByID(downtime->Get("triggered_by"));
int triggeredByLegacy = 0; int triggeredByLegacy = 0;
if (triggeredByObj) if (triggeredByObj)
triggeredByLegacy = triggeredByObj->Get("legacy_id"); triggeredByLegacy = triggeredByObj->Get("legacy_id");
fp << "\t" << "host_name=" << host_name << "\n" fp << "\t" << "host_name=" << host->GetName() << "\n"
<< "\t" << "downtime_id=" << static_cast<String>(downtime->Get("legacy_id")) << "\n" << "\t" << "downtime_id=" << static_cast<String>(downtime->Get("legacy_id")) << "\n"
<< "\t" << "entry_time=" << static_cast<double>(downtime->Get("entry_time")) << "\n" << "\t" << "entry_time=" << static_cast<double>(downtime->Get("entry_time")) << "\n"
<< "\t" << "start_time=" << static_cast<double>(downtime->Get("start_time")) << "\n" << "\t" << "start_time=" << static_cast<double>(downtime->Get("start_time")) << "\n"
@ -290,23 +267,19 @@ void CompatComponent::DumpDowntimes(ostream& fp, const Service::Ptr& owner, Comp
void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host) void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
{ {
{ fp << "hoststatus {" << "\n"
ObjectLock olock(host); << "\t" << "host_name=" << host->GetName() << "\n";
fp << "hoststatus {" << "\n"
<< "\t" << "host_name=" << host->GetName() << "\n";
}
ServiceState hcState = StateOK; ServiceState hcState = StateOK;
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) { ObjectLock olock(hc);
ObjectLock olock(hc);
if (hc)
hcState = hc->GetState(); hcState = hc->GetState();
}
int state; int state;
if (!Host::IsReachable(host)) if (!host->IsReachable())
state = 2; /* unreachable */ state = 2; /* unreachable */
else if (hcState != StateOK) else if (hcState != StateOK)
state = 1; /* down */ state = 1; /* down */
@ -327,15 +300,11 @@ void CompatComponent::DumpHostStatus(ostream& fp, const Host::Ptr& host)
void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host) void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
{ {
{ fp << "define host {" << "\n"
ObjectLock olock(host); << "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "display_name" << "\t" << host->GetDisplayName() << "\n";
fp << "define host {" << "\n" set<Host::Ptr> parents = host->GetParentHosts();
<< "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "display_name" << "\t" << host->GetDisplayName() << "\n";
}
set<Host::Ptr> parents = Host::GetParentHosts(host);
if (!parents.empty()) { if (!parents.empty()) {
fp << "\t" << "parents" << "\t"; fp << "\t" << "parents" << "\t";
@ -343,7 +312,7 @@ void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
fp << "\n"; fp << "\n";
} }
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) { if (hc) {
ObjectLock olock(hc); ObjectLock olock(hc);
@ -372,94 +341,77 @@ void CompatComponent::DumpHostObject(ostream& fp, const Host::Ptr& host)
void CompatComponent::DumpServiceStatusAttrs(ostream& fp, const Service::Ptr& service, CompatObjectType type) void CompatComponent::DumpServiceStatusAttrs(ostream& fp, const Service::Ptr& service, CompatObjectType type)
{ {
ObjectLock olock(service);
String output; String output;
String perfdata; String perfdata;
double schedule_end = -1; double schedule_end = -1;
Dictionary::Ptr cr; Dictionary::Ptr cr = service->GetLastCheckResult();
int state, state_type;
Host::Ptr host;
{
ObjectLock olock(service);
cr = service->GetLastCheckResult();
state = service->GetState();
state_type = service->GetStateType();
host = service->GetHost();
}
if (cr) { if (cr) {
ObjectLock olock(cr);
output = cr->Get("output"); output = cr->Get("output");
schedule_end = cr->Get("schedule_end"); schedule_end = cr->Get("schedule_end");
perfdata = cr->Get("performance_data_raw"); perfdata = cr->Get("performance_data_raw");
} }
int state = service->GetState();
if (state > StateUnknown) if (state > StateUnknown)
state = StateUnknown; state = StateUnknown;
if (type == CompatTypeHost) { if (type == CompatTypeHost) {
if (state == StateOK || state == StateWarning) if (state == StateOK || state == StateWarning)
state = 0; state = 0; /* UP */
else else
state = 1; state = 1; /* DOWN */
if (!Host::IsReachable(host)) Host::Ptr host = service->GetHost();
state = 2;
if (!host)
return;
if (!host->IsReachable())
state = 2; /* UNREACHABLE */
} }
{ fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n"
ObjectLock olock(service); << "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n"
fp << "\t" << "check_interval=" << service->GetCheckInterval() / 60.0 << "\n" << "\t" << "should_be_scheduled=1" << "\n"
<< "\t" << "retry_interval=" << service->GetRetryInterval() / 60.0 << "\n" << "\t" << "check_execution_time=" << Service::CalculateExecutionTime(cr) << "\n"
<< "\t" << "has_been_checked=" << (service->GetLastCheckResult() ? 1 : 0) << "\n" << "\t" << "check_latency=" << Service::CalculateLatency(cr) << "\n"
<< "\t" << "should_be_scheduled=1" << "\n" << "\t" << "current_state=" << state << "\n"
<< "\t" << "check_execution_time=" << Service::CalculateExecutionTime(cr) << "\n" << "\t" << "state_type=" << service->GetStateType() << "\n"
<< "\t" << "check_latency=" << Service::CalculateLatency(cr) << "\n" << "\t" << "plugin_output=" << output << "\n"
<< "\t" << "current_state=" << state << "\n" << "\t" << "performance_data=" << perfdata << "\n"
<< "\t" << "state_type=" << state_type << "\n" << "\t" << "last_check=" << schedule_end << "\n"
<< "\t" << "plugin_output=" << output << "\n" << "\t" << "next_check=" << service->GetNextCheck() << "\n"
<< "\t" << "performance_data=" << perfdata << "\n" << "\t" << "current_attempt=" << service->GetCurrentCheckAttempt() << "\n"
<< "\t" << "last_check=" << schedule_end << "\n" << "\t" << "max_attempts=" << service->GetMaxCheckAttempts() << "\n"
<< "\t" << "next_check=" << service->GetNextCheck() << "\n" << "\t" << "last_state_change=" << service->GetLastStateChange() << "\n"
<< "\t" << "current_attempt=" << service->GetCurrentCheckAttempt() << "\n" << "\t" << "last_hard_state_change=" << service->GetLastHardStateChange() << "\n"
<< "\t" << "max_attempts=" << service->GetMaxCheckAttempts() << "\n" << "\t" << "last_update=" << time(NULL) << "\n"
<< "\t" << "last_state_change=" << service->GetLastStateChange() << "\n" << "\t" << "notifications_enabled=" << (service->GetEnableNotifications() ? 1 : 0) << "\n"
<< "\t" << "last_hard_state_change=" << service->GetLastHardStateChange() << "\n" << "\t" << "active_checks_enabled=" << (service->GetEnableActiveChecks() ? 1 : 0) <<"\n"
<< "\t" << "last_update=" << time(NULL) << "\n" << "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n"
<< "\t" << "notifications_enabled=" << (service->GetEnableNotifications() ? 1 : 0) << "\n" << "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n"
<< "\t" << "active_checks_enabled=" << (service->GetEnableActiveChecks() ? 1 : 0) <<"\n" << "\t" << "acknowledgement_type=" << static_cast<int>(service->GetAcknowledgement()) << "\n"
<< "\t" << "passive_checks_enabled=" << (service->GetEnablePassiveChecks() ? 1 : 0) << "\n" << "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n"
<< "\t" << "problem_has_been_acknowledged=" << (service->GetAcknowledgement() != AcknowledgementNone ? 1 : 0) << "\n" << "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n"
<< "\t" << "acknowledgement_type=" << static_cast<int>(service->GetAcknowledgement()) << "\n" << "\t" << "last_notification=" << service->GetLastNotification() << "\n";
<< "\t" << "acknowledgement_end_time=" << service->GetAcknowledgementExpiry() << "\n"
<< "\t" << "scheduled_downtime_depth=" << (service->IsInDowntime() ? 1 : 0) << "\n"
<< "\t" << "last_notification=" << service->GetLastNotification() << "\n";
}
} }
void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service) void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service)
{ {
String host_name, short_name; Host::Ptr host = service->GetHost();
Host::Ptr host;
{ if (!host)
ObjectLock olock(service); return;
short_name = service->GetShortName();
host = service->GetHost();
}
{
ObjectLock olock(host);
host_name = host->GetName();
}
fp << "servicestatus {" << "\n" fp << "servicestatus {" << "\n"
<< "\t" << "host_name=" << host_name << "\n" << "\t" << "host_name=" << host->GetName() << "\n"
<< "\t" << "service_description=" << short_name << "\n"; << "\t" << "service_description=" << service->GetShortName() << "\n";
DumpServiceStatusAttrs(fp, service, CompatTypeService); DumpServiceStatusAttrs(fp, service, CompatTypeService);
@ -472,29 +424,17 @@ void CompatComponent::DumpServiceStatus(ostream& fp, const Service::Ptr& service
void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service) void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service)
{ {
Host::Ptr host; Host::Ptr host = service->GetHost();
String host_name, short_name;
{
ObjectLock olock(service);
host = service->GetHost();
short_name = service->GetShortName();
}
if (!host) if (!host)
return; return;
{
ObjectLock olock(host);
host_name = host->GetName();
}
{ {
ObjectLock olock(service); ObjectLock olock(service);
fp << "define service {" << "\n" fp << "define service {" << "\n"
<< "\t" << "host_name" << "\t" << host_name << "\n" << "\t" << "host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "service_description" << "\t" << short_name << "\n" << "\t" << "service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "display_name" << "\t" << service->GetDisplayName() << "\n" << "\t" << "display_name" << "\t" << service->GetDisplayName() << "\n"
<< "\t" << "check_command" << "\t" << "check_i2" << "\n" << "\t" << "check_command" << "\t" << "check_i2" << "\n"
<< "\t" << "check_interval" << "\t" << service->GetCheckInterval() / 60.0 << "\n" << "\t" << "check_interval" << "\t" << service->GetCheckInterval() / 60.0 << "\n"
@ -510,14 +450,22 @@ void CompatComponent::DumpServiceObject(ostream& fp, const Service::Ptr& service
<< "\n"; << "\n";
} }
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(service)) { BOOST_FOREACH(const Service::Ptr& parent, service->GetParentServices()) {
ObjectLock plock(parent); Host::Ptr host = service->GetHost();
if (!host)
continue;
Host::Ptr parent_host = parent->GetHost();
if (!parent_host)
continue;
fp << "define servicedependency {" << "\n" fp << "define servicedependency {" << "\n"
<< "\t" << "dependent_host_name" << "\t" << host_name << "\n" << "\t" << "dependent_host_name" << "\t" << host->GetName() << "\n"
<< "\t" << "dependent_service_description" << "\t" << service->GetShortName() << "\n" << "\t" << "dependent_service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "host_name" << "\t" << parent->GetHost()->GetName() << "\n" << "\t" << "host_name" << "\t" << parent_host->GetName() << "\n"
<< "\t" << "service_description" << "\t" << short_name << "\n" << "\t" << "service_description" << "\t" << service->GetShortName() << "\n"
<< "\t" << "execution_failure_criteria" << "\t" << "n" << "\n" << "\t" << "execution_failure_criteria" << "\t" << "n" << "\n"
<< "\t" << "notification_failure_criteria" << "\t" << "w,u,c" << "\n" << "\t" << "notification_failure_criteria" << "\t" << "w,u,c" << "\n"
<< "\t" << "}" << "\n" << "\t" << "}" << "\n"
@ -552,18 +500,10 @@ void CompatComponent::StatusTimerHandler(void)
<< "\t" << "}" << "\n" << "\t" << "}" << "\n"
<< "\n"; << "\n";
double startTime;
{
IcingaApplication::Ptr app = IcingaApplication::GetInstance();
ObjectLock olock(app);
startTime = app->GetStartTime();
}
statusfp << "programstatus {" << "\n" statusfp << "programstatus {" << "\n"
<< "icinga_pid=" << Utility::GetPid() << "\n" << "icinga_pid=" << Utility::GetPid() << "\n"
<< "\t" << "daemon_mode=1" << "\n" << "\t" << "daemon_mode=1" << "\n"
<< "\t" << "program_start=" << startTime << "\n" << "\t" << "program_start=" << IcingaApplication::GetInstance()->GetStartTime() << "\n"
<< "\t" << "active_service_checks_enabled=1" << "\n" << "\t" << "active_service_checks_enabled=1" << "\n"
<< "\t" << "passive_service_checks_enabled=1" << "\n" << "\t" << "passive_service_checks_enabled=1" << "\n"
<< "\t" << "active_host_checks_enabled=1" << "\n" << "\t" << "active_host_checks_enabled=1" << "\n"
@ -622,17 +562,13 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp; stringstream tempobjectfp;
tempobjectfp << std::fixed; tempobjectfp << std::fixed;
{ tempobjectfp << "define hostgroup {" << "\n"
ObjectLock olock(hg); << "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
tempobjectfp << "define hostgroup {" << "\n" << "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
<< "\t" << "hostgroup_name" << "\t" << hg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << hg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << hg->GetActionUrl() << "\n";
}
tempobjectfp << "\t" << "members" << "\t"; tempobjectfp << "\t" << "members" << "\t";
DumpNameList(tempobjectfp, HostGroup::GetMembers(hg)); DumpNameList(tempobjectfp, hg->GetMembers());
tempobjectfp << "\n" tempobjectfp << "\n"
<< "\t" << "}" << "\n"; << "\t" << "}" << "\n";
@ -659,35 +595,22 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp; stringstream tempobjectfp;
tempobjectfp << std::fixed; tempobjectfp << std::fixed;
{ tempobjectfp << "define servicegroup {" << "\n"
ObjectLock olock(sg); << "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
tempobjectfp << "define servicegroup {" << "\n" << "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
<< "\t" << "servicegroup_name" << "\t" << sg->GetName() << "\n"
<< "\t" << "notes_url" << "\t" << sg->GetNotesUrl() << "\n"
<< "\t" << "action_url" << "\t" << sg->GetActionUrl() << "\n";
}
tempobjectfp << "\t" << "members" << "\t"; tempobjectfp << "\t" << "members" << "\t";
vector<String> sglist; vector<String> sglist;
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Host::Ptr host; Host::Ptr host = service->GetHost();
String host_name, short_name;
{ if (!host)
ObjectLock olock(service); continue;
host = service->GetHost();
short_name = service->GetShortName();
}
{ sglist.push_back(host->GetName());
ObjectLock olock(host); sglist.push_back(service->GetShortName());
host_name = host->GetName();
}
sglist.push_back(host_name);
sglist.push_back(short_name);
} }
DumpStringList(tempobjectfp, sglist); DumpStringList(tempobjectfp, sglist);
@ -704,19 +627,15 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp; stringstream tempobjectfp;
tempobjectfp << std::fixed; tempobjectfp << std::fixed;
{ tempobjectfp << "define contact {" << "\n"
ObjectLock olock(user); << "\t" << "contact_name" << "\t" << user->GetName() << "\n"
<< "\t" << "alias" << "\t" << user->GetDisplayName() << "\n"
tempobjectfp << "define contact {" << "\n" << "\t" << "service_notification_options" << "\t" << "w,u,c,r,f,s" << "\n"
<< "\t" << "contact_name" << "\t" << user->GetName() << "\n" << "\t" << "host_notification_options" << "\t" << "d,u,r,f,s" << "\n"
<< "\t" << "alias" << "\t" << user->GetDisplayName() << "\n" << "\t" << "host_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "service_notification_options" << "\t" << "w,u,c,r,f,s" << "\n" << "\t" << "service_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "host_notification_options" << "\t" << "d,u,r,f,s" << "\n" << "\t" << "}" << "\n"
<< "\t" << "host_notifications_enabled" << "\t" << 1 << "\n" << "\n";
<< "\t" << "service_notifications_enabled" << "\t" << 1 << "\n"
<< "\t" << "}" << "\n"
<< "\n";
}
objectfp << tempobjectfp.str(); objectfp << tempobjectfp.str();
} }
@ -727,16 +646,12 @@ void CompatComponent::StatusTimerHandler(void)
stringstream tempobjectfp; stringstream tempobjectfp;
tempobjectfp << std::fixed; tempobjectfp << std::fixed;
{ tempobjectfp << "define contactgroup {" << "\n"
ObjectLock olock(ug); << "\t" << "contactgroup_name" << "\t" << ug->GetName() << "\n"
<< "\t" << "alias" << "\t" << ug->GetDisplayName() << "\n";
tempobjectfp << "define contactgroup {" << "\n"
<< "\t" << "contactgroup_name" << "\t" << ug->GetName() << "\n"
<< "\t" << "alias" << "\t" << ug->GetDisplayName() << "\n";
}
tempobjectfp << "\t" << "members" << "\t"; tempobjectfp << "\t" << "members" << "\t";
DumpNameList(tempobjectfp, UserGroup::GetMembers(ug)); DumpNameList(tempobjectfp, ug->GetMembers());
tempobjectfp << "\n" tempobjectfp << "\n"
<< "\t" << "}" << "\n"; << "\t" << "}" << "\n";

View File

@ -43,7 +43,6 @@ private:
thread m_CommandThread; thread m_CommandThread;
void CommandPipeThread(const String& commandPath); void CommandPipeThread(const String& commandPath);
void ProcessCommand(const String& command);
#endif /* _WIN32 */ #endif /* _WIN32 */
Timer::Ptr m_StatusTimer; Timer::Ptr m_StatusTimer;

View File

@ -46,8 +46,6 @@ set<Endpoint::Ptr> DelegationComponent::GetCheckerCandidates(const Service::Ptr&
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Endpoint")) {
Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object); Endpoint::Ptr endpoint = dynamic_pointer_cast<Endpoint>(object);
ObjectLock olock(endpoint);
String myIdentity = EndpointManager::GetInstance()->GetIdentity(); String myIdentity = EndpointManager::GetInstance()->GetIdentity();
/* ignore local-only endpoints (unless this is a local-only instance) */ /* ignore local-only endpoints (unless this is a local-only instance) */
@ -93,8 +91,8 @@ void DelegationComponent::DelegationTimerHandler(void)
services.push_back(service); services.push_back(service);
ObjectLock olock(service);
String checker = service->GetCurrentChecker(); String checker = service->GetCurrentChecker();
if (checker.IsEmpty()) if (checker.IsEmpty())
continue; continue;
@ -112,8 +110,6 @@ void DelegationComponent::DelegationTimerHandler(void)
/* re-assign services */ /* re-assign services */
BOOST_FOREACH(const Service::Ptr& service, services) { BOOST_FOREACH(const Service::Ptr& service, services) {
ObjectLock olock(service);
String checker = service->GetCurrentChecker(); String checker = service->GetCurrentChecker();
Endpoint::Ptr oldEndpoint = Endpoint::GetByName(checker); Endpoint::Ptr oldEndpoint = Endpoint::GetByName(checker);
@ -141,8 +137,6 @@ void DelegationComponent::DelegationTimerHandler(void)
/* don't re-assign service if the checker is still valid /* don't re-assign service if the checker is still valid
* and doesn't have too many services */ * and doesn't have too many services */
ObjectLock elock(oldEndpoint);
if (oldEndpoint && oldEndpoint->IsConnected() && if (oldEndpoint && oldEndpoint->IsConnected() &&
candidates.find(oldEndpoint) != candidates.end() && candidates.find(oldEndpoint) != candidates.end() &&
histogram[oldEndpoint] <= avg_services + overflow_tolerance) histogram[oldEndpoint] <= avg_services + overflow_tolerance)
@ -162,7 +156,6 @@ void DelegationComponent::DelegationTimerHandler(void)
if (histogram[candidate] > avg_services) if (histogram[candidate] > avg_services)
continue; continue;
ObjectLock clock(candidate);
service->SetCurrentChecker(candidate->GetName()); service->SetCurrentChecker(candidate->GetName());
histogram[candidate]++; histogram[candidate]++;
@ -189,6 +182,8 @@ void DelegationComponent::DelegationTimerHandler(void)
cr->Set("state", StateUncheckable); cr->Set("state", StateUncheckable);
cr->Set("output", "No checker is available for this service."); cr->Set("output", "No checker is available for this service.");
cr->Seal();
service->ProcessCheckResult(cr); service->ProcessCheckResult(cr);
Logger::Write(LogWarning, "delegation", "Can't delegate service: " + service->GetName()); Logger::Write(LogWarning, "delegation", "Can't delegate service: " + service->GetName());
@ -203,8 +198,6 @@ void DelegationComponent::DelegationTimerHandler(void)
Endpoint::Ptr endpoint; Endpoint::Ptr endpoint;
int count; int count;
BOOST_FOREACH(tie(endpoint, count), histogram) { BOOST_FOREACH(tie(endpoint, count), histogram) {
ObjectLock olock(endpoint);
stringstream msgbuf; stringstream msgbuf;
msgbuf << "histogram: " << endpoint->GetName() << " - " << count; msgbuf << "histogram: " << endpoint->GetName() << " - " << count;
Logger::Write(LogInformation, "delegation", msgbuf.str()); Logger::Write(LogInformation, "delegation", msgbuf.str());

View File

@ -54,16 +54,12 @@ void DemoComponent::Stop(void)
*/ */
void DemoComponent::DemoTimerHandler(void) void DemoComponent::DemoTimerHandler(void)
{ {
Logger::Write(LogInformation, "demo", "Sending multicast 'hello" Logger::Write(LogInformation, "demo", "Sending multicast 'hello world' message.");
" world' message.");
RequestMessage request; RequestMessage request;
request.SetMethod("demo::HelloWorld"); request.SetMethod("demo::HelloWorld");
EndpointManager::Ptr em = EndpointManager::GetInstance(); EndpointManager::GetInstance()->SendMulticastMessage(m_Endpoint, request);
ObjectLock olock(em);
em->SendMulticastMessage(m_Endpoint, request);
} }
/** /**

View File

@ -29,13 +29,9 @@ REGISTER_COMPONENT("notification", NotificationComponent);
void NotificationComponent::Start(void) void NotificationComponent::Start(void)
{ {
m_Endpoint = Endpoint::MakeEndpoint("notification", false); m_Endpoint = Endpoint::MakeEndpoint("notification", false);
m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
{ boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
ObjectLock olock(m_Endpoint); _3));
m_Endpoint->RegisterTopicHandler("icinga::SendNotifications",
boost::bind(&NotificationComponent::SendNotificationsRequestHandler, this, _2,
_3));
}
m_NotificationTimer = boost::make_shared<Timer>(); m_NotificationTimer = boost::make_shared<Timer>();
m_NotificationTimer->SetInterval(5); m_NotificationTimer->SetInterval(5);
@ -48,6 +44,7 @@ void NotificationComponent::Start(void)
*/ */
void NotificationComponent::Stop(void) void NotificationComponent::Stop(void)
{ {
m_Endpoint->Unregister();
} }
/** /**
@ -61,6 +58,8 @@ void NotificationComponent::NotificationTimerHandler(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object); Service::Ptr service = dynamic_pointer_cast<Service>(object);
bool reachable = service->IsReachable();
ObjectLock olock(service); ObjectLock olock(service);
if (service->GetStateType() == StateTypeSoft) if (service->GetStateType() == StateTypeSoft)
@ -75,7 +74,7 @@ void NotificationComponent::NotificationTimerHandler(void)
if (service->GetLastNotification() > now - service->GetNotificationInterval()) if (service->GetLastNotification() > now - service->GetNotificationInterval())
continue; continue;
if (Service::IsReachable(service) && !service->IsInDowntime() && !service->IsAcknowledged()) if (reachable && !service->IsInDowntime() && !service->IsAcknowledged())
service->RequestNotifications(NotificationProblem); service->RequestNotifications(NotificationProblem);
} }
} }
@ -100,5 +99,5 @@ void NotificationComponent::SendNotificationsRequestHandler(const Endpoint::Ptr&
Service::Ptr service = Service::GetByName(svc); Service::Ptr service = Service::GetByName(svc);
Service::SendNotifications(service, static_cast<NotificationType>(type)); service->SendNotifications(static_cast<NotificationType>(type));
} }

View File

@ -79,9 +79,9 @@ Application::~Application(void)
* *
* @returns The application object. * @returns The application object.
*/ */
Application *Application::GetInstance(void) Application::Ptr Application::GetInstance(void)
{ {
return m_Instance; return m_Instance->GetSelf();
} }
int Application::GetArgC(void) int Application::GetArgC(void)
@ -285,7 +285,7 @@ void Application::SigIntHandler(int signum)
{ {
assert(signum == SIGINT); assert(signum == SIGINT);
Application *instance = Application::GetInstance(); Application::Ptr instance = Application::GetInstance();
if (!instance) if (!instance)
return; return;
@ -320,7 +320,7 @@ void Application::SigAbrtHandler(int signum)
*/ */
BOOL WINAPI Application::CtrlHandler(DWORD type) BOOL WINAPI Application::CtrlHandler(DWORD type)
{ {
Application *instance = Application::GetInstance(); Application::Ptr instance = Application::GetInstance();
if (!instance) if (!instance)
return TRUE; return TRUE;
@ -410,6 +410,8 @@ int Application::Run(void)
*/ */
void Application::UpdatePidFile(const String& filename) void Application::UpdatePidFile(const String& filename)
{ {
ObjectLock olock(this);
ClosePidFile(); ClosePidFile();
/* There's just no sane way of getting a file descriptor for a /* There's just no sane way of getting a file descriptor for a
@ -420,7 +422,15 @@ void Application::UpdatePidFile(const String& filename)
BOOST_THROW_EXCEPTION(runtime_error("Could not open PID file '" + filename + "'")); BOOST_THROW_EXCEPTION(runtime_error("Could not open PID file '" + filename + "'"));
#ifndef _WIN32 #ifndef _WIN32
Utility::SetCloExec(fileno(m_PidFile)); int fd = fileno(m_PidFile);
Utility::SetCloExec(fd);
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
Logger::Write(LogCritical, "base", "Could not lock PID file. Make sure that only one instance of the application is running.");
_exit(EXIT_FAILURE);
}
#endif /* _WIN32 */ #endif /* _WIN32 */
fprintf(m_PidFile, "%d", Utility::GetPid()); fprintf(m_PidFile, "%d", Utility::GetPid());
@ -432,6 +442,8 @@ void Application::UpdatePidFile(const String& filename)
*/ */
void Application::ClosePidFile(void) void Application::ClosePidFile(void)
{ {
ObjectLock olock(this);
if (m_PidFile != NULL) if (m_PidFile != NULL)
fclose(m_PidFile); fclose(m_PidFile);

View File

@ -37,7 +37,7 @@ public:
Application(const Dictionary::Ptr& serializedUpdate); Application(const Dictionary::Ptr& serializedUpdate);
~Application(void); ~Application(void);
static Application *GetInstance(void); static Application::Ptr GetInstance(void);
int Run(void); int Run(void);

View File

@ -23,6 +23,7 @@ using namespace icinga;
REGISTER_TYPE(Component); REGISTER_TYPE(Component);
boost::mutex Component::m_Mutex;
map<String, Component::Factory> Component::m_Factories; map<String, Component::Factory> Component::m_Factories;
/** /**
@ -38,18 +39,24 @@ Component::Component(const Dictionary::Ptr& properties)
(void) Utility::LoadIcingaLibrary(GetName(), true); (void) Utility::LoadIcingaLibrary(GetName(), true);
map<String, Factory>::iterator it; Component::Factory factory;
it = m_Factories.find(GetName());
if (it == m_Factories.end()) {
BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName())); boost::mutex::scoped_lock lock(m_Mutex);
IComponent::Ptr impl = it->second(); map<String, Factory>::iterator it;
it = m_Factories.find(GetName());
if (!impl) if (it == m_Factories.end())
BOOST_THROW_EXCEPTION(invalid_argument("Unknown component: " + GetName()));
factory = it->second;
}
m_Impl = factory();
if (!m_Impl)
BOOST_THROW_EXCEPTION(runtime_error("Component factory returned NULL.")); BOOST_THROW_EXCEPTION(runtime_error("Component factory returned NULL."));
m_Impl = impl;
} }
/** /**
@ -67,7 +74,9 @@ Component::~Component(void)
*/ */
void Component::Start(void) void Component::Start(void)
{ {
m_Impl->m_Config = GetSelf(); ObjectLock olock(this);
m_Impl->SetConfig(GetSelf());
m_Impl->Start(); m_Impl->Start();
} }
@ -95,9 +104,21 @@ void Component::AddSearchDir(const String& componentDirectory)
*/ */
DynamicObject::Ptr IComponent::GetConfig(void) const DynamicObject::Ptr IComponent::GetConfig(void) const
{ {
ObjectLock olock(this);
return m_Config.lock(); return m_Config.lock();
} }
/**
* Sets the configuration for this component.
*/
void IComponent::SetConfig(const DynamicObject::Ptr& config)
{
ObjectLock olock(this);
m_Config = config;
}
/** /**
* Starts the component. * Starts the component.
*/ */
@ -119,5 +140,7 @@ void IComponent::Stop(void)
*/ */
void Component::Register(const String& name, const Component::Factory& factory) void Component::Register(const String& name, const Component::Factory& factory)
{ {
boost::mutex::scoped_lock lock(m_Mutex);
m_Factories[name] = factory; m_Factories[name] = factory;
} }

View File

@ -44,6 +44,8 @@ private:
DynamicObject::WeakPtr m_Config; /**< The configuration object for this DynamicObject::WeakPtr m_Config; /**< The configuration object for this
component. */ component. */
void SetConfig(const DynamicObject::Ptr& config);
friend class Component; friend class Component;
}; };
@ -74,6 +76,7 @@ private:
IComponent::Ptr m_Impl; /**< The implementation object for this IComponent::Ptr m_Impl; /**< The implementation object for this
component. */ component. */
static boost::mutex m_Mutex;
static map<String, Factory> m_Factories; static map<String, Factory> m_Factories;
}; };

View File

@ -33,7 +33,7 @@ signals2::signal<void (double, const set<DynamicObject::WeakPtr>&)> DynamicObjec
signals2::signal<void (double, const DynamicObject::Ptr&)> DynamicObject::OnFlushObject; signals2::signal<void (double, const DynamicObject::Ptr&)> DynamicObject::OnFlushObject;
DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject) DynamicObject::DynamicObject(const Dictionary::Ptr& serializedObject)
: m_EventSafe(false), m_ConfigTx(0), m_Registered(false) : m_ConfigTx(0), m_Registered(false)
{ {
RegisterAttribute("__name", Attribute_Config, &m_Name); RegisterAttribute("__name", Attribute_Config, &m_Name);
RegisterAttribute("__type", Attribute_Config, &m_Type); RegisterAttribute("__type", Attribute_Config, &m_Type);
@ -115,7 +115,8 @@ Dictionary::Ptr DynamicObject::BuildUpdate(double sinceTx, int attributeTypes) c
void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate, void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
int allowedTypes) int allowedTypes)
{ {
assert(OwnsLock()); ObjectLock olock(this);
assert(serializedUpdate->IsSealed()); assert(serializedUpdate->IsSealed());
Value configTxValue = serializedUpdate->Get("configTx"); Value configTxValue = serializedUpdate->Get("configTx");
@ -132,7 +133,7 @@ void DynamicObject::ApplyUpdate(const Dictionary::Ptr& serializedUpdate,
assert(attrs->IsSealed()); assert(attrs->IsSealed());
{ {
ObjectLock olock(attrs); ObjectLock alock(attrs);
Dictionary::Iterator it; Dictionary::Iterator it;
for (it = attrs->Begin(); it != attrs->End(); it++) { for (it = attrs->Begin(); it != attrs->End(); it++) {
@ -233,7 +234,7 @@ void DynamicObject::InternalSetAttribute(const String& name, const Value& data,
m_ConfigTx = tx; m_ConfigTx = tx;
} }
if (GetEventSafe()) { if (m_Registered) {
/* We can't call GetSelf() in the constructor or destructor. /* We can't call GetSelf() in the constructor or destructor.
* The Register() function will take care of adding this * The Register() function will take care of adding this
* object to the list of modified objects later on if we can't * object to the list of modified objects later on if we can't
@ -365,17 +366,16 @@ String DynamicObject::GetSource(void) const
void DynamicObject::Register(void) void DynamicObject::Register(void)
{ {
assert(OwnsLock()); assert(!OwnsLock());
/* It's now safe to send us attribute events. */ DynamicObject::Ptr self = GetSelf();
SetEventSafe(true);
/* Add this new object to the list of modified objects. /* Add this new object to the list of modified objects.
* We're doing this here because we can't construct * We're doing this here because we can't construct
* a while WeakPtr from within the object's constructor. */ * a while WeakPtr from within the object's constructor. */
{ {
boost::mutex::scoped_lock lock(m_TransactionMutex); boost::mutex::scoped_lock lock(m_TransactionMutex);
m_ModifiedObjects.insert(GetSelf()); m_ModifiedObjects.insert(self);
} }
{ {
@ -384,7 +384,6 @@ void DynamicObject::Register(void)
DynamicObject::Ptr dobj = dtype->GetObject(GetName()); DynamicObject::Ptr dobj = dtype->GetObject(GetName());
DynamicObject::Ptr self = GetSelf();
assert(!dobj || dobj == self); assert(!dobj || dobj == self);
if (!dobj) if (!dobj)
@ -394,6 +393,8 @@ void DynamicObject::Register(void)
void DynamicObject::OnRegistrationCompleted(void) void DynamicObject::OnRegistrationCompleted(void)
{ {
assert(!OwnsLock());
DynamicObject::Ptr object; DynamicObject::Ptr object;
{ {
@ -402,14 +403,24 @@ void DynamicObject::OnRegistrationCompleted(void)
Start(); Start();
Flush();
object = GetSelf(); object = GetSelf();
} }
OnRegistered(object); OnRegistered(object);
} }
void DynamicObject::OnUnregistrationCompleted(void)
{
assert(!OwnsLock());
{
ObjectLock olock(this);
m_Registered = false;
}
OnUnregistered(GetSelf());
}
void DynamicObject::Start(void) void DynamicObject::Start(void)
{ {
assert(OwnsLock()); assert(OwnsLock());
@ -419,25 +430,30 @@ void DynamicObject::Start(void)
void DynamicObject::Unregister(void) void DynamicObject::Unregister(void)
{ {
assert(OwnsLock()); assert(!OwnsLock());
DynamicObject::Ptr self = GetSelf();
DynamicType::Ptr dtype = GetType(); DynamicType::Ptr dtype = GetType();
ObjectLock olock(dtype);
if (!dtype || !dtype->GetObject(GetName())) if (!dtype)
return; return;
dtype->UnregisterObject(GetSelf()); {
ObjectLock olock(dtype);
OnUnregistered(GetSelf()); dtype->UnregisterObject(self);
}
} }
ScriptTask::Ptr DynamicObject::MakeMethodTask(const String& method, ScriptTask::Ptr DynamicObject::MakeMethodTask(const String& method,
const vector<Value>& arguments) const vector<Value>& arguments)
{ {
assert(OwnsLock()); Dictionary::Ptr methods;
Dictionary::Ptr methods = m_Methods; {
ObjectLock olock(this);
methods = m_Methods;
}
String funcName = methods->Get(method); String funcName = methods->Get(method);
@ -471,13 +487,6 @@ void DynamicObject::DumpObjects(const String& filename)
sfp->Start(); sfp->Start();
BOOST_FOREACH(const DynamicType::Ptr& type, DynamicType::GetTypes()) { 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()) { BOOST_FOREACH(const DynamicObject::Ptr& object, type->GetObjects()) {
ObjectLock olock(object); ObjectLock olock(object);
@ -486,7 +495,7 @@ void DynamicObject::DumpObjects(const String& filename)
Dictionary::Ptr persistentObject = boost::make_shared<Dictionary>(); Dictionary::Ptr persistentObject = boost::make_shared<Dictionary>();
persistentObject->Set("type", type_name); persistentObject->Set("type", type->GetName());
persistentObject->Set("name", object->GetName()); persistentObject->Set("name", object->GetName());
int types = Attribute_Local | Attribute_Replicated; int types = Attribute_Local | Attribute_Replicated;
@ -558,10 +567,8 @@ void DynamicObject::RestoreObjects(const String& filename)
if (hasConfig && !object) { if (hasConfig && !object) {
object = DynamicType::CreateObject(dt, update); object = DynamicType::CreateObject(dt, update);
ObjectLock olock(object);
object->Register(); object->Register();
} else if (object) { } else if (object) {
ObjectLock olock(object);
object->ApplyUpdate(update, Attribute_All); object->ApplyUpdate(update, Attribute_All);
} }
@ -579,7 +586,6 @@ void DynamicObject::DeactivateObjects(void)
{ {
BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) { BOOST_FOREACH(const DynamicType::Ptr& dt, DynamicType::GetTypes()) {
BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) { BOOST_FOREACH(const DynamicObject::Ptr& object, dt->GetObjects()) {
ObjectLock olock(object);
object->Unregister(); object->Unregister();
} }
} }
@ -624,31 +630,28 @@ void DynamicObject::NewTx(void)
BOOST_FOREACH(const DynamicObject::WeakPtr& wobject, objects) { BOOST_FOREACH(const DynamicObject::WeakPtr& wobject, objects) {
DynamicObject::Ptr object = wobject.lock(); DynamicObject::Ptr object = wobject.lock();
if (!object) if (!object || !object->IsRegistered())
continue; continue;
map<String, Value, string_iless> attrs; map<String, Value, string_iless> attrs;
bool event_safe;
{ {
ObjectLock olock(object); ObjectLock olock(object);
attrs.swap(object->m_ModifiedAttributes); attrs.swap(object->m_ModifiedAttributes);
event_safe = object->GetEventSafe();
} }
/* Send attribute events if it's safe to do so. */ map<String, Value, string_iless>::iterator it;
if (event_safe) { for (it = attrs.begin(); it != attrs.end(); it++)
map<String, Value, string_iless>::iterator it; object->OnAttributeChanged(it->first, it->second);
for (it = attrs.begin(); it != attrs.end(); it++)
object->OnAttributeChanged(it->first, it->second);
}
} }
OnTransactionClosing(tx, objects); OnTransactionClosing(tx, objects);
} }
void DynamicObject::OnAttributeChanged(const String&, const Value&) void DynamicObject::OnAttributeChanged(const String&, const Value&)
{ } {
assert(!OwnsLock());
}
/* /*
* @threadsafety Always. * @threadsafety Always.
@ -665,17 +668,3 @@ const DynamicObject::AttributeMap& DynamicObject::GetAttributes(void) const
return m_Attributes; return m_Attributes;
} }
void DynamicObject::SetEventSafe(bool safe)
{
assert(OwnsLock());
m_EventSafe = safe;
}
bool DynamicObject::GetEventSafe(void) const
{
assert(OwnsLock());
return m_EventSafe;
}

View File

@ -252,9 +252,6 @@ public:
const AttributeMap& GetAttributes(void) const; const AttributeMap& GetAttributes(void) const;
void SetEventSafe(bool initialized);
bool GetEventSafe(void) const;
static DynamicObject::Ptr GetObject(const String& type, const String& name); static DynamicObject::Ptr GetObject(const String& type, const String& name);
static void DumpObjects(const String& filename); static void DumpObjects(const String& filename);
@ -265,6 +262,8 @@ public:
protected: protected:
virtual void OnRegistrationCompleted(void); virtual void OnRegistrationCompleted(void);
virtual void OnUnregistrationCompleted(void);
virtual void OnAttributeChanged(const String& name, const Value& oldValue); virtual void OnAttributeChanged(const String& name, const Value& oldValue);
private: private:
@ -284,7 +283,6 @@ private:
Attribute<Dictionary::Ptr> m_Methods; Attribute<Dictionary::Ptr> m_Methods;
bool m_Registered; bool m_Registered;
bool m_EventSafe;
static double m_CurrentTx; static double m_CurrentTx;

View File

@ -103,12 +103,11 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object)
void DynamicType::UnregisterObject(const DynamicObject::Ptr& object) void DynamicType::UnregisterObject(const DynamicObject::Ptr& object)
{ {
ObjectLock olock(object);
object->SetEventSafe(false);
assert(OwnsLock()); assert(OwnsLock());
m_ObjectMap.erase(object->GetName()); m_ObjectMap.erase(object->GetName());
m_ObjectSet.erase(object); m_ObjectSet.erase(object);
object->OnUnregistrationCompleted();
} }
/** /**

View File

@ -21,7 +21,9 @@
using namespace icinga; using namespace icinga;
#ifdef _DEBUG
boost::mutex Object::m_DebugMutex; boost::mutex Object::m_DebugMutex;
#endif /* _DEBUG */
/** /**
* Default constructor for the Object class. * Default constructor for the Object class.
@ -49,6 +51,7 @@ Object::SharedPtrHolder Object::GetSelf(void)
return Object::SharedPtrHolder(shared_from_this()); return Object::SharedPtrHolder(shared_from_this());
} }
#ifdef _DEBUG
/** /**
* Checks if the calling thread owns the lock on this object or is currently * 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. * in the constructor or destructor and therefore implicitly owns the lock.
@ -73,3 +76,4 @@ bool Object::OwnsLock(void) const
return true; return true;
} }
#endif /* _DEBUG */

View File

@ -100,7 +100,9 @@ protected:
SharedPtrHolder GetSelf(void); SharedPtrHolder GetSelf(void);
#ifdef _DEBUG
bool OwnsLock(void) const; bool OwnsLock(void) const;
#endif /* _DEBUG */
private: private:
Object(const Object& other); Object(const Object& other);
@ -110,7 +112,9 @@ private:
mutable unsigned int m_LockCount; mutable unsigned int m_LockCount;
mutable boost::thread::id m_LockOwner; mutable boost::thread::id m_LockOwner;
#ifdef _DEBUG
static boost::mutex m_DebugMutex; static boost::mutex m_DebugMutex;
#endif /* _DEBUG */
friend class ObjectLock; friend class ObjectLock;
}; };

View File

@ -21,6 +21,10 @@
using namespace icinga; using namespace icinga;
#ifdef _DEBUG
static __thread int g_LockCount;
#endif /* _DEBUG */
ObjectLock::ObjectLock(void) ObjectLock::ObjectLock(void)
: m_Object(NULL), m_Lock() : m_Object(NULL), m_Lock()
{ } { }
@ -50,21 +54,42 @@ void ObjectLock::Lock(void)
m_Lock = recursive_mutex::scoped_lock(m_Object->m_Mutex); m_Lock = recursive_mutex::scoped_lock(m_Object->m_Mutex);
#ifdef _DEBUG
{ {
boost::mutex::scoped_lock lock(Object::m_DebugMutex); boost::mutex::scoped_lock lock(Object::m_DebugMutex);
m_Object->m_LockCount++; m_Object->m_LockCount++;
m_Object->m_LockOwner = boost::this_thread::get_id(); m_Object->m_LockOwner = boost::this_thread::get_id();
if (m_Object->m_LockCount == 1) {
g_LockCount++;
m_TS = Utility::GetTime();
}
} }
#endif /* _DEBUG */
} }
void ObjectLock::Unlock(void) void ObjectLock::Unlock(void)
{ {
#ifdef _DEBUG
{ {
boost::mutex::scoped_lock lock(Object::m_DebugMutex); boost::mutex::scoped_lock lock(Object::m_DebugMutex);
if (m_Lock.owns_lock()) if (m_Lock.owns_lock()) {
if (m_Object->m_LockCount == 1) {
g_LockCount--;
double dt = Utility::GetTime() - m_TS;
if (dt > 0.05) {
std::cerr << "Held object lock for " << dt << " seconds at:";
Utility::PrintStacktrace(std::cerr);
}
}
m_Object->m_LockCount--; m_Object->m_LockCount--;
}
} }
#endif /* _DEBUG */
m_Lock = recursive_mutex::scoped_lock(); m_Lock = recursive_mutex::scoped_lock();
} }

View File

@ -39,6 +39,9 @@ public:
private: private:
const Object *m_Object; const Object *m_Object;
recursive_mutex::scoped_lock m_Lock; recursive_mutex::scoped_lock m_Lock;
#ifdef _DEBUG
double m_TS;
#endif /* _DEBUG */
}; };
} }

View File

@ -35,6 +35,9 @@ Script::Script(const Dictionary::Ptr& properties)
RegisterAttribute("code", Attribute_Config, &m_Code); RegisterAttribute("code", Attribute_Config, &m_Code);
} }
/**
* @threadsafety Always.
*/
void Script::Start(void) void Script::Start(void)
{ {
assert(OwnsLock()); assert(OwnsLock());
@ -42,6 +45,9 @@ void Script::Start(void)
SpawnInterpreter(); SpawnInterpreter();
} }
/**
* @threadsafety Always.
*/
String Script::GetLanguage(void) const String Script::GetLanguage(void) const
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -49,6 +55,9 @@ String Script::GetLanguage(void) const
return m_Language; return m_Language;
} }
/**
* @threadsafety Always.
*/
String Script::GetCode(void) const String Script::GetCode(void) const
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -56,12 +65,20 @@ String Script::GetCode(void) const
return m_Code; return m_Code;
} }
/**
* @threadsafety Always.
*/
void Script::OnAttributeUpdate(const String& name, const Value& oldValue) void Script::OnAttributeUpdate(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
if (name == "language" || name == "code") if (name == "language" || name == "code")
SpawnInterpreter(); SpawnInterpreter();
} }
/**
* @threadsafety Always.
*/
void Script::SpawnInterpreter(void) void Script::SpawnInterpreter(void)
{ {
Logger::Write(LogInformation, "base", "Reloading script '" + GetName() + "'"); Logger::Write(LogInformation, "base", "Reloading script '" + GetName() + "'");

View File

@ -28,25 +28,37 @@ ScriptFunction::ScriptFunction(const Callback& function)
: m_Callback(function) : m_Callback(function)
{ } { }
/**
* @threadsafety Always.
*/
void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function) void ScriptFunction::Register(const String& name, const ScriptFunction::Ptr& function)
{ {
boost::mutex::scoped_lock lock(GetMutex()); boost::mutex::scoped_lock lock(GetMutex());
InternalGetFunctions()[name] = function; InternalGetFunctions()[name] = function;
OnRegistered(name, function); OnRegistered(name, function);
} }
/**
* @threadsafety Always.
*/
void ScriptFunction::Unregister(const String& name) void ScriptFunction::Unregister(const String& name)
{ {
boost::mutex::scoped_lock lock(GetMutex()); boost::mutex::scoped_lock lock(GetMutex());
InternalGetFunctions().erase(name); InternalGetFunctions().erase(name);
OnUnregistered(name); OnUnregistered(name);
} }
/**
* @threadsafety Always.
*/
ScriptFunction::Ptr ScriptFunction::GetByName(const String& name) ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
{ {
boost::mutex::scoped_lock lock(GetMutex());
map<String, ScriptFunction::Ptr>::iterator it; map<String, ScriptFunction::Ptr>::iterator it;
boost::mutex::scoped_lock lock(GetMutex());
it = InternalGetFunctions().find(name); it = InternalGetFunctions().find(name);
if (it == InternalGetFunctions().end()) if (it == InternalGetFunctions().end())
@ -55,6 +67,9 @@ ScriptFunction::Ptr ScriptFunction::GetByName(const String& name)
return it->second; return it->second;
} }
/**
* @threadsafety Always.
*/
void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& arguments) void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -62,9 +77,13 @@ void ScriptFunction::Invoke(const ScriptTask::Ptr& task, const vector<Value>& ar
m_Callback(task, arguments); m_Callback(task, arguments);
} }
/**
* @threadsafety Always.
*/
map<String, ScriptFunction::Ptr> ScriptFunction::GetFunctions(void) map<String, ScriptFunction::Ptr> ScriptFunction::GetFunctions(void)
{ {
boost::mutex::scoped_lock lock(GetMutex()); boost::mutex::scoped_lock lock(GetMutex());
return InternalGetFunctions(); /* makes a copy of the map */ return InternalGetFunctions(); /* makes a copy of the map */
} }
@ -77,6 +96,9 @@ map<String, ScriptFunction::Ptr>& ScriptFunction::InternalGetFunctions(void)
return functions; return functions;
} }
/**
* @threadsafety Always.
*/
boost::mutex& ScriptFunction::GetMutex(void) boost::mutex& ScriptFunction::GetMutex(void)
{ {
static boost::mutex mtx; static boost::mutex mtx;

View File

@ -44,8 +44,6 @@ public:
static void Unregister(const String& name); static void Unregister(const String& name);
static ScriptFunction::Ptr GetByName(const String& name); static ScriptFunction::Ptr GetByName(const String& name);
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
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&, const ScriptFunction::Ptr&)> OnRegistered;
@ -56,6 +54,10 @@ private:
static map<String, ScriptFunction::Ptr>& InternalGetFunctions(void); static map<String, ScriptFunction::Ptr>& InternalGetFunctions(void);
static boost::mutex& GetMutex(void); static boost::mutex& GetMutex(void);
void Invoke(const shared_ptr<ScriptTask>& task, const vector<Value>& arguments);
friend class ScriptTask;
}; };
/** /**

View File

@ -29,12 +29,5 @@ ScriptTask::ScriptTask(const ScriptFunction::Ptr& function,
void ScriptTask::Run(void) void ScriptTask::Run(void)
{ {
ScriptTask::Ptr self; m_Function->Invoke(GetSelf(), m_Arguments);
{
ObjectLock olock(this);
self = GetSelf();
}
m_Function->Invoke(self, m_Arguments);
} }

View File

@ -48,6 +48,8 @@ Socket::~Socket(void)
*/ */
void Socket::Start(void) void Socket::Start(void)
{ {
ObjectLock olock(this);
assert(!m_ReadThread.joinable() && !m_WriteThread.joinable()); assert(!m_ReadThread.joinable() && !m_WriteThread.joinable());
assert(GetFD() != INVALID_SOCKET); assert(GetFD() != INVALID_SOCKET);
@ -68,6 +70,8 @@ void Socket::Start(void)
*/ */
void Socket::SetFD(SOCKET fd) void Socket::SetFD(SOCKET fd)
{ {
ObjectLock olock(this);
/* mark the socket as non-blocking and close-on-exec */ /* mark the socket as non-blocking and close-on-exec */
if (fd != INVALID_SOCKET) { if (fd != INVALID_SOCKET) {
Utility::SetNonBlockingSocket(fd); Utility::SetNonBlockingSocket(fd);
@ -86,27 +90,25 @@ void Socket::SetFD(SOCKET fd)
*/ */
SOCKET Socket::GetFD(void) const SOCKET Socket::GetFD(void) const
{ {
ObjectLock olock(this);
return m_FD; return m_FD;
} }
void Socket::CloseUnlocked(void)
{
if (m_FD == INVALID_SOCKET)
return;
closesocket(m_FD);
m_FD = INVALID_SOCKET;
Stream::Close();
}
/** /**
* Closes the socket. * Closes the socket.
*/ */
void Socket::Close(void) void Socket::Close(void)
{ {
boost::mutex::scoped_lock lock(m_SocketMutex); ObjectLock olock(this);
CloseUnlocked();
if (m_FD == INVALID_SOCKET)
return;
closesocket(m_FD);
m_FD = INVALID_SOCKET;
Stream::Close();
} }
/** /**
@ -146,6 +148,8 @@ int Socket::GetLastSocketError(void)
*/ */
void Socket::HandleException(void) void Socket::HandleException(void)
{ {
ObjectLock olock(this);
BOOST_THROW_EXCEPTION(SocketException("select() returned fd in except fdset", GetError())); BOOST_THROW_EXCEPTION(SocketException("select() returned fd in except fdset", GetError()));
} }
@ -271,7 +275,7 @@ void Socket::ReadThreadProc(void)
} catch (...) { } catch (...) {
SetException(boost::current_exception()); SetException(boost::current_exception());
CloseUnlocked(); Close();
break; break;
} }
@ -326,7 +330,7 @@ void Socket::WriteThreadProc(void)
} catch (...) { } catch (...) {
SetException(boost::current_exception()); SetException(boost::current_exception());
CloseUnlocked(); Close();
break; break;
} }
@ -340,6 +344,8 @@ void Socket::WriteThreadProc(void)
*/ */
void Socket::SetConnected(bool connected) void Socket::SetConnected(bool connected)
{ {
ObjectLock olock(this);
m_Connected = connected; m_Connected = connected;
} }
@ -350,6 +356,8 @@ void Socket::SetConnected(bool connected)
*/ */
bool Socket::IsConnected(void) const bool Socket::IsConnected(void) const
{ {
ObjectLock olock(this);
return m_Connected; return m_Connected;
} }
@ -360,14 +368,12 @@ bool Socket::IsConnected(void) const
*/ */
size_t Socket::GetAvailableBytes(void) const size_t Socket::GetAvailableBytes(void) const
{ {
ObjectLock olock(this);
if (m_Listening) if (m_Listening)
throw new logic_error("Socket does not support GetAvailableBytes()."); throw new logic_error("Socket does not support GetAvailableBytes().");
{ return m_RecvQueue->GetAvailableBytes();
boost::mutex::scoped_lock lock(m_QueueMutex);
return m_RecvQueue->GetAvailableBytes();
}
} }
/** /**
@ -379,11 +385,13 @@ size_t Socket::GetAvailableBytes(void) const
*/ */
size_t Socket::Read(void *buffer, size_t size) size_t Socket::Read(void *buffer, size_t size)
{ {
ObjectLock olock(this);
if (m_Listening) if (m_Listening)
throw new logic_error("Socket does not support Read()."); throw new logic_error("Socket does not support Read().");
{ {
boost::mutex::scoped_lock lock(m_QueueMutex); ObjectLock olock(m_RecvQueue);
if (m_RecvQueue->GetAvailableBytes() == 0) if (m_RecvQueue->GetAvailableBytes() == 0)
CheckException(); CheckException();
@ -401,11 +409,15 @@ size_t Socket::Read(void *buffer, size_t size)
*/ */
size_t Socket::Peek(void *buffer, size_t size) size_t Socket::Peek(void *buffer, size_t size)
{ {
if (m_Listening) {
throw new logic_error("Socket does not support Peek()."); ObjectLock olock(this);
if (m_Listening)
throw new logic_error("Socket does not support Peek().");
}
{ {
boost::mutex::scoped_lock lock(m_QueueMutex); ObjectLock olock(m_RecvQueue);
if (m_RecvQueue->GetAvailableBytes() == 0) if (m_RecvQueue->GetAvailableBytes() == 0)
CheckException(); CheckException();
@ -422,14 +434,14 @@ size_t Socket::Peek(void *buffer, size_t size)
*/ */
void Socket::Write(const void *buffer, size_t size) void Socket::Write(const void *buffer, size_t size)
{ {
if (m_Listening)
throw new logic_error("Socket does not support Write().");
{ {
boost::mutex::scoped_lock lock(m_QueueMutex); ObjectLock olock(this);
m_SendQueue->Write(buffer, size); if (m_Listening)
throw new logic_error("Socket does not support Write().");
} }
m_SendQueue->Write(buffer, size);
} }
/** /**
@ -437,6 +449,8 @@ void Socket::Write(const void *buffer, size_t size)
*/ */
void Socket::Listen(void) void Socket::Listen(void)
{ {
ObjectLock olock(this);
if (listen(GetFD(), SOMAXCONN) < 0) if (listen(GetFD(), SOMAXCONN) < 0)
BOOST_THROW_EXCEPTION(SocketException("listen() failed", GetError())); BOOST_THROW_EXCEPTION(SocketException("listen() failed", GetError()));
@ -472,29 +486,17 @@ void Socket::HandleWritableClient(void)
SetConnected(true); SetConnected(true);
for (;;) { for (;;) {
{ count = m_SendQueue->Peek(data, sizeof(data));
boost::mutex::scoped_lock lock(m_QueueMutex);
count = m_SendQueue->GetAvailableBytes(); if (count == 0)
break;
if (count == 0)
break;
if (count > sizeof(data))
count = sizeof(data);
m_SendQueue->Peek(data, count);
}
rc = send(GetFD(), data, count, 0); rc = send(GetFD(), data, count, 0);
if (rc <= 0) if (rc <= 0)
BOOST_THROW_EXCEPTION(SocketException("send() failed", GetError())); BOOST_THROW_EXCEPTION(SocketException("send() failed", GetError()));
{ m_SendQueue->Read(NULL, rc);
boost::mutex::scoped_lock lock(m_QueueMutex);
m_SendQueue->Read(NULL, rc);
}
} }
} }
@ -522,11 +524,7 @@ void Socket::HandleReadableClient(void)
if (rc <= 0) if (rc <= 0)
BOOST_THROW_EXCEPTION(SocketException("recv() failed", GetError())); BOOST_THROW_EXCEPTION(SocketException("recv() failed", GetError()));
{ m_RecvQueue->Write(data, rc);
boost::mutex::scoped_lock lock(m_QueueMutex);
m_RecvQueue->Write(data, rc);
}
new_data = true; new_data = true;
} }
@ -603,12 +601,8 @@ bool Socket::WantsToReadClient(void) const
*/ */
bool Socket::WantsToWriteClient(void) const bool Socket::WantsToWriteClient(void) const
{ {
{ if (m_SendQueue->GetAvailableBytes() > 0)
boost::mutex::scoped_lock lock(m_QueueMutex); return true;
if (m_SendQueue->GetAvailableBytes() > 0)
return true;
}
return (!IsConnected()); return (!IsConnected());
} }

View File

@ -83,7 +83,6 @@ private:
static String GetAddressFromSockaddr(sockaddr *address, socklen_t len); static String GetAddressFromSockaddr(sockaddr *address, socklen_t len);
mutable boost::mutex m_QueueMutex;
FIFO::Ptr m_SendQueue; FIFO::Ptr m_SendQueue;
FIFO::Ptr m_RecvQueue; FIFO::Ptr m_RecvQueue;
@ -105,8 +104,6 @@ private:
bool WantsToWrite(void) const; bool WantsToWrite(void) const;
bool WantsToRead(void) const; bool WantsToRead(void) const;
void CloseUnlocked(void);
}; };
/** /**

View File

@ -43,13 +43,21 @@ StdioStream::~StdioStream(void)
m_ReadAheadBuffer->Close(); m_ReadAheadBuffer->Close();
} }
/**
* @threadsafety Always.
*/
void StdioStream::Start(void) void StdioStream::Start(void)
{ {
ObjectLock olock(this);
SetConnected(true); SetConnected(true);
Stream::Start(); Stream::Start();
} }
/**
* @threadsafety Always.
*/
size_t StdioStream::GetAvailableBytes(void) const size_t StdioStream::GetAvailableBytes(void) const
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -60,6 +68,9 @@ size_t StdioStream::GetAvailableBytes(void) const
return 1024; /* doesn't have to be accurate */ return 1024; /* doesn't have to be accurate */
} }
/**
* @threadsafety Always.
*/
size_t StdioStream::Read(void *buffer, size_t size) size_t StdioStream::Read(void *buffer, size_t size)
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -75,6 +86,9 @@ size_t StdioStream::Read(void *buffer, size_t size)
return peek_len + read_len; return peek_len + read_len;
} }
/**
* @threadsafety Always.
*/
size_t StdioStream::Peek(void *buffer, size_t size) size_t StdioStream::Peek(void *buffer, size_t size)
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -91,6 +105,9 @@ size_t StdioStream::Peek(void *buffer, size_t size)
return peek_len + read_len; return peek_len + read_len;
} }
/**
* @threadsafety Always.
*/
void StdioStream::Write(const void *buffer, size_t size) void StdioStream::Write(const void *buffer, size_t size)
{ {
ObjectLock olock(this); ObjectLock olock(this);
@ -98,6 +115,9 @@ void StdioStream::Write(const void *buffer, size_t size)
m_InnerStream->write(static_cast<const char *>(buffer), size); m_InnerStream->write(static_cast<const char *>(buffer), size);
} }
/**
* @threadsafety Always.
*/
void StdioStream::Close(void) void StdioStream::Close(void)
{ {
ObjectLock olock(this); ObjectLock olock(this);

View File

@ -30,48 +30,81 @@ Stream::~Stream(void)
assert(!m_Running); assert(!m_Running);
} }
/**
* @threadsafety Always.
*/
bool Stream::IsConnected(void) const bool Stream::IsConnected(void) const
{ {
ObjectLock olock(this);
return m_Connected; return m_Connected;
} }
/**
* @threadsafety Always.
*/
void Stream::SetConnected(bool connected) void Stream::SetConnected(bool connected)
{ {
m_Connected = connected; {
ObjectLock olock(this);
m_Connected = connected;
}
if (m_Connected) if (connected)
OnConnected(GetSelf()); OnConnected(GetSelf());
else else
OnClosed(GetSelf()); OnClosed(GetSelf());
} }
/** /**
* Checks whether an exception is available for this socket and re-throws * Checks whether an exception is available for this stream and re-throws
* the exception if there is one. * the exception if there is one.
*
* @threadsafety Always.
*/ */
void Stream::CheckException(void) void Stream::CheckException(void)
{ {
ObjectLock olock(this);
if (m_Exception) if (m_Exception)
rethrow_exception(m_Exception); rethrow_exception(m_Exception);
} }
/**
* @threadsafety Always.
*/
void Stream::SetException(boost::exception_ptr exception) void Stream::SetException(boost::exception_ptr exception)
{ {
ObjectLock olock(this);
m_Exception = exception; m_Exception = exception;
} }
/**
* @threadsafety Always.
*/
boost::exception_ptr Stream::GetException(void) boost::exception_ptr Stream::GetException(void)
{ {
return m_Exception; return m_Exception;
} }
/**
* @threadsafety Always.
*/
void Stream::Start(void) void Stream::Start(void)
{ {
ObjectLock olock(this);
m_Running = true; m_Running = true;
} }
/**
* @threadsafety Always.
*/
void Stream::Close(void) void Stream::Close(void)
{ {
ObjectLock olock(this);
assert(m_Running); assert(m_Running);
m_Running = false; m_Running = false;

View File

@ -49,11 +49,17 @@ typedef struct I2Stream_bio_s
boost::exception_ptr Exception; boost::exception_ptr Exception;
} I2Stream_bio_t; } I2Stream_bio_t;
/**
* @threadsafety Always.
*/
BIO_METHOD *BIO_s_I2Stream(void) BIO_METHOD *BIO_s_I2Stream(void)
{ {
return &I2Stream_method; return &I2Stream_method;
} }
/**
* @threadsafety Always.
*/
BIO *icinga::BIO_new_I2Stream(const Stream::Ptr& stream) BIO *icinga::BIO_new_I2Stream(const Stream::Ptr& stream)
{ {
BIO *bi = BIO_new(BIO_s_I2Stream()); BIO *bi = BIO_new(BIO_s_I2Stream());
@ -68,6 +74,9 @@ BIO *icinga::BIO_new_I2Stream(const Stream::Ptr& stream)
return bi; return bi;
} }
/**
* @threadsafety Always.
*/
void icinga::I2Stream_check_exception(BIO *bi) { void icinga::I2Stream_check_exception(BIO *bi) {
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr; I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -78,6 +87,9 @@ void icinga::I2Stream_check_exception(BIO *bi) {
} }
} }
/**
* @threadsafety Always.
*/
static int I2Stream_new(BIO *bi) static int I2Stream_new(BIO *bi)
{ {
bi->shutdown = 0; bi->shutdown = 0;
@ -88,6 +100,9 @@ static int I2Stream_new(BIO *bi)
return 1; return 1;
} }
/**
* @threadsafety Always.
*/
static int I2Stream_free(BIO *bi) static int I2Stream_free(BIO *bi)
{ {
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr; I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -96,6 +111,9 @@ static int I2Stream_free(BIO *bi)
return 1; return 1;
} }
/**
* @threadsafety Always.
*/
static int I2Stream_read(BIO *bi, char *out, int outl) static int I2Stream_read(BIO *bi, char *out, int outl)
{ {
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr; I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -119,6 +137,9 @@ static int I2Stream_read(BIO *bi, char *out, int outl)
return data_read; return data_read;
} }
/**
* @threadsafety Always.
*/
static int I2Stream_write(BIO *bi, const char *in, int inl) static int I2Stream_write(BIO *bi, const char *in, int inl)
{ {
I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr; I2Stream_bio_t *bp = (I2Stream_bio_t *)bi->ptr;
@ -127,6 +148,9 @@ static int I2Stream_write(BIO *bi, const char *in, int inl)
return inl; return inl;
} }
/**
* @threadsafety Always.
*/
static long I2Stream_ctrl(BIO *, int cmd, long, void *) static long I2Stream_ctrl(BIO *, int cmd, long, void *)
{ {
switch (cmd) { switch (cmd) {

View File

@ -48,6 +48,9 @@ StreamLogger::~StreamLogger(void)
delete m_Stream; delete m_Stream;
} }
/**
* @threadsafety Always.
*/
void StreamLogger::OpenFile(const String& filename) void StreamLogger::OpenFile(const String& filename)
{ {
ofstream *stream = new ofstream(); ofstream *stream = new ofstream();
@ -62,6 +65,8 @@ void StreamLogger::OpenFile(const String& filename)
throw; throw;
} }
ObjectLock olock(this);
m_Stream = stream; m_Stream = stream;
m_OwnsStream = true; m_OwnsStream = true;
m_Tty = false; m_Tty = false;
@ -73,6 +78,7 @@ void StreamLogger::OpenFile(const String& filename)
* @param stream The output stream. * @param stream The output stream.
* @param tty Whether the output stream is a TTY. * @param tty Whether the output stream is a TTY.
* @param entry The log entry. * @param entry The log entry.
* @threadsafety Always.
*/ */
void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& entry) void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& entry)
{ {
@ -107,12 +113,18 @@ void StreamLogger::ProcessLogEntry(ostream& stream, bool tty, const LogEntry& en
* Processes a log entry and outputs it to a stream. * Processes a log entry and outputs it to a stream.
* *
* @param entry The log entry. * @param entry The log entry.
* @threadsafety Always.
*/ */
void StreamLogger::ProcessLogEntry(const LogEntry& entry) void StreamLogger::ProcessLogEntry(const LogEntry& entry)
{ {
ObjectLock olock(this);
ProcessLogEntry(*m_Stream, m_Tty, entry); ProcessLogEntry(*m_Stream, m_Tty, entry);
} }
/**
* @threadsafety Always.
*/
bool StreamLogger::IsTty(ostream& stream) bool StreamLogger::IsTty(ostream& stream)
{ {
#ifndef _WIN32 #ifndef _WIN32

View File

@ -26,6 +26,7 @@ using namespace icinga;
* Processes a log entry and outputs it to syslog. * Processes a log entry and outputs it to syslog.
* *
* @param entry The log entry. * @param entry The log entry.
* @threadsafety Always.
*/ */
void SyslogLogger::ProcessLogEntry(const LogEntry& entry) void SyslogLogger::ProcessLogEntry(const LogEntry& entry)
{ {

View File

@ -38,6 +38,7 @@ void TcpSocket::Bind(String service, int family)
* @param node The node. * @param node The node.
* @param service The service. * @param service The service.
* @param family The address family for the socket. * @param family The address family for the socket.
* @threadsafety Always.
*/ */
void TcpSocket::Bind(String node, String service, int family) void TcpSocket::Bind(String node, String service, int family)
{ {
@ -99,6 +100,7 @@ void TcpSocket::Bind(String node, String service, int family)
* *
* @param node The node. * @param node The node.
* @param service The service. * @param service The service.
* @threadsafety Always.
*/ */
void TcpSocket::Connect(const String& node, const String& service) void TcpSocket::Connect(const String& node, const String& service)
{ {

View File

@ -42,6 +42,8 @@ TlsStream::TlsStream(const Stream::Ptr& innerStream, TlsRole role, shared_ptr<SS
void TlsStream::Start(void) void TlsStream::Start(void)
{ {
ObjectLock olock(this);
m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free); m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free);
m_SSLContext.reset(); m_SSLContext.reset();
@ -88,6 +90,8 @@ void TlsStream::Start(void)
*/ */
shared_ptr<X509> TlsStream::GetClientCertificate(void) const shared_ptr<X509> TlsStream::GetClientCertificate(void) const
{ {
ObjectLock olock(this);
return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), &Utility::NullDeleter); return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), &Utility::NullDeleter);
} }
@ -98,6 +102,8 @@ shared_ptr<X509> TlsStream::GetClientCertificate(void) const
*/ */
shared_ptr<X509> TlsStream::GetPeerCertificate(void) const shared_ptr<X509> TlsStream::GetPeerCertificate(void) const
{ {
ObjectLock olock(this);
return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free); return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
} }
@ -114,6 +120,8 @@ void TlsStream::DataAvailableHandler(void)
void TlsStream::ClosedHandler(void) void TlsStream::ClosedHandler(void)
{ {
ObjectLock olock(this);
SetException(m_InnerStream->GetException()); SetException(m_InnerStream->GetException());
Close(); Close();
} }
@ -123,6 +131,9 @@ void TlsStream::ClosedHandler(void)
*/ */
void TlsStream::HandleIO(void) void TlsStream::HandleIO(void)
{ {
assert(!OwnsLock());
ObjectLock olock(this);
char data[16 * 1024]; char data[16 * 1024];
int rc; int rc;
@ -172,8 +183,11 @@ void TlsStream::HandleIO(void)
} }
} }
if (new_data) if (new_data) {
olock.Unlock();
OnDataAvailable(GetSelf()); OnDataAvailable(GetSelf());
olock.Lock();
}
while (m_SendQueue->GetAvailableBytes() > 0) { while (m_SendQueue->GetAvailableBytes() > 0) {
size_t count = m_SendQueue->GetAvailableBytes(); size_t count = m_SendQueue->GetAvailableBytes();
@ -212,6 +226,8 @@ void TlsStream::HandleIO(void)
*/ */
void TlsStream::Close(void) void TlsStream::Close(void)
{ {
ObjectLock olock(this);
if (m_SSL) if (m_SSL)
SSL_shutdown(m_SSL.get()); SSL_shutdown(m_SSL.get());
@ -223,22 +239,32 @@ void TlsStream::Close(void)
size_t TlsStream::GetAvailableBytes(void) const size_t TlsStream::GetAvailableBytes(void) const
{ {
ObjectLock olock(this);
return m_RecvQueue->GetAvailableBytes(); return m_RecvQueue->GetAvailableBytes();
} }
size_t TlsStream::Peek(void *buffer, size_t count) size_t TlsStream::Peek(void *buffer, size_t count)
{ {
ObjectLock olock(this);
return m_RecvQueue->Peek(buffer, count); return m_RecvQueue->Peek(buffer, count);
} }
size_t TlsStream::Read(void *buffer, size_t count) size_t TlsStream::Read(void *buffer, size_t count)
{ {
ObjectLock olock(this);
return m_RecvQueue->Read(buffer, count); return m_RecvQueue->Read(buffer, count);
} }
void TlsStream::Write(const void *buffer, size_t count) void TlsStream::Write(const void *buffer, size_t count)
{ {
m_SendQueue->Write(buffer, count); {
ObjectLock olock(this);
m_SendQueue->Write(buffer, count);
}
HandleIO(); HandleIO();
} }

View File

@ -137,6 +137,6 @@ void ConfigCompilerContext::ActivateItems(void)
Logger::Write(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'"); Logger::Write(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'");
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) { BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
ConfigItem::Commit(item); item->Commit();
} }
} }

View File

@ -50,6 +50,8 @@ ConfigItem::ConfigItem(const String& type, const String& name,
*/ */
String ConfigItem::GetType(void) const String ConfigItem::GetType(void) const
{ {
ObjectLock olock(this);
return m_Type; return m_Type;
} }
@ -60,6 +62,8 @@ String ConfigItem::GetType(void) const
*/ */
String ConfigItem::GetName(void) const String ConfigItem::GetName(void) const
{ {
ObjectLock olock(this);
return m_Name; return m_Name;
} }
@ -70,6 +74,8 @@ String ConfigItem::GetName(void) const
*/ */
String ConfigItem::GetUnit(void) const String ConfigItem::GetUnit(void) const
{ {
ObjectLock olock(this);
return m_Unit; return m_Unit;
} }
@ -80,6 +86,8 @@ String ConfigItem::GetUnit(void) const
*/ */
DebugInfo ConfigItem::GetDebugInfo(void) const DebugInfo ConfigItem::GetDebugInfo(void) const
{ {
ObjectLock olock(this);
return m_DebugInfo; return m_DebugInfo;
} }
@ -90,6 +98,8 @@ DebugInfo ConfigItem::GetDebugInfo(void) const
*/ */
ExpressionList::Ptr ConfigItem::GetExpressionList(void) const ExpressionList::Ptr ConfigItem::GetExpressionList(void) const
{ {
ObjectLock olock(this);
return m_ExpressionList; return m_ExpressionList;
} }
@ -100,11 +110,15 @@ ExpressionList::Ptr ConfigItem::GetExpressionList(void) const
*/ */
vector<String> ConfigItem::GetParents(void) const vector<String> ConfigItem::GetParents(void) const
{ {
ObjectLock olock(this);
return m_Parents; return m_Parents;
} }
set<ConfigItem::WeakPtr> ConfigItem::GetChildren(void) const set<ConfigItem::WeakPtr> ConfigItem::GetChildren(void) const
{ {
ObjectLock olock(this);
return m_ChildObjects; return m_ChildObjects;
} }
@ -124,6 +138,8 @@ Dictionary::Ptr ConfigItem::Link(void) const
*/ */
void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
{ {
ObjectLock olock(this);
BOOST_FOREACH(const String& name, m_Parents) { BOOST_FOREACH(const String& name, m_Parents) {
ConfigItem::Ptr parent; ConfigItem::Ptr parent;
@ -157,66 +173,67 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
* *
* @returns The DynamicObject that was created/updated. * @returns The DynamicObject that was created/updated.
*/ */
DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self) DynamicObject::Ptr ConfigItem::Commit(void)
{ {
assert(!OwnsLock());
String type, name; String type, name;
DynamicObject::Ptr dobj;
vector<String> parents;
Dictionary::Ptr properties;
{ Logger::Write(LogDebug, "base", "Commit called for ConfigItem Type=" + GetType() + ", Name=" + GetName());
ObjectLock olock(self);
type = self->GetType();
name = self->GetName();
dobj = self->GetDynamicObject();
parents = self->GetParents();
properties = self->Link();
}
Logger::Write(LogDebug, "base", "Commit called for ConfigItem Type=" + type + ", Name=" + name);
/* Make sure the type is valid. */ /* Make sure the type is valid. */
DynamicType::Ptr dtype = DynamicType::GetByName(type); DynamicType::Ptr dtype = DynamicType::GetByName(GetType());
if (!dtype) if (!dtype)
BOOST_THROW_EXCEPTION(runtime_error("Type '" + type + "' does not exist.")); BOOST_THROW_EXCEPTION(runtime_error("Type '" + GetType() + "' does not exist."));
/* Try to find an existing item with the same type and name. */
pair<String, String> ikey = make_pair(GetType(), GetName());
ConfigItem::Ptr oldItem;
{ {
recursive_mutex::scoped_lock lock(m_Mutex); recursive_mutex::scoped_lock lock(m_Mutex);
/* Try to find an existing item with the same type and name. */
pair<String, String> ikey = make_pair(type, name);
ItemMap::iterator it = m_Items.find(ikey); ItemMap::iterator it = m_Items.find(ikey);
set<ConfigItem::WeakPtr> children; if (it != m_Items.end())
oldItem = it->second;
if (it != m_Items.end()) {
/* Unregister the old item from its parents. */
ConfigItem::Ptr oldItem = it->second;
ObjectLock olock(oldItem);
oldItem->UnregisterFromParents();
/* Steal the old item's children. */
children = oldItem->GetChildren();
}
{
ObjectLock olock(self);
self->m_ChildObjects = children;
}
/* Register this item. */
m_Items[ikey] = self;
} }
set<ConfigItem::WeakPtr> children;
if (oldItem) {
ObjectLock olock(oldItem);
/* Unregister the old item from its parents. */
oldItem->UnregisterFromParents();
/* Steal the old item's children. */
children = oldItem->GetChildren();
}
{
ObjectLock olock(this);
m_ChildObjects = children;
}
{
recursive_mutex::scoped_lock lock(m_Mutex);
/* Register this item. */
m_Items[ikey] = GetSelf();
}
DynamicObject::Ptr dobj = GetDynamicObject();
if (!dobj) if (!dobj)
dobj = dtype->GetObject(name); dobj = dtype->GetObject(GetName());
/* Register this item with its parents. */ /* Register this item with its parents. */
BOOST_FOREACH(const String& parentName, parents) { BOOST_FOREACH(const String& parentName, GetParents()) {
ConfigItem::Ptr parent = GetObject(type, parentName); ConfigItem::Ptr parent = GetObject(GetType(), parentName);
ObjectLock olock(parent); ObjectLock olock(parent);
parent->RegisterChild(self); parent->RegisterChild(GetSelf());
} }
/* Create a fake update in the format that /* Create a fake update in the format that
@ -225,6 +242,8 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
double tx = DynamicObject::GetCurrentTx(); double tx = DynamicObject::GetCurrentTx();
Dictionary::Ptr properties = Link();
{ {
ObjectLock olock(properties); ObjectLock olock(properties);
@ -256,29 +275,20 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
was_null = true; was_null = true;
} }
{ if (!was_null)
ObjectLock olock(dobj); dobj->ApplyUpdate(update, Attribute_Config);
if (!was_null)
dobj->ApplyUpdate(update, Attribute_Config);
self->m_DynamicObject = dobj;
if (dobj->IsAbstract())
dobj->Unregister();
else
dobj->Register();
}
/* We need to make a copy of the child objects because the
* OnParentCommitted() handler is going to update the list. */
set<ConfigItem::WeakPtr> children;
{ {
ObjectLock olock(self); ObjectLock olock(this);
children = self->m_ChildObjects;
m_DynamicObject = dobj;
} }
if (dobj->IsAbstract())
dobj->Unregister();
else
dobj->Register();
/* notify our children of the update */ /* notify our children of the update */
BOOST_FOREACH(const ConfigItem::WeakPtr wchild, children) { BOOST_FOREACH(const ConfigItem::WeakPtr wchild, children) {
const ConfigItem::Ptr& child = wchild.lock(); const ConfigItem::Ptr& child = wchild.lock();
@ -289,7 +299,7 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
child->OnParentCommitted(); child->OnParentCommitted();
} }
OnCommitted(self); OnCommitted(GetSelf());
return dobj; return dobj;
} }
@ -299,19 +309,23 @@ DynamicObject::Ptr ConfigItem::Commit(const ConfigItem::Ptr& self)
*/ */
void ConfigItem::Unregister(void) void ConfigItem::Unregister(void)
{ {
DynamicObject::Ptr dobj = m_DynamicObject.lock(); assert(!OwnsLock());
if (dobj) { DynamicObject::Ptr dobj = GetDynamicObject();
ObjectLock olock(dobj);
if (dobj)
dobj->Unregister(); dobj->Unregister();
{
ObjectLock olock(this);
ConfigItem::ItemMap::iterator it;
it = m_Items.find(make_pair(GetType(), GetName()));
if (it != m_Items.end())
m_Items.erase(it);
} }
ConfigItem::ItemMap::iterator it;
it = m_Items.find(make_pair(GetType(), GetName()));
if (it != m_Items.end())
m_Items.erase(it);
UnregisterFromParents(); UnregisterFromParents();
OnRemoved(GetSelf()); OnRemoved(GetSelf());
@ -319,23 +333,27 @@ void ConfigItem::Unregister(void)
void ConfigItem::RegisterChild(const ConfigItem::Ptr& child) void ConfigItem::RegisterChild(const ConfigItem::Ptr& child)
{ {
ObjectLock olock(this);
m_ChildObjects.insert(child); m_ChildObjects.insert(child);
} }
void ConfigItem::UnregisterChild(const ConfigItem::Ptr& child) void ConfigItem::UnregisterChild(const ConfigItem::Ptr& child)
{ {
ObjectLock olock(this);
m_ChildObjects.erase(child); m_ChildObjects.erase(child);
} }
void ConfigItem::UnregisterFromParents(void) void ConfigItem::UnregisterFromParents(void)
{ {
ObjectLock olock(this);
BOOST_FOREACH(const String& parentName, m_Parents) { BOOST_FOREACH(const String& parentName, m_Parents) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName); ConfigItem::Ptr parent = GetObject(GetType(), parentName);
if (parent) { if (parent)
ObjectLock olock(parent);
parent->UnregisterChild(GetSelf()); parent->UnregisterChild(GetSelf());
}
} }
} }
@ -344,6 +362,8 @@ void ConfigItem::UnregisterFromParents(void)
*/ */
void ConfigItem::OnParentCommitted(void) void ConfigItem::OnParentCommitted(void)
{ {
assert(!OwnsLock());
ConfigItem::Ptr self; ConfigItem::Ptr self;
{ {
@ -354,7 +374,7 @@ void ConfigItem::OnParentCommitted(void)
return; return;
} }
Commit(self); Commit();
} }
/** /**
@ -364,6 +384,8 @@ void ConfigItem::OnParentCommitted(void)
*/ */
DynamicObject::Ptr ConfigItem::GetDynamicObject(void) const DynamicObject::Ptr ConfigItem::GetDynamicObject(void) const
{ {
ObjectLock olock(this);
return m_DynamicObject.lock(); return m_DynamicObject.lock();
} }
@ -397,6 +419,8 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name)
*/ */
void ConfigItem::Dump(ostream& fp) const void ConfigItem::Dump(ostream& fp) const
{ {
ObjectLock olock(this);
fp << "object \"" << m_Type << "\" \"" << m_Name << "\""; fp << "object \"" << m_Type << "\" \"" << m_Name << "\"";
if (m_Parents.size() > 0) { if (m_Parents.size() > 0) {
@ -440,7 +464,6 @@ void ConfigItem::UnloadUnit(const String& unit)
} }
BOOST_FOREACH(const ConfigItem::Ptr& item, obsoleteItems) { BOOST_FOREACH(const ConfigItem::Ptr& item, obsoleteItems) {
ObjectLock olock(item);
item->Unregister(); item->Unregister();
} }
} }

View File

@ -47,7 +47,7 @@ public:
ExpressionList::Ptr GetExpressionList(void) const; ExpressionList::Ptr GetExpressionList(void) const;
static DynamicObject::Ptr Commit(const ConfigItem::Ptr& self); DynamicObject::Ptr Commit(void);
void Unregister(void); void Unregister(void);
void Dump(ostream& fp) const; void Dump(ostream& fp) const;

View File

@ -35,8 +35,5 @@ void API::GetAnswerToEverything(const ScriptTask::Ptr& task, const vector<Value>
Logger::Write(LogInformation, "icinga", "Hello from the Icinga 2 API: " + text); Logger::Write(LogInformation, "icinga", "Hello from the Icinga 2 API: " + text);
{ task->FinishResult(42);
ObjectLock olock(task);
task->FinishResult(42);
}
} }

View File

@ -44,4 +44,3 @@ void CheckResultMessage::SetCheckResult(const Dictionary::Ptr& result)
{ {
Set("check_result", result); Set("check_result", result);
} }

View File

@ -162,7 +162,7 @@ void ExternalCommandProcessor::ProcessHostCheckResult(double time, const vector<
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (!hc->GetEnablePassiveChecks()) if (!hc->GetEnablePassiveChecks())
BOOST_THROW_EXCEPTION(invalid_argument("Got passive check result for host '" + arguments[0] + "' which has passive checks disabled.")); BOOST_THROW_EXCEPTION(invalid_argument("Got passive check result for host '" + arguments[0] + "' which has passive checks disabled."));
@ -222,7 +222,7 @@ void ExternalCommandProcessor::ScheduleHostCheck(double, const vector<String>& a
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
double planned_check = Convert::ToDouble(arguments[1]); double planned_check = Convert::ToDouble(arguments[1]);
@ -243,7 +243,7 @@ void ExternalCommandProcessor::ScheduleForcedHostCheck(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
Logger::Write(LogInformation, "icinga", "Rescheduling next check for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Rescheduling next check for host '" + arguments[0] + "'");
hc->SetForceNextCheck(true); hc->SetForceNextCheck(true);
@ -289,7 +289,7 @@ void ExternalCommandProcessor::EnableHostCheck(double, const vector<String>& arg
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling active checks for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Enabling active checks for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnableActiveChecks(true); hc->SetEnableActiveChecks(true);
@ -303,7 +303,7 @@ void ExternalCommandProcessor::DisableHostCheck(double, const vector<String>& ar
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling active checks for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Disabling active checks for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnableActiveChecks(false); hc->SetEnableActiveChecks(false);
@ -454,7 +454,7 @@ void ExternalCommandProcessor::AcknowledgeHostProblem(double, const vector<Strin
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Setting acknowledgement for host '" + host->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Setting acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
if (service->GetState() == StateOK) if (service->GetState() == StateOK)
BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK.")); BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK."));
@ -474,7 +474,7 @@ void ExternalCommandProcessor::AcknowledgeHostProblemExpire(double, const vector
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Setting timed acknowledgement for host '" + host->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Setting timed acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
if (service->GetState() == StateOK) if (service->GetState() == StateOK)
BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK.")); BOOST_THROW_EXCEPTION(invalid_argument("The host '" + arguments[0] + "' is OK."));
@ -491,7 +491,7 @@ void ExternalCommandProcessor::RemoveHostAcknowledgement(double, const vector<St
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Removing acknowledgement for host '" + host->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Removing acknowledgement for host '" + host->GetName() + "'");
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
service->ClearAcknowledgement(); service->ClearAcknowledgement();
} }
@ -504,7 +504,7 @@ void ExternalCommandProcessor::EnableHostgroupSvcChecks(double, const vector<Str
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true); service->SetEnableActiveChecks(true);
@ -519,7 +519,7 @@ void ExternalCommandProcessor::DisableHostgroupSvcChecks(double, const vector<St
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false); service->SetEnableActiveChecks(false);
@ -534,7 +534,7 @@ void ExternalCommandProcessor::EnableServicegroupSvcChecks(double, const vector<
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(true); service->SetEnableActiveChecks(true);
} }
@ -547,7 +547,7 @@ void ExternalCommandProcessor::DisableServicegroupSvcChecks(double, const vector
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling active checks for service '" + service->GetName() + "'");
service->SetEnableActiveChecks(false); service->SetEnableActiveChecks(false);
} }
@ -561,7 +561,7 @@ void ExternalCommandProcessor::EnablePassiveHostChecks(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling passive checks for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Enabling passive checks for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnablePassiveChecks(true); hc->SetEnablePassiveChecks(true);
@ -575,7 +575,7 @@ void ExternalCommandProcessor::DisablePassiveHostChecks(double, const vector<Str
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling passive checks for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Disabling passive checks for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnablePassiveChecks(false); hc->SetEnablePassiveChecks(false);
@ -610,7 +610,7 @@ void ExternalCommandProcessor::EnableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
} }
@ -623,7 +623,7 @@ void ExternalCommandProcessor::DisableServicegroupPassiveSvcChecks(double, const
ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]); ServiceGroup::Ptr sg = ServiceGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
} }
@ -636,7 +636,7 @@ void ExternalCommandProcessor::EnableHostgroupPassiveSvcChecks(double, const vec
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Enabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(true); service->SetEnablePassiveChecks(true);
@ -651,7 +651,7 @@ void ExternalCommandProcessor::DisableHostgroupPassiveSvcChecks(double, const ve
HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]); HostGroup::Ptr hg = HostGroup::GetByName(arguments[0]);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'"); Logger::Write(LogInformation, "icinga", "Disabling passive checks for service '" + service->GetName() + "'");
service->SetEnablePassiveChecks(false); service->SetEnablePassiveChecks(false);
@ -735,7 +735,7 @@ void ExternalCommandProcessor::ScheduleHostDowntime(double, const vector<String>
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy); triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
(void) service->AddDowntime(arguments[6], arguments[7], (void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -786,9 +786,9 @@ void ExternalCommandProcessor::ScheduleHostgroupHostDowntime(double, const vecto
if (triggeredByLegacy != 0) if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy); triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Creating downtime for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
(void) service->AddDowntime(arguments[6], arguments[7], (void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -815,7 +815,7 @@ void ExternalCommandProcessor::ScheduleHostgroupSvcDowntime(double, const vector
set<Service::Ptr> services; set<Service::Ptr> services;
BOOST_FOREACH(const Host::Ptr& host, HostGroup::GetMembers(hg)) { BOOST_FOREACH(const Host::Ptr& host, hg->GetMembers()) {
BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) { BOOST_FOREACH(const Service::Ptr& service, host->GetServices()) {
services.insert(service); services.insert(service);
} }
@ -847,9 +847,9 @@ void ExternalCommandProcessor::ScheduleServicegroupHostDowntime(double, const ve
set<Service::Ptr> services; set<Service::Ptr> services;
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Host::Ptr host = service->GetHost(); Host::Ptr host = service->GetHost();
Service::Ptr hcService = Host::GetHostCheckService(host); Service::Ptr hcService = host->GetHostCheckService();
if (hcService) if (hcService)
services.insert(hcService); services.insert(hcService);
} }
@ -874,7 +874,7 @@ void ExternalCommandProcessor::ScheduleServicegroupSvcDowntime(double, const vec
if (triggeredByLegacy != 0) if (triggeredByLegacy != 0)
triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy); triggeredBy = Service::GetDowntimeIDFromLegacyID(triggeredByLegacy);
BOOST_FOREACH(const Service::Ptr& service, ServiceGroup::GetMembers(sg)) { BOOST_FOREACH(const Service::Ptr& service, sg->GetMembers()) {
Logger::Write(LogInformation, "icinga", "Creating downtime for service " + service->GetName()); Logger::Write(LogInformation, "icinga", "Creating downtime for service " + service->GetName());
(void) service->AddDowntime(arguments[6], arguments[7], (void) service->AddDowntime(arguments[6], arguments[7],
Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]), Convert::ToDouble(arguments[1]), Convert::ToDouble(arguments[2]),
@ -890,7 +890,7 @@ void ExternalCommandProcessor::AddHostComment(double, const vector<String>& argu
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Creating comment for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Creating comment for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) if (service)
(void) service->AddComment(CommentUser, arguments[2], arguments[3], 0); (void) service->AddComment(CommentUser, arguments[2], arguments[3], 0);
} }
@ -937,7 +937,7 @@ void ExternalCommandProcessor::DelAllHostComments(double, const vector<String>&
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Removing all comments for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Removing all comments for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) if (service)
service->RemoveAllComments(); service->RemoveAllComments();
} }
@ -961,7 +961,7 @@ void ExternalCommandProcessor::SendCustomHostNotification(double time, const vec
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Sending custom notification for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Sending custom notification for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
service->RequestNotifications(NotificationCustom); service->RequestNotifications(NotificationCustom);
} }
@ -986,7 +986,7 @@ void ExternalCommandProcessor::DelayHostNotification(double time, const vector<S
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Delaying notifications for host " + host->GetName()); Logger::Write(LogInformation, "icinga", "Delaying notifications for host " + host->GetName());
Service::Ptr service = Host::GetHostCheckService(host); Service::Ptr service = host->GetHostCheckService();
if (service) { if (service) {
service->SetLastNotification(Convert::ToDouble(arguments[1])); service->SetLastNotification(Convert::ToDouble(arguments[1]));
} }
@ -1011,7 +1011,7 @@ void ExternalCommandProcessor::EnableHostNotifications(double, const vector<Stri
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Enabling notifications for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Enabling notifications for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnableNotifications(true); hc->SetEnableNotifications(true);
@ -1025,7 +1025,7 @@ void ExternalCommandProcessor::DisableHostNotifications(double, const vector<Str
Host::Ptr host = Host::GetByName(arguments[0]); Host::Ptr host = Host::GetByName(arguments[0]);
Logger::Write(LogInformation, "icinga", "Disabling notifications for host '" + arguments[0] + "'"); Logger::Write(LogInformation, "icinga", "Disabling notifications for host '" + arguments[0] + "'");
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
if (hc) if (hc)
hc->SetEnableNotifications(false); hc->SetEnableNotifications(false);

View File

@ -55,14 +55,18 @@ Host::~Host(void)
void Host::OnRegistrationCompleted(void) void Host::OnRegistrationCompleted(void)
{ {
assert(!OwnsLock());
DynamicObject::OnRegistrationCompleted(); DynamicObject::OnRegistrationCompleted();
Host::InvalidateServicesCache(); Host::InvalidateServicesCache();
Host::UpdateSlaveServices(GetSelf()); UpdateSlaveServices();
} }
String Host::GetDisplayName(void) const String Host::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty()) if (!m_DisplayName.IsEmpty())
return m_DisplayName; return m_DisplayName;
else else
@ -81,32 +85,44 @@ Host::Ptr Host::GetByName(const String& name)
Dictionary::Ptr Host::GetGroups(void) const Dictionary::Ptr Host::GetGroups(void) const
{ {
ObjectLock olock(this);
return m_HostGroups;; return m_HostGroups;;
} }
Dictionary::Ptr Host::GetMacros(void) const Dictionary::Ptr Host::GetMacros(void) const
{ {
ObjectLock olock(this);
return m_Macros; return m_Macros;
} }
Dictionary::Ptr Host::GetHostDependencies(void) const Dictionary::Ptr Host::GetHostDependencies(void) const
{ {
ObjectLock olock(this);
return m_HostDependencies;; return m_HostDependencies;;
} }
Dictionary::Ptr Host::GetServiceDependencies(void) const Dictionary::Ptr Host::GetServiceDependencies(void) const
{ {
ObjectLock olock(this);
return m_ServiceDependencies; return m_ServiceDependencies;
} }
String Host::GetHostCheck(void) const String Host::GetHostCheck(void) const
{ {
ObjectLock olock(this);
return m_HostCheck; return m_HostCheck;
} }
bool Host::IsReachable(const Host::Ptr& self) bool Host::IsReachable(void) const
{ {
set<Service::Ptr> parentServices = Host::GetParentServices(self); assert(!OwnsLock());
set<Service::Ptr> parentServices = GetParentServices();
BOOST_FOREACH(const Service::Ptr& service, parentServices) { BOOST_FOREACH(const Service::Ptr& service, parentServices) {
ObjectLock olock(service); ObjectLock olock(service);
@ -127,14 +143,19 @@ bool Host::IsReachable(const Host::Ptr& self)
return false; return false;
} }
set<Host::Ptr> parentHosts = Host::GetParentHosts(self); set<Host::Ptr> parentHosts = GetParentHosts();
BOOST_FOREACH(const Host::Ptr& host, parentHosts) { BOOST_FOREACH(const Host::Ptr& host, parentHosts) {
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = GetHostCheckService();
/* ignore hosts that don't have a hostcheck */
if (!hc)
continue;
ObjectLock olock(hc); ObjectLock olock(hc);
/* ignore hosts that are up */ /* ignore hosts that are up */
if (hc && hc->GetState() == StateOK) if (hc->GetState() == StateOK)
continue; continue;
return false; return false;
@ -190,37 +211,21 @@ static void CopyServiceAttributes(TDict serviceDesc, const ConfigItemBuilder::Pt
} }
} }
void Host::UpdateSlaveServices(const Host::Ptr& self) void Host::UpdateSlaveServices(void)
{ {
ConfigItem::Ptr item; assert(!OwnsLock());
Dictionary::Ptr oldServices, newServices, serviceDescs;
String host_name;
{ ConfigItem::Ptr item = ConfigItem::GetObject("Host", GetName());
ObjectLock olock(self);
host_name = self->GetName(); /* Don't create slave services unless we own this object
* and it's not a template. */
if (!item || IsAbstract())
return;
item = ConfigItem::GetObject("Host", host_name); Dictionary::Ptr oldServices = m_SlaveServices;
Dictionary::Ptr serviceDescs = Get("services");
/* Don't create slave services unless we own this object Dictionary::Ptr newServices = boost::make_shared<Dictionary>();
* and it's not a template. */
if (!item || self->IsAbstract())
return;
oldServices = self->m_SlaveServices;
serviceDescs = self->Get("services");
}
newServices = boost::make_shared<Dictionary>();
ObjectLock nlock(newServices);
DebugInfo debug_info;
{
ObjectLock olock(item);
debug_info = item->GetDebugInfo();
}
if (serviceDescs) { if (serviceDescs) {
ObjectLock olock(serviceDescs); ObjectLock olock(serviceDescs);
@ -231,17 +236,17 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
svcname = svcdesc; svcname = svcdesc;
stringstream namebuf; stringstream namebuf;
namebuf << host_name << "-" << svcname; namebuf << GetName() << "-" << svcname;
String name = namebuf.str(); String name = namebuf.str();
ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(debug_info); ConfigItemBuilder::Ptr builder = boost::make_shared<ConfigItemBuilder>(item->GetDebugInfo());
builder->SetType("Service"); builder->SetType("Service");
builder->SetName(name); builder->SetName(name);
builder->AddExpression("host_name", OperatorSet, host_name); builder->AddExpression("host_name", OperatorSet, GetName());
builder->AddExpression("display_name", OperatorSet, svcname); builder->AddExpression("display_name", OperatorSet, svcname);
builder->AddExpression("short_name", OperatorSet, svcname); builder->AddExpression("short_name", OperatorSet, svcname);
CopyServiceAttributes<false>(self, builder); CopyServiceAttributes<false>(this, builder);
if (svcdesc.IsScalar()) { if (svcdesc.IsScalar()) {
builder->AddParent(svcdesc); builder->AddParent(svcdesc);
@ -272,7 +277,7 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
} }
ConfigItem::Ptr serviceItem = builder->Compile(); ConfigItem::Ptr serviceItem = builder->Compile();
DynamicObject::Ptr dobj = ConfigItem::Commit(serviceItem); DynamicObject::Ptr dobj = serviceItem->Commit();
newServices->Set(name, serviceItem); newServices->Set(name, serviceItem);
} }
@ -293,23 +298,18 @@ void Host::UpdateSlaveServices(const Host::Ptr& self)
newServices->Seal(); newServices->Seal();
ObjectLock olock(self); ObjectLock olock(this);
self->Set("slave_services", newServices); Set("slave_services", newServices);
} }
void Host::OnAttributeChanged(const String& name, const Value&) void Host::OnAttributeChanged(const String& name, const Value&)
{ {
assert(!OwnsLock());
if (name == "hostgroups") if (name == "hostgroups")
HostGroup::InvalidateMembersCache(); HostGroup::InvalidateMembersCache();
else if (name == "services") { else if (name == "services") {
Host::Ptr self; UpdateSlaveServices();
{
ObjectLock olock(this);
self = GetSelf();
}
UpdateSlaveServices(self);
} else if (name == "notifications") { } else if (name == "notifications") {
set<Service::Ptr> services; set<Service::Ptr> services;
@ -450,20 +450,13 @@ void Host::ValidateServiceDictionary(const ScriptTask::Ptr& task, const vector<V
task->FinishResult(Empty); task->FinishResult(Empty);
} }
Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& name) Service::Ptr Host::GetServiceByShortName(const Value& name) const
{ {
String host_name;
{
ObjectLock olock(self);
host_name = self->GetName();
}
if (name.IsScalar()) { if (name.IsScalar()) {
{ {
boost::mutex::scoped_lock lock(m_ServiceMutex); boost::mutex::scoped_lock lock(m_ServiceMutex);
map<String, Service::WeakPtr>& services = m_ServicesCache[host_name]; map<String, Service::WeakPtr>& services = m_ServicesCache[GetName()];
map<String, Service::WeakPtr>::iterator it = services.find(name); map<String, Service::WeakPtr>::iterator it = services.find(name);
if (it != services.end()) { if (it != services.end()) {
@ -478,35 +471,26 @@ Service::Ptr Host::GetServiceByShortName(const Host::Ptr& self, const Value& nam
Dictionary::Ptr dict = name; Dictionary::Ptr dict = name;
String short_name; String short_name;
{ assert(dict->IsSealed());
ObjectLock olock(dict);
host_name = dict->Get("host");
short_name = dict->Get("service");
}
return Service::GetByNamePair(host_name, short_name); return Service::GetByNamePair(dict->Get("host"), dict->Get("service"));
} else { } else {
BOOST_THROW_EXCEPTION(invalid_argument("Host/Service name pair is invalid.")); BOOST_THROW_EXCEPTION(invalid_argument("Host/Service name pair is invalid."));
} }
} }
set<Host::Ptr> Host::GetParentHosts(const Host::Ptr& self) set<Host::Ptr> Host::GetParentHosts(void) const
{ {
set<Host::Ptr> parents; set<Host::Ptr> parents;
Dictionary::Ptr dependencies; Dictionary::Ptr dependencies = GetHostDependencies();
String host_name;
{
ObjectLock olock(self);
dependencies = self->GetHostDependencies();
host_name = self->GetName();
}
if (dependencies) { if (dependencies) {
ObjectLock olock(dependencies);
Value value; Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) { BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
if (value == host_name) if (value == GetName())
continue; continue;
Host::Ptr host = GetByName(value); Host::Ptr host = GetByName(value);
@ -521,60 +505,52 @@ set<Host::Ptr> Host::GetParentHosts(const Host::Ptr& self)
return parents; return parents;
} }
Service::Ptr Host::GetHostCheckService(const Host::Ptr& self) Service::Ptr Host::GetHostCheckService(void) const
{ {
String host_check; String host_check = GetHostCheck();
{
ObjectLock olock(self);
host_check = self->GetHostCheck();
}
if (host_check.IsEmpty()) if (host_check.IsEmpty())
return Service::Ptr(); return Service::Ptr();
return GetServiceByShortName(self, host_check); return GetServiceByShortName(host_check);
} }
set<Service::Ptr> Host::GetParentServices(const Host::Ptr& self) set<Service::Ptr> Host::GetParentServices(void) const
{ {
set<Service::Ptr> parents; set<Service::Ptr> parents;
Dictionary::Ptr dependencies; Dictionary::Ptr dependencies = GetServiceDependencies();
{
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
}
if (dependencies) { if (dependencies) {
ObjectLock olock(dependencies);
Value value; Value value;
BOOST_FOREACH(tie(tuples::ignore, value), dependencies) { BOOST_FOREACH(tie(tuples::ignore, value), dependencies) {
parents.insert(GetServiceByShortName(self, value)); parents.insert(GetServiceByShortName(value));
} }
} }
return parents; return parents;
} }
Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self) Dictionary::Ptr Host::CalculateDynamicMacros(void) const
{ {
assert(!OwnsLock());
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros); ObjectLock mlock(macros);
{ {
ObjectLock olock(self); ObjectLock olock(this);
macros->Set("HOSTNAME", self->GetName()); macros->Set("HOSTNAME", GetName());
macros->Set("HOSTDISPLAYNAME", self->GetDisplayName()); macros->Set("HOSTDISPLAYNAME", GetDisplayName());
macros->Set("HOSTALIAS", self->GetName()); macros->Set("HOSTALIAS", GetName());
} }
bool reachable = Host::IsReachable(self);
Dictionary::Ptr cr; Dictionary::Ptr cr;
Service::Ptr hc = Host::GetHostCheckService(self); Service::Ptr hc = GetHostCheckService();
if (hc) { if (hc) {
ObjectLock olock(hc); ObjectLock olock(hc);
@ -594,7 +570,7 @@ Dictionary::Ptr Host::CalculateDynamicMacros(const Host::Ptr& self)
break; break;
} }
if (!reachable) { if (!IsReachable()) {
state = "UNREACHABLE"; state = "UNREACHABLE";
stateid = 2; stateid = 2;
} }

View File

@ -49,15 +49,15 @@ public:
Dictionary::Ptr GetServiceDependencies(void) const; Dictionary::Ptr GetServiceDependencies(void) const;
String GetHostCheck(void) const; String GetHostCheck(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const Host::Ptr& self); Dictionary::Ptr CalculateDynamicMacros(void) const;
static shared_ptr<Service> GetHostCheckService(const Host::Ptr& self); shared_ptr<Service> GetHostCheckService(void) const;
static set<Host::Ptr> GetParentHosts(const Host::Ptr& self); set<Host::Ptr> GetParentHosts(void) const;
static set<shared_ptr<Service> > GetParentServices(const Host::Ptr& self); set<shared_ptr<Service> > GetParentServices(void) const;
static bool IsReachable(const Host::Ptr& self); bool IsReachable() const;
static shared_ptr<Service> GetServiceByShortName(const Host::Ptr& self, const Value& name); shared_ptr<Service> GetServiceByShortName(const Value& name) const;
set<shared_ptr<Service> > GetServices(void) const; set<shared_ptr<Service> > GetServices(void) const;
static void InvalidateServicesCache(void); static void InvalidateServicesCache(void);
@ -82,7 +82,7 @@ private:
static map<String, map<String, weak_ptr<Service> > > m_ServicesCache; static map<String, map<String, weak_ptr<Service> > > m_ServicesCache;
static bool m_ServicesCacheValid; static bool m_ServicesCacheValid;
static void UpdateSlaveServices(const Host::Ptr& self); void UpdateSlaveServices(void);
static void RefreshServicesCache(void); static void RefreshServicesCache(void);
}; };

View File

@ -40,26 +40,46 @@ HostGroup::~HostGroup(void)
InvalidateMembersCache(); InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
void HostGroup::OnRegistrationCompleted(void) void HostGroup::OnRegistrationCompleted(void)
{ {
assert(!OwnsLock());
InvalidateMembersCache(); InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
String HostGroup::GetDisplayName(void) const String HostGroup::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty()) if (!m_DisplayName.IsEmpty())
return m_DisplayName; return m_DisplayName;
else else
return GetName(); return GetName();
} }
/**
* @threadsafety Always.
*/
String HostGroup::GetNotesUrl(void) const String HostGroup::GetNotesUrl(void) const
{ {
ObjectLock olock(this);
return m_NotesUrl; return m_NotesUrl;
} }
/**
* @threadsafety Always.
*/
String HostGroup::GetActionUrl(void) const String HostGroup::GetActionUrl(void) const
{ {
ObjectLock olock(this);
return m_ActionUrl; return m_ActionUrl;
} }
@ -76,21 +96,17 @@ HostGroup::Ptr HostGroup::GetByName(const String& name)
return dynamic_pointer_cast<HostGroup>(configObject); return dynamic_pointer_cast<HostGroup>(configObject);
} }
set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self) /**
* @threadsafety Always.
*/
set<Host::Ptr> HostGroup::GetMembers(void) const
{ {
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Host::Ptr> hosts; set<Host::Ptr> hosts;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Host::WeakPtr& whost, m_MembersCache[name]) { BOOST_FOREACH(const Host::WeakPtr& whost, m_MembersCache[GetName()]) {
Host::Ptr host = whost.lock(); Host::Ptr host = whost.lock();
if (!host) if (!host)
@ -103,18 +119,22 @@ set<Host::Ptr> HostGroup::GetMembers(const HostGroup::Ptr& self)
return hosts; return hosts;
} }
/**
* @threadsafety Always.
*/
void HostGroup::InvalidateMembersCache(void) void HostGroup::InvalidateMembersCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid) if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&HostGroup::RefreshMembersCache)); Utility::QueueAsyncCallback(boost::bind(&HostGroup::RefreshMembersCache));
m_MembersCacheValid = false; m_MembersCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void HostGroup::RefreshMembersCache(void) void HostGroup::RefreshMembersCache(void)
{ {
{ {

View File

@ -43,7 +43,7 @@ public:
String GetNotesUrl(void) const; String GetNotesUrl(void) const;
String GetActionUrl(void) const; String GetActionUrl(void) const;
static set<Host::Ptr> GetMembers(const HostGroup::Ptr& self); set<Host::Ptr> GetMembers(void) const;
static void InvalidateMembersCache(void); static void InvalidateMembersCache(void);

View File

@ -85,13 +85,24 @@ int IcingaApplication::Main(void)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/**
* @threadsafety Always.
*/
void IcingaApplication::OnShutdown(void) void IcingaApplication::OnShutdown(void)
{ {
m_RetentionTimer->Stop(); assert(!OwnsLock());
{
ObjectLock olock(this);
m_RetentionTimer->Stop();
}
DumpProgramState(); DumpProgramState();
} }
/**
* @threadsafety Always.
*/
void IcingaApplication::DumpProgramState(void) void IcingaApplication::DumpProgramState(void)
{ {
DynamicObject::DumpObjects(GetStatePath()); DynamicObject::DumpObjects(GetStatePath());
@ -102,58 +113,106 @@ IcingaApplication::Ptr IcingaApplication::GetInstance(void)
return static_pointer_cast<IcingaApplication>(Application::GetInstance()); return static_pointer_cast<IcingaApplication>(Application::GetInstance());
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetCertificateFile(void) const String IcingaApplication::GetCertificateFile(void) const
{ {
ObjectLock olock(this);
return m_CertPath; return m_CertPath;
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetCAFile(void) const String IcingaApplication::GetCAFile(void) const
{ {
ObjectLock olock(this);
return m_CAPath; return m_CAPath;
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetNode(void) const String IcingaApplication::GetNode(void) const
{ {
ObjectLock olock(this);
return m_Node; return m_Node;
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetService(void) const String IcingaApplication::GetService(void) const
{ {
ObjectLock olock(this);
return m_Service; return m_Service;
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetPidPath(void) const String IcingaApplication::GetPidPath(void) const
{ {
ObjectLock olock(this);
if (m_PidPath.IsEmpty()) if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/run/icinga2.pid"; return Application::GetLocalStateDir() + "/run/icinga2.pid";
else else
return m_PidPath; return m_PidPath;
} }
/**
* @threadsafety Always.
*/
String IcingaApplication::GetStatePath(void) const String IcingaApplication::GetStatePath(void) const
{ {
ObjectLock olock(this);
if (m_PidPath.IsEmpty()) if (m_PidPath.IsEmpty())
return Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state"; return Application::GetLocalStateDir() + "/lib/icinga2/icinga2.state";
else else
return m_PidPath; return m_PidPath;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr IcingaApplication::GetMacros(void) const Dictionary::Ptr IcingaApplication::GetMacros(void) const
{ {
ObjectLock olock(this);
return m_Macros; return m_Macros;
} }
/**
* @threadsafety Always.
*/
double IcingaApplication::GetStartTime(void) const double IcingaApplication::GetStartTime(void) const
{ {
ObjectLock olock(this);
return m_StartTime; return m_StartTime;
} }
/**
* @threadsafety Always.
*/
shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const shared_ptr<SSL_CTX> IcingaApplication::GetSSLContext(void) const
{ {
ObjectLock olock(this);
return m_SSLContext; return m_SSLContext;
} }
Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(const IcingaApplication::Ptr& self) /**
* @threadsafety Always.
*/
Dictionary::Ptr IcingaApplication::CalculateDynamicMacros(void)
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros); ObjectLock mlock(macros);

View File

@ -51,7 +51,7 @@ public:
double GetStartTime(void) const; double GetStartTime(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const IcingaApplication::Ptr& self); static Dictionary::Ptr CalculateDynamicMacros(void);
private: private:
Attribute<String> m_CertPath; Attribute<String> m_CertPath;

View File

@ -21,10 +21,15 @@
using namespace icinga; using namespace icinga;
/**
* @threadsafety Always.
*/
Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& macros) Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& macros)
{ {
Value result; Value result;
assert(macros->IsSealed());
if (cmd.IsScalar()) { if (cmd.IsScalar()) {
result = InternalResolveMacros(cmd, macros); result = InternalResolveMacros(cmd, macros);
} else if (cmd.IsObjectType<Dictionary>()) { } else if (cmd.IsObjectType<Dictionary>()) {
@ -46,6 +51,9 @@ Value MacroProcessor::ResolveMacros(const Value& cmd, const Dictionary::Ptr& mac
return result; return result;
} }
/**
* @threadsafety Always.
*/
String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary::Ptr& macros) String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary::Ptr& macros)
{ {
ObjectLock olock(macros); ObjectLock olock(macros);
@ -73,6 +81,9 @@ String MacroProcessor::InternalResolveMacros(const String& str, const Dictionary
return result; return result;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr MacroProcessor::MergeMacroDicts(const vector<Dictionary::Ptr>& dicts) Dictionary::Ptr MacroProcessor::MergeMacroDicts(const vector<Dictionary::Ptr>& dicts)
{ {
Dictionary::Ptr result = boost::make_shared<Dictionary>(); Dictionary::Ptr result = boost::make_shared<Dictionary>();

View File

@ -39,6 +39,9 @@ Notification::~Notification(void)
Service::InvalidateNotificationsCache(); Service::InvalidateNotificationsCache();
} }
/**
* @threadsafety Always.
*/
Notification::Ptr Notification::GetByName(const String& name) Notification::Ptr Notification::GetByName(const String& name)
{ {
DynamicObject::Ptr configObject = DynamicObject::GetObject("Notification", name); DynamicObject::Ptr configObject = DynamicObject::GetObject("Notification", name);
@ -46,34 +49,57 @@ Notification::Ptr Notification::GetByName(const String& name)
return dynamic_pointer_cast<Notification>(configObject); return dynamic_pointer_cast<Notification>(configObject);
} }
/**
* @threadsafety Always.
*/
Service::Ptr Notification::GetService(void) const Service::Ptr Notification::GetService(void) const
{ {
ObjectLock olock(this);
Host::Ptr host = Host::GetByName(m_HostName); Host::Ptr host = Host::GetByName(m_HostName);
if (!host) if (!host)
return Service::Ptr(); return Service::Ptr();
if (m_Service.IsEmpty()) if (m_Service.IsEmpty())
return Host::GetHostCheckService(host); return host->GetHostCheckService();
else else
return Host::GetServiceByShortName(host, m_Service); return host->GetServiceByShortName(m_Service);
} }
/**
* @threadsafety Always.
*/
Value Notification::GetNotificationCommand(void) const Value Notification::GetNotificationCommand(void) const
{ {
ObjectLock olock(this);
return m_NotificationCommand; return m_NotificationCommand;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Notification::GetMacros(void) const Dictionary::Ptr Notification::GetMacros(void) const
{ {
ObjectLock olock(this);
return m_Macros; return m_Macros;
} }
/**
* @threadsafety Always.
*/
set<User::Ptr> Notification::GetUsers(void) const set<User::Ptr> Notification::GetUsers(void) const
{ {
set<User::Ptr> result; set<User::Ptr> result;
Dictionary::Ptr users = m_Users; Dictionary::Ptr users;
{
ObjectLock olock(this);
users = m_Users;
}
if (users) { if (users) {
ObjectLock olock(users); ObjectLock olock(users);
@ -92,11 +118,19 @@ set<User::Ptr> Notification::GetUsers(void) const
return result; return result;
} }
/**
* @threadsafety Always.
*/
set<UserGroup::Ptr> Notification::GetGroups(void) const set<UserGroup::Ptr> Notification::GetGroups(void) const
{ {
set<UserGroup::Ptr> result; set<UserGroup::Ptr> result;
Dictionary::Ptr groups = m_Groups; Dictionary::Ptr groups;
{
ObjectLock olock(this);
groups = m_Groups;
}
if (groups) { if (groups) {
ObjectLock olock(groups); ObjectLock olock(groups);
@ -115,6 +149,9 @@ set<UserGroup::Ptr> Notification::GetGroups(void) const
return result; return result;
} }
/**
* @threadsafety Always.
*/
String Notification::NotificationTypeToString(NotificationType type) String Notification::NotificationTypeToString(NotificationType type)
{ {
switch (type) { switch (type) {
@ -137,8 +174,12 @@ String Notification::NotificationTypeToString(NotificationType type)
} }
} }
void Notification::BeginExecuteNotification(const Notification::Ptr& self, NotificationType type) /**
* @threadsafety Always.
*/
void Notification::BeginExecuteNotification(NotificationType type)
{ {
assert(!OwnsLock());
vector<Dictionary::Ptr> macroDicts; vector<Dictionary::Ptr> macroDicts;
@ -146,53 +187,36 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type)); notificationMacros->Set("NOTIFICATIONTYPE", NotificationTypeToString(type));
macroDicts.push_back(notificationMacros); macroDicts.push_back(notificationMacros);
Service::Ptr service; macroDicts.push_back(GetMacros());
set<User::Ptr> users;
set<UserGroup::Ptr> groups;
{ Service::Ptr service = GetService();
ObjectLock olock(self);
macroDicts.push_back(self->GetMacros());
service = self->GetService();
users = self->GetUsers();
groups = self->GetGroups();
}
Host::Ptr host; if (service) {
String service_name;
{
ObjectLock olock(service);
macroDicts.push_back(service->GetMacros()); macroDicts.push_back(service->GetMacros());
service_name = service->GetName(); macroDicts.push_back(service->CalculateDynamicMacros());
host = service->GetHost();
}
macroDicts.push_back(Service::CalculateDynamicMacros(service)); Host::Ptr host = service->GetHost();
{ if (host) {
ObjectLock olock(host); macroDicts.push_back(host->GetMacros());
macroDicts.push_back(host->GetMacros()); macroDicts.push_back(host->CalculateDynamicMacros());
macroDicts.push_back(Host::CalculateDynamicMacros(host)); }
} }
IcingaApplication::Ptr app = IcingaApplication::GetInstance(); IcingaApplication::Ptr app = IcingaApplication::GetInstance();
macroDicts.push_back(app->GetMacros());
{ macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
ObjectLock olock(app);
macroDicts.push_back(app->GetMacros());
}
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts); Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
set<User::Ptr> allUsers; set<User::Ptr> allUsers;
set<User::Ptr> users = GetUsers();
std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin())); std::copy(users.begin(), users.end(), std::inserter(allUsers, allUsers.begin()));
BOOST_FOREACH(const UserGroup::Ptr& ug, groups) { BOOST_FOREACH(const UserGroup::Ptr& ug, GetGroups()) {
set<User::Ptr> members = UserGroup::GetMembers(ug); set<User::Ptr> members = ug->GetMembers();
std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin())); std::copy(members.begin(), members.end(), std::inserter(allUsers, allUsers.begin()));
} }
@ -205,58 +229,66 @@ void Notification::BeginExecuteNotification(const Notification::Ptr& self, Notif
} }
Logger::Write(LogDebug, "icinga", "Sending notification for user " + user_name); Logger::Write(LogDebug, "icinga", "Sending notification for user " + user_name);
BeginExecuteNotificationHelper(self, macros, type, user); BeginExecuteNotificationHelper(macros, type, user);
} }
if (allUsers.size() == 0) { if (allUsers.size() == 0) {
/* Send a notification even if there are no users specified. */ /* Send a notification even if there are no users specified. */
BeginExecuteNotificationHelper(self, macros, type, User::Ptr()); BeginExecuteNotificationHelper(macros, type, User::Ptr());
} }
} }
void Notification::BeginExecuteNotificationHelper(const Notification::Ptr& self, const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user) /**
* @threadsafety Always.
*/
void Notification::BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user)
{ {
assert(!OwnsLock());
vector<Dictionary::Ptr> macroDicts; vector<Dictionary::Ptr> macroDicts;
if (user) { if (user) {
{ macroDicts.push_back(user->GetMacros());
ObjectLock olock(user); macroDicts.push_back(user->CalculateDynamicMacros());
macroDicts.push_back(user->GetMacros());
}
macroDicts.push_back(User::CalculateDynamicMacros(user));
} }
macroDicts.push_back(notificationMacros); macroDicts.push_back(notificationMacros);
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts); Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
Notification::Ptr self = GetSelf();
vector<Value> arguments;
arguments.push_back(self);
arguments.push_back(macros);
arguments.push_back(type);
ScriptTask::Ptr task; ScriptTask::Ptr task;
task = MakeMethodTask("notify", arguments);
if (!task) {
Logger::Write(LogWarning, "icinga", "Notification object '" + GetName() + "' doesn't have a 'notify' method.");
return;
}
{ {
ObjectLock olock(self); ObjectLock olock(this);
vector<Value> arguments;
arguments.push_back(self);
arguments.push_back(macros);
arguments.push_back(type);
task = self->MakeMethodTask("notify", arguments);
if (!task) {
Logger::Write(LogWarning, "icinga", "Notification object '" + self->GetName() + "' doesn't have a 'notify' method.");
return;
}
/* We need to keep the task object alive until the completion handler is called. */ /* We need to keep the task object alive until the completion handler is called. */
self->m_Tasks.insert(task); m_Tasks.insert(task);
} }
task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1)); task->Start(boost::bind(&Notification::NotificationCompletedHandler, self, _1));
} }
/**
* @threadsafety Always.
*/
void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task) void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
{ {
assert(!OwnsLock());
m_Tasks.erase(task); m_Tasks.erase(task);
try { try {
@ -273,8 +305,13 @@ void Notification::NotificationCompletedHandler(const ScriptTask::Ptr& task)
} }
} }
/**
* @threadsafety Always.
*/
void Notification::OnAttributeChanged(const String& name, const Value& oldValue) void Notification::OnAttributeChanged(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
if (name == "host_name" || name == "service") if (name == "host_name" || name == "service")
Service::InvalidateNotificationsCache(); Service::InvalidateNotificationsCache();
} }

View File

@ -63,7 +63,7 @@ public:
set<User::Ptr> GetUsers(void) const; set<User::Ptr> GetUsers(void) const;
set<UserGroup::Ptr> GetGroups(void) const; set<UserGroup::Ptr> GetGroups(void) const;
static void BeginExecuteNotification(const Notification::Ptr& self, NotificationType type); void BeginExecuteNotification(NotificationType type);
static String NotificationTypeToString(NotificationType type); static String NotificationTypeToString(NotificationType type);
@ -82,8 +82,8 @@ private:
void NotificationCompletedHandler(const ScriptTask::Ptr& task); void NotificationCompletedHandler(const ScriptTask::Ptr& task);
static void BeginExecuteNotificationHelper(const Notification::Ptr& self, void BeginExecuteNotificationHelper(const Dictionary::Ptr& notificationMacros,
const Dictionary::Ptr& notificationMacros, NotificationType type, const User::Ptr& user); NotificationType type, const User::Ptr& user);
}; };
} }

View File

@ -23,6 +23,9 @@ using namespace icinga;
REGISTER_SCRIPTFUNCTION("NullCheck", &NullCheckTask::ScriptFunc); REGISTER_SCRIPTFUNCTION("NullCheck", &NullCheckTask::ScriptFunc);
/**
* @threadsafety Always.
*/
void NullCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments) void NullCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{ {
if (arguments.size() < 1) if (arguments.size() < 1)
@ -31,8 +34,5 @@ void NullCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>&
Dictionary::Ptr cr = boost::make_shared<Dictionary>(); Dictionary::Ptr cr = boost::make_shared<Dictionary>();
cr->Set("state", StateUnknown); cr->Set("state", StateUnknown);
{ task->FinishResult(cr);
ObjectLock olock(task);
task->FinishResult(cr);
}
} }

View File

@ -35,16 +35,26 @@ PerfdataWriter::~PerfdataWriter(void)
{ {
} }
/**
* @threadsafety Always.
*/
void PerfdataWriter::OnAttributeChanged(const String& name, const Value& oldValue) void PerfdataWriter::OnAttributeChanged(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
if (name == "rotation_interval") { if (name == "rotation_interval") {
ObjectLock olock(this); ObjectLock olock(this);
m_RotationTimer->SetInterval(GetRotationInterval()); m_RotationTimer->SetInterval(GetRotationInterval());
} }
} }
/**
* @threadsafety Always.
*/
void PerfdataWriter::Start(void) void PerfdataWriter::Start(void)
{ {
ObjectLock olock(this);
m_Endpoint = Endpoint::MakeEndpoint("perfdata_" + GetName(), false); m_Endpoint = Endpoint::MakeEndpoint("perfdata_" + GetName(), false);
{ {
@ -62,6 +72,9 @@ void PerfdataWriter::Start(void)
RotateFile(); RotateFile();
} }
/**
* @threadsafety Always.
*/
PerfdataWriter::Ptr PerfdataWriter::GetByName(const String& name) PerfdataWriter::Ptr PerfdataWriter::GetByName(const String& name)
{ {
DynamicObject::Ptr configObject = DynamicObject::GetObject("PerfdataWriter", name); DynamicObject::Ptr configObject = DynamicObject::GetObject("PerfdataWriter", name);
@ -69,16 +82,26 @@ PerfdataWriter::Ptr PerfdataWriter::GetByName(const String& name)
return dynamic_pointer_cast<PerfdataWriter>(configObject); return dynamic_pointer_cast<PerfdataWriter>(configObject);
} }
/**
* @threadsafety Always.
*/
String PerfdataWriter::GetPathPrefix(void) const String PerfdataWriter::GetPathPrefix(void) const
{ {
ObjectLock olock(this);
if (!m_PathPrefix.IsEmpty()) if (!m_PathPrefix.IsEmpty())
return m_PathPrefix; return m_PathPrefix;
else else
return Application::GetLocalStateDir() + "/cache/icinga2/perfdata/perfdata"; return Application::GetLocalStateDir() + "/cache/icinga2/perfdata/perfdata";
} }
/**
* @threadsafety Always.
*/
String PerfdataWriter::GetFormatTemplate(void) const String PerfdataWriter::GetFormatTemplate(void) const
{ {
ObjectLock olock(this);
if (!m_FormatTemplate.IsEmpty()) { if (!m_FormatTemplate.IsEmpty()) {
return m_FormatTemplate; return m_FormatTemplate;
} else { } else {
@ -95,14 +118,22 @@ String PerfdataWriter::GetFormatTemplate(void) const
} }
} }
/**
* @threadsafety Always.
*/
double PerfdataWriter::GetRotationInterval(void) const double PerfdataWriter::GetRotationInterval(void) const
{ {
ObjectLock olock(this);
if (!m_RotationInterval.IsEmpty()) if (!m_RotationInterval.IsEmpty())
return m_RotationInterval; return m_RotationInterval;
else else
return 30; return 30;
} }
/**
* @threadsafety Always.
*/
void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request) void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request)
{ {
CheckResultMessage params; CheckResultMessage params;
@ -119,15 +150,20 @@ void PerfdataWriter::CheckResultRequestHandler(const RequestMessage& request)
Dictionary::Ptr macros = cr->Get("macros"); Dictionary::Ptr macros = cr->Get("macros");
String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), macros); String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), macros);
ObjectLock olock(this);
if (!m_OutputFile.good()) if (!m_OutputFile.good())
return; return;
ObjectLock olock(this);
m_OutputFile << line << "\n"; m_OutputFile << line << "\n";
} }
/**
* @threadsafety Always.
*/
void PerfdataWriter::RotateFile(void) void PerfdataWriter::RotateFile(void)
{ {
ObjectLock olock(this);
String tempFile = GetPathPrefix(); String tempFile = GetPathPrefix();
if (m_OutputFile.good()) { if (m_OutputFile.good()) {
@ -143,8 +179,10 @@ void PerfdataWriter::RotateFile(void)
Logger::Write(LogWarning, "icinga", "Could not open perfdata file '" + tempFile + "' for writing. Perfdata will be lost."); Logger::Write(LogWarning, "icinga", "Could not open perfdata file '" + tempFile + "' for writing. Perfdata will be lost.");
} }
/**
* @threadsafety Always.
*/
void PerfdataWriter::RotationTimerHandler(void) void PerfdataWriter::RotationTimerHandler(void)
{ {
ObjectLock olock(this);
RotateFile(); RotateFile();
} }

View File

@ -27,6 +27,9 @@ PluginCheckTask::PluginCheckTask(const ScriptTask::Ptr& task, const Process::Ptr
: m_Task(task), m_Process(process), m_Command(command) : m_Task(task), m_Process(process), m_Command(command)
{ } { }
/**
* @threadsafety Always.
*/
void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments) void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value>& arguments)
{ {
if (arguments.size() < 1) if (arguments.size() < 1)
@ -38,13 +41,7 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
Service::Ptr service = arguments[0]; Service::Ptr service = arguments[0];
Dictionary::Ptr macros = arguments[1]; Dictionary::Ptr macros = arguments[1];
Value raw_command; Value raw_command = service->GetCheckCommand();
{
ObjectLock olock(service);
raw_command = service->GetCheckCommand();
}
Value command = MacroProcessor::ResolveMacros(raw_command, macros); Value command = MacroProcessor::ResolveMacros(raw_command, macros);
Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros); Process::Ptr process = boost::make_shared<Process>(Process::SplitCommand(command), macros);
@ -54,6 +51,9 @@ void PluginCheckTask::ScriptFunc(const ScriptTask::Ptr& task, const vector<Value
process->Start(boost::bind(&PluginCheckTask::ProcessFinishedHandler, ct)); process->Start(boost::bind(&PluginCheckTask::ProcessFinishedHandler, ct));
} }
/**
* @threadsafety Always.
*/
void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct) void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
{ {
ProcessResult pr; ProcessResult pr;
@ -77,6 +77,9 @@ void PluginCheckTask::ProcessFinishedHandler(PluginCheckTask ct)
ct.m_Task->FinishResult(result); ct.m_Task->FinishResult(result);
} }
/**
* @threadsafety Always.
*/
ServiceState PluginCheckTask::ExitStatusToState(int exitStatus) ServiceState PluginCheckTask::ExitStatusToState(int exitStatus)
{ {
switch (exitStatus) { switch (exitStatus) {
@ -91,6 +94,9 @@ ServiceState PluginCheckTask::ExitStatusToState(int exitStatus)
} }
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr PluginCheckTask::ParseCheckOutput(const String& output) Dictionary::Ptr PluginCheckTask::ParseCheckOutput(const String& output)
{ {
Dictionary::Ptr result = boost::make_shared<Dictionary>(); Dictionary::Ptr result = boost::make_shared<Dictionary>();

View File

@ -46,20 +46,13 @@ void PluginNotificationTask::ScriptFunc(const ScriptTask::Ptr& task, const vecto
Dictionary::Ptr macros = arguments[1]; Dictionary::Ptr macros = arguments[1];
NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2])); NotificationType type = static_cast<NotificationType>(static_cast<int>(arguments[2]));
Value raw_command; Value raw_command = notification->GetNotificationCommand();
String service_name; String service_name;
Service::Ptr service;
{ Service::Ptr service = notification->GetService();
ObjectLock olock(notification); if (service)
raw_command = notification->GetNotificationCommand();
service = notification->GetService();
}
{
ObjectLock olock(service);
service_name = service->GetName(); service_name = service->GetName();
}
Value command = MacroProcessor::ResolveMacros(raw_command, macros); Value command = MacroProcessor::ResolveMacros(raw_command, macros);
@ -78,9 +71,7 @@ void PluginNotificationTask::ProcessFinishedHandler(PluginNotificationTask ct)
ProcessResult pr; ProcessResult pr;
try { try {
{ pr = ct.m_Process->GetResult();
pr = ct.m_Process->GetResult();
}
if (pr.ExitStatus != 0) { if (pr.ExitStatus != 0) {
stringstream msgbuf; stringstream msgbuf;

View File

@ -28,58 +28,103 @@ const int Service::CheckIntervalDivisor = 5;
signals2::signal<void (const Service::Ptr&, const String&)> Service::OnCheckerChanged; signals2::signal<void (const Service::Ptr&, const String&)> Service::OnCheckerChanged;
signals2::signal<void (const Service::Ptr&, const Value&)> Service::OnNextCheckChanged; signals2::signal<void (const Service::Ptr&, const Value&)> Service::OnNextCheckChanged;
/**
* @threadsafety Always.
*/
Value Service::GetCheckCommand(void) const Value Service::GetCheckCommand(void) const
{ {
ObjectLock olock(this);
return m_CheckCommand; return m_CheckCommand;
} }
/**
* @threadsafety Always.
*/
long Service::GetMaxCheckAttempts(void) const long Service::GetMaxCheckAttempts(void) const
{ {
ObjectLock olock(this);
if (m_MaxCheckAttempts.IsEmpty()) if (m_MaxCheckAttempts.IsEmpty())
return DefaultMaxCheckAttempts; return DefaultMaxCheckAttempts;
return m_MaxCheckAttempts; return m_MaxCheckAttempts;
} }
/**
* @threadsafety Always.
*/
double Service::GetCheckInterval(void) const double Service::GetCheckInterval(void) const
{ {
ObjectLock olock(this);
if (m_CheckInterval.IsEmpty()) if (m_CheckInterval.IsEmpty())
return DefaultCheckInterval; return DefaultCheckInterval;
return m_CheckInterval; return m_CheckInterval;
} }
/**
* @threadsafety Always.
*/
double Service::GetRetryInterval(void) const double Service::GetRetryInterval(void) const
{ {
ObjectLock olock(this);
if (m_RetryInterval.IsEmpty()) if (m_RetryInterval.IsEmpty())
return GetCheckInterval() / CheckIntervalDivisor; return GetCheckInterval() / CheckIntervalDivisor;
return m_RetryInterval; return m_RetryInterval;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetCheckers(void) const Dictionary::Ptr Service::GetCheckers(void) const
{ {
ObjectLock olock(this);
return m_Checkers; return m_Checkers;
} }
/**
* @threadsafety Always.
*/
void Service::SetSchedulingOffset(long offset) void Service::SetSchedulingOffset(long offset)
{ {
ObjectLock olock(this);
m_SchedulingOffset = offset; m_SchedulingOffset = offset;
} }
/**
* @threadsafety Always.
*/
long Service::GetSchedulingOffset(void) long Service::GetSchedulingOffset(void)
{ {
ObjectLock olock(this);
return m_SchedulingOffset; return m_SchedulingOffset;
} }
/**
* @threadsafety Always.
*/
void Service::SetNextCheck(double nextCheck) void Service::SetNextCheck(double nextCheck)
{ {
ObjectLock olock(this);
m_NextCheck = nextCheck; m_NextCheck = nextCheck;
Touch("next_check"); Touch("next_check");
} }
/**
* @threadsafety Always.
*/
double Service::GetNextCheck(void) double Service::GetNextCheck(void)
{ {
ObjectLock olock(this);
if (m_NextCheck.IsEmpty()) { if (m_NextCheck.IsEmpty()) {
UpdateNextCheck(); UpdateNextCheck();
@ -90,8 +135,13 @@ double Service::GetNextCheck(void)
return m_NextCheck; return m_NextCheck;
} }
/**
* @threadsafety Always.
*/
void Service::UpdateNextCheck(void) void Service::UpdateNextCheck(void)
{ {
ObjectLock olock(this);
double interval; double interval;
if (GetStateType() == StateTypeSoft) if (GetStateType() == StateTypeSoft)
@ -108,39 +158,69 @@ void Service::UpdateNextCheck(void)
SetNextCheck(now - adj + interval); SetNextCheck(now - adj + interval);
} }
/**
* @threadsafety Always.
*/
void Service::SetCurrentChecker(const String& checker) void Service::SetCurrentChecker(const String& checker)
{ {
ObjectLock olock(this);
m_CurrentChecker = checker; m_CurrentChecker = checker;
Touch("current_checker"); Touch("current_checker");
} }
/**
* @threadsafety Always.
*/
String Service::GetCurrentChecker(void) const String Service::GetCurrentChecker(void) const
{ {
ObjectLock olock(this);
return m_CurrentChecker; return m_CurrentChecker;
} }
/**
* @threadsafety Always.
*/
void Service::SetCurrentCheckAttempt(long attempt) void Service::SetCurrentCheckAttempt(long attempt)
{ {
ObjectLock olock(this);
m_CheckAttempt = attempt; m_CheckAttempt = attempt;
Touch("check_attempt"); Touch("check_attempt");
} }
/**
* @threadsafety Always.
*/
long Service::GetCurrentCheckAttempt(void) const long Service::GetCurrentCheckAttempt(void) const
{ {
ObjectLock olock(this);
if (m_CheckAttempt.IsEmpty()) if (m_CheckAttempt.IsEmpty())
return 1; return 1;
return m_CheckAttempt; return m_CheckAttempt;
} }
/**
* @threadsafety Always.
*/
void Service::SetState(ServiceState state) void Service::SetState(ServiceState state)
{ {
ObjectLock olock(this);
m_State = static_cast<long>(state); m_State = static_cast<long>(state);
Touch("state"); Touch("state");
} }
/**
* @threadsafety Always.
*/
ServiceState Service::GetState(void) const ServiceState Service::GetState(void) const
{ {
ObjectLock olock(this);
if (m_State.IsEmpty()) if (m_State.IsEmpty())
return StateUnknown; return StateUnknown;
@ -148,14 +228,24 @@ ServiceState Service::GetState(void) const
return static_cast<ServiceState>(ivalue); return static_cast<ServiceState>(ivalue);
} }
/**
* @threadsafety Always.
*/
void Service::SetStateType(ServiceStateType type) void Service::SetStateType(ServiceStateType type)
{ {
ObjectLock olock(this);
m_StateType = static_cast<long>(type); m_StateType = static_cast<long>(type);
Touch("state_type"); Touch("state_type");
} }
/**
* @threadsafety Always.
*/
ServiceStateType Service::GetStateType(void) const ServiceStateType Service::GetStateType(void) const
{ {
ObjectLock olock(this);
if (m_StateType.IsEmpty()) if (m_StateType.IsEmpty())
return StateTypeSoft; return StateTypeSoft;
@ -163,89 +253,155 @@ ServiceStateType Service::GetStateType(void) const
return static_cast<ServiceStateType>(ivalue); return static_cast<ServiceStateType>(ivalue);
} }
/**
* @threadsafety Always.
*/
void Service::SetLastCheckResult(const Dictionary::Ptr& result) void Service::SetLastCheckResult(const Dictionary::Ptr& result)
{ {
ObjectLock olock(this);
m_LastResult = result; m_LastResult = result;
Touch("last_result"); Touch("last_result");
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetLastCheckResult(void) const Dictionary::Ptr Service::GetLastCheckResult(void) const
{ {
ObjectLock olock(this);
return m_LastResult; return m_LastResult;
} }
/**
* @threadsafety Always.
*/
void Service::SetLastStateChange(double ts) void Service::SetLastStateChange(double ts)
{ {
ObjectLock olock(this);
m_LastStateChange = ts; m_LastStateChange = ts;
Touch("last_state_change"); Touch("last_state_change");
} }
/**
* @threadsafety Always.
*/
double Service::GetLastStateChange(void) const double Service::GetLastStateChange(void) const
{ {
ObjectLock olock(this);
if (m_LastStateChange.IsEmpty()) if (m_LastStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime(); return IcingaApplication::GetInstance()->GetStartTime();
return m_LastStateChange; return m_LastStateChange;
} }
/**
* @threadsafety Always.
*/
void Service::SetLastHardStateChange(double ts) void Service::SetLastHardStateChange(double ts)
{ {
ObjectLock olock(this);
m_LastHardStateChange = ts; m_LastHardStateChange = ts;
Touch("last_hard_state_change"); Touch("last_hard_state_change");
} }
/**
* @threadsafety Always.
*/
double Service::GetLastHardStateChange(void) const double Service::GetLastHardStateChange(void) const
{ {
ObjectLock olock(this);
if (m_LastHardStateChange.IsEmpty()) if (m_LastHardStateChange.IsEmpty())
return IcingaApplication::GetInstance()->GetStartTime(); return IcingaApplication::GetInstance()->GetStartTime();
return m_LastHardStateChange; return m_LastHardStateChange;
} }
/**
* @threadsafety Always.
*/
bool Service::GetEnableActiveChecks(void) const bool Service::GetEnableActiveChecks(void) const
{ {
ObjectLock olock(this);
if (m_EnableActiveChecks.IsEmpty()) if (m_EnableActiveChecks.IsEmpty())
return true; return true;
else else
return m_EnableActiveChecks; return m_EnableActiveChecks;
} }
/**
* @threadsafety Always.
*/
void Service::SetEnableActiveChecks(bool enabled) void Service::SetEnableActiveChecks(bool enabled)
{ {
ObjectLock olock(this);
m_EnableActiveChecks = enabled ? 1 : 0; m_EnableActiveChecks = enabled ? 1 : 0;
Touch("enable_active_checks"); Touch("enable_active_checks");
} }
/**
* @threadsafety Always.
*/
bool Service::GetEnablePassiveChecks(void) const bool Service::GetEnablePassiveChecks(void) const
{ {
ObjectLock olock(this);
if (m_EnablePassiveChecks.IsEmpty()) if (m_EnablePassiveChecks.IsEmpty())
return true; return true;
else else
return m_EnablePassiveChecks; return m_EnablePassiveChecks;
} }
/**
* @threadsafety Always.
*/
void Service::SetEnablePassiveChecks(bool enabled) void Service::SetEnablePassiveChecks(bool enabled)
{ {
ObjectLock olock(this);
m_EnablePassiveChecks = enabled ? 1 : 0; m_EnablePassiveChecks = enabled ? 1 : 0;
Touch("enable_passive_checks"); Touch("enable_passive_checks");
} }
/**
* @threadsafety Always.
*/
bool Service::GetForceNextCheck(void) const bool Service::GetForceNextCheck(void) const
{ {
ObjectLock olock(this);
if (m_ForceNextCheck.IsEmpty()) if (m_ForceNextCheck.IsEmpty())
return false; return false;
return static_cast<bool>(m_ForceNextCheck); return static_cast<bool>(m_ForceNextCheck);
} }
/**
* @threadsafety Always.
*/
void Service::SetForceNextCheck(bool forced) void Service::SetForceNextCheck(bool forced)
{ {
ObjectLock olock(this);
m_ForceNextCheck = forced ? 1 : 0; m_ForceNextCheck = forced ? 1 : 0;
Touch("force_next_check"); Touch("force_next_check");
} }
void Service::ApplyCheckResult(const Dictionary::Ptr& cr) /**
* @threadsafety Always.
*/
void Service::ProcessCheckResult(const Dictionary::Ptr& cr)
{ {
assert(!OwnsLock());
ObjectLock olock(this);
ServiceState old_state = GetState(); ServiceState old_state = GetState();
ServiceStateType old_stateType = GetStateType(); ServiceStateType old_stateType = GetStateType();
bool hardChange = false; bool hardChange = false;
@ -298,13 +454,13 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
} }
/* reschedule service dependencies */ /* reschedule service dependencies */
BOOST_FOREACH(const Service::Ptr& parent, Service::GetParentServices(GetSelf())) { BOOST_FOREACH(const Service::Ptr& parent, GetParentServices()) {
parent->SetNextCheck(Utility::GetTime()); parent->SetNextCheck(Utility::GetTime());
} }
/* reschedule host dependencies */ /* reschedule host dependencies */
BOOST_FOREACH(const Host::Ptr& parent, Service::GetParentHosts(GetSelf())) { BOOST_FOREACH(const Host::Ptr& parent, GetParentHosts()) {
Service::Ptr service = Host::GetHostCheckService(parent); Service::Ptr service = parent->GetHostCheckService();
if (service) { if (service) {
ObjectLock olock(service); ObjectLock olock(service);
@ -313,21 +469,39 @@ void Service::ApplyCheckResult(const Dictionary::Ptr& cr)
} }
} }
if (hardChange)
SetLastHardStateChange(now);
if (GetState() != StateOK) if (GetState() != StateOK)
TriggerDowntimes(); TriggerDowntimes();
if (hardChange) { Service::UpdateStatistics(cr);
SetLastHardStateChange(now);
/* Make sure the notification component sees the updated olock.Unlock();
* state/state_type attributes. */
Flush();
if (IsReachable(GetSelf()) && !IsInDowntime() && !IsAcknowledged()) /* Flush the object so other instances see the service's
RequestNotifications(recovery ? NotificationRecovery : NotificationProblem); * new state when they receive the CheckResult message */
} Flush();
RequestMessage rm;
rm.SetMethod("checker::CheckResult");
/* TODO: add _old_ state to message */
CheckResultMessage params;
params.SetService(GetName());
params.SetCheckResult(cr);
rm.SetParams(params);
EndpointManager::GetInstance()->SendMulticastMessage(rm);
if (hardChange && IsReachable() && !IsInDowntime() && !IsAcknowledged())
RequestNotifications(recovery ? NotificationRecovery : NotificationProblem);
} }
/**
* @threadsafety Always.
*/
ServiceState Service::StateFromString(const String& state) ServiceState Service::StateFromString(const String& state)
{ {
if (state == "OK") if (state == "OK")
@ -342,6 +516,9 @@ ServiceState Service::StateFromString(const String& state)
return StateUnknown; return StateUnknown;
} }
/**
* @threadsafety Always.
*/
String Service::StateToString(ServiceState state) String Service::StateToString(ServiceState state)
{ {
switch (state) { switch (state) {
@ -359,6 +536,9 @@ String Service::StateToString(ServiceState state)
} }
} }
/**
* @threadsafety Always.
*/
ServiceStateType Service::StateTypeFromString(const String& type) ServiceStateType Service::StateTypeFromString(const String& type)
{ {
if (type == "SOFT") if (type == "SOFT")
@ -367,6 +547,9 @@ ServiceStateType Service::StateTypeFromString(const String& type)
return StateTypeHard; return StateTypeHard;
} }
/**
* @threadsafety Always.
*/
String Service::StateTypeToString(ServiceStateType type) String Service::StateTypeToString(ServiceStateType type)
{ {
if (type == StateTypeSoft) if (type == StateTypeSoft)
@ -375,6 +558,9 @@ String Service::StateTypeToString(ServiceStateType type)
return "HARD"; return "HARD";
} }
/**
* @threadsafety Always.
*/
bool Service::IsAllowedChecker(const String& checker) const bool Service::IsAllowedChecker(const String& checker) const
{ {
Dictionary::Ptr checkers = GetCheckers(); Dictionary::Ptr checkers = GetCheckers();
@ -382,6 +568,8 @@ bool Service::IsAllowedChecker(const String& checker) const
if (!checkers) if (!checkers)
return true; return true;
ObjectLock olock(checkers);
Value pattern; Value pattern;
BOOST_FOREACH(tie(tuples::ignore, pattern), checkers) { BOOST_FOREACH(tie(tuples::ignore, pattern), checkers) {
if (Utility::Match(pattern, checker)) if (Utility::Match(pattern, checker))
@ -391,6 +579,9 @@ bool Service::IsAllowedChecker(const String& checker) const
return false; return false;
} }
/**
* @threadsafety Always.
*/
void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (void)>& callback) void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (void)>& callback)
{ {
ObjectLock slock(self); ObjectLock slock(self);
@ -407,16 +598,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 */ /* keep track of scheduling info in case the check type doesn't provide its own information */
Dictionary::Ptr checkInfo = boost::make_shared<Dictionary>(); 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; vector<Dictionary::Ptr> macroDicts;
macroDicts.push_back(self->GetMacros()); macroDicts.push_back(self->GetMacros());
macroDicts.push_back(Service::CalculateDynamicMacros(self)); macroDicts.push_back(self->CalculateDynamicMacros());
Value raw_command = self->GetCheckCommand(); Value raw_command = self->GetCheckCommand();
@ -424,21 +611,13 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
slock.Unlock(); slock.Unlock();
{ macroDicts.push_back(host->GetMacros());
ObjectLock olock(host); macroDicts.push_back(host->CalculateDynamicMacros());
macroDicts.push_back(host->GetMacros());
}
macroDicts.push_back(Host::CalculateDynamicMacros(host));
IcingaApplication::Ptr app = IcingaApplication::GetInstance(); IcingaApplication::Ptr app = IcingaApplication::GetInstance();
macroDicts.push_back(app->GetMacros());
{ macroDicts.push_back(IcingaApplication::CalculateDynamicMacros());
ObjectLock olock(app);
macroDicts.push_back(app->GetMacros());
}
macroDicts.push_back(IcingaApplication::CalculateDynamicMacros(app));
Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts); Dictionary::Ptr macros = MacroProcessor::MergeMacroDicts(macroDicts);
@ -459,9 +638,14 @@ void Service::BeginExecuteCheck(const Service::Ptr& self, const function<void (v
task->Start(boost::bind(&Service::CheckCompletedHandler, self, checkInfo, _1, callback)); task->Start(boost::bind(&Service::CheckCompletedHandler, self, checkInfo, _1, callback));
} }
/**
* @threadsafety Always.
*/
void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo, void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
const ScriptTask::Ptr& task, const function<void (void)>& callback) const ScriptTask::Ptr& task, const function<void (void)>& callback)
{ {
assert(!OwnsLock());
checkInfo->Set("execution_end", Utility::GetTime()); checkInfo->Set("execution_end", Utility::GetTime());
checkInfo->Set("schedule_end", Utility::GetTime()); checkInfo->Set("schedule_end", Utility::GetTime());
checkInfo->Seal(); checkInfo->Seal();
@ -515,47 +699,25 @@ void Service::CheckCompletedHandler(const Dictionary::Ptr& checkInfo,
result->Seal(); result->Seal();
} }
if (result)
ProcessCheckResult(result);
{ {
ObjectLock olock(this); ObjectLock olock(this);
if (result)
ProcessCheckResult(result);
m_CurrentTask.reset(); m_CurrentTask.reset();
/* figure out when the next check is for this service; the call to
* ApplyCheckResult() should've already done this but lets do it again
* just in case there was no check result. */
UpdateNextCheck();
} }
/* figure out when the next check is for this service; the call to
* ApplyCheckResult() should've already done this but lets do it again
* just in case there was no check result. */
UpdateNextCheck();
callback(); callback();
} }
void Service::ProcessCheckResult(const Dictionary::Ptr& cr) /**
{ * @threadsafety Always.
ApplyCheckResult(cr); */
Service::UpdateStatistics(cr);
/* Flush the object so other instances see the service's
* new state when they receive the CheckResult message */
Flush();
RequestMessage rm;
rm.SetMethod("checker::CheckResult");
/* TODO: add _old_ state to message */
CheckResultMessage params;
params.SetService(GetName());
params.SetCheckResult(cr);
rm.SetParams(params);
EndpointManager::Ptr em = EndpointManager::GetInstance();
ObjectLock olock(em);
em->SendMulticastMessage(rm);
}
void Service::UpdateStatistics(const Dictionary::Ptr& cr) void Service::UpdateStatistics(const Dictionary::Ptr& cr)
{ {
time_t ts; time_t ts;
@ -572,15 +734,14 @@ void Service::UpdateStatistics(const Dictionary::Ptr& cr)
CIB::UpdatePassiveChecksStatistics(ts, 1); CIB::UpdatePassiveChecksStatistics(ts, 1);
} }
/**
* @threadsafety Always.
*/
double Service::CalculateExecutionTime(const Dictionary::Ptr& cr) double Service::CalculateExecutionTime(const Dictionary::Ptr& cr)
{ {
ObjectLock olock(cr);
double execution_start = 0, execution_end = 0; double execution_start = 0, execution_end = 0;
if (cr) { if (cr) {
ObjectLock olock(cr);
if (!cr->Contains("execution_start") || !cr->Contains("execution_end")) if (!cr->Contains("execution_start") || !cr->Contains("execution_end"))
return 0; return 0;
@ -591,13 +752,14 @@ double Service::CalculateExecutionTime(const Dictionary::Ptr& cr)
return (execution_end - execution_start); return (execution_end - execution_start);
} }
/**
* @threadsafety Always.
*/
double Service::CalculateLatency(const Dictionary::Ptr& cr) double Service::CalculateLatency(const Dictionary::Ptr& cr)
{ {
double schedule_start = 0, schedule_end = 0; double schedule_start = 0, schedule_end = 0;
if (cr) { if (cr) {
ObjectLock olock(cr);
if (!cr->Contains("schedule_start") || !cr->Contains("schedule_end")) if (!cr->Contains("schedule_start") || !cr->Contains("schedule_end"))
return 0; return 0;

View File

@ -28,16 +28,29 @@ map<String, Service::WeakPtr> Service::m_CommentsCache;
bool Service::m_CommentsCacheValid = true; bool Service::m_CommentsCacheValid = true;
Timer::Ptr Service::m_CommentsExpireTimer; Timer::Ptr Service::m_CommentsExpireTimer;
/**
* @threadsafety Always.
*/
int Service::GetNextCommentID(void) int Service::GetNextCommentID(void)
{ {
boost::mutex::scoped_lock lock(m_CommentMutex);
return m_NextCommentID; return m_NextCommentID;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetComments(void) const Dictionary::Ptr Service::GetComments(void) const
{ {
ObjectLock olock(this);
return m_Comments; return m_Comments;
} }
/**
* @threadsafety Always.
*/
String Service::AddComment(CommentType entryType, const String& author, String Service::AddComment(CommentType entryType, const String& author,
const String& text, double expireTime) const String& text, double expireTime)
{ {
@ -57,7 +70,9 @@ String Service::AddComment(CommentType entryType, const String& author,
comment->Set("legacy_id", legacy_id); comment->Set("legacy_id", legacy_id);
Dictionary::Ptr comments = m_Comments; ObjectLock olock(this);
Dictionary::Ptr comments = GetComments();
if (!comments) if (!comments)
comments = boost::make_shared<Dictionary>(); comments = boost::make_shared<Dictionary>();
@ -71,12 +86,20 @@ String Service::AddComment(CommentType entryType, const String& author,
return id; return id;
} }
/**
* @threadsafety Always.
*/
void Service::RemoveAllComments(void) void Service::RemoveAllComments(void)
{ {
ObjectLock olock(this);
m_Comments = Empty; m_Comments = Empty;
Touch("comments"); Touch("comments");
} }
/**
* @threadsafety Always.
*/
void Service::RemoveComment(const String& id) void Service::RemoveComment(const String& id)
{ {
Service::Ptr owner = GetOwnerByCommentID(id); Service::Ptr owner = GetOwnerByCommentID(id);
@ -84,7 +107,9 @@ void Service::RemoveComment(const String& id)
if (!owner) if (!owner)
return; return;
Dictionary::Ptr comments = owner->m_Comments; ObjectLock olock(owner);
Dictionary::Ptr comments = owner->GetComments();
if (comments) { if (comments) {
comments->Remove(id); comments->Remove(id);
@ -92,6 +117,9 @@ void Service::RemoveComment(const String& id)
} }
} }
/**
* @threadsafety Always.
*/
String Service::GetCommentIDFromLegacyID(int id) String Service::GetCommentIDFromLegacyID(int id)
{ {
boost::mutex::scoped_lock lock(m_CommentMutex); boost::mutex::scoped_lock lock(m_CommentMutex);
@ -104,6 +132,9 @@ String Service::GetCommentIDFromLegacyID(int id)
return it->second; return it->second;
} }
/**
* @threadsafety Always.
*/
Service::Ptr Service::GetOwnerByCommentID(const String& id) Service::Ptr Service::GetOwnerByCommentID(const String& id)
{ {
boost::mutex::scoped_lock lock(m_CommentMutex); boost::mutex::scoped_lock lock(m_CommentMutex);
@ -111,6 +142,9 @@ Service::Ptr Service::GetOwnerByCommentID(const String& id)
return m_CommentsCache[id].lock(); return m_CommentsCache[id].lock();
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetCommentByID(const String& id) Dictionary::Ptr Service::GetCommentByID(const String& id)
{ {
Service::Ptr owner = GetOwnerByCommentID(id); Service::Ptr owner = GetOwnerByCommentID(id);
@ -118,36 +152,40 @@ Dictionary::Ptr Service::GetCommentByID(const String& id)
if (!owner) if (!owner)
return Dictionary::Ptr(); return Dictionary::Ptr();
Dictionary::Ptr comments = owner->m_Comments; Dictionary::Ptr comments = owner->GetComments();
if (comments) { if (comments)
Dictionary::Ptr comment = comments->Get(id); return comments->Get(id);
return comment;
}
return Dictionary::Ptr(); return Dictionary::Ptr();
} }
/**
* @threadsafety Always.
*/
bool Service::IsCommentExpired(const Dictionary::Ptr& comment) bool Service::IsCommentExpired(const Dictionary::Ptr& comment)
{ {
ObjectLock olock(comment);
double expire_time = comment->Get("expire_time"); double expire_time = comment->Get("expire_time");
return (expire_time != 0 && expire_time < Utility::GetTime()); return (expire_time != 0 && expire_time < Utility::GetTime());
} }
/**
* @threadsafety Always.
*/
void Service::InvalidateCommentsCache(void) void Service::InvalidateCommentsCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_CommentMutex);
boost::mutex::scoped_lock lock(m_CommentMutex);
if (m_CommentsCacheValid) if (m_CommentsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshCommentsCache)); Utility::QueueAsyncCallback(boost::bind(&Service::RefreshCommentsCache));
m_CommentsCacheValid = false; m_CommentsCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void Service::RefreshCommentsCache(void) void Service::RefreshCommentsCache(void)
{ {
{ {
@ -214,16 +252,21 @@ void Service::RefreshCommentsCache(void)
} }
} }
/**
* @threadsafety Always.
*/
void Service::RemoveExpiredComments(void) void Service::RemoveExpiredComments(void)
{ {
Dictionary::Ptr comments = m_Comments; ObjectLock olock(this);
Dictionary::Ptr comments = GetComments();
if (!comments) if (!comments)
return; return;
vector<String> expiredComments; vector<String> expiredComments;
ObjectLock olock(comments); ObjectLock dlock(comments);
String id; String id;
Dictionary::Ptr comment; Dictionary::Ptr comment;
@ -241,11 +284,13 @@ void Service::RemoveExpiredComments(void)
} }
} }
/**
* @threadsafety Always.
*/
void Service::CommentsExpireTimerHandler(void) void Service::CommentsExpireTimerHandler(void)
{ {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object); Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock olock(service);
service->RemoveExpiredComments(); service->RemoveExpiredComments();
} }
} }

View File

@ -28,16 +28,27 @@ map<String, Service::WeakPtr> Service::m_DowntimesCache;
bool Service::m_DowntimesCacheValid = true; bool Service::m_DowntimesCacheValid = true;
Timer::Ptr Service::m_DowntimesExpireTimer; Timer::Ptr Service::m_DowntimesExpireTimer;
/**
* @threadsafety Always.
*/
int Service::GetNextDowntimeID(void) int Service::GetNextDowntimeID(void)
{ {
boost::mutex::scoped_lock lock(m_DowntimeMutex);
return m_NextDowntimeID; return m_NextDowntimeID;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetDowntimes(void) const Dictionary::Ptr Service::GetDowntimes(void) const
{ {
return m_Downtimes; return m_Downtimes;
} }
/**
* @threadsafety Always.
*/
String Service::AddDowntime(const String& author, const String& comment, String Service::AddDowntime(const String& author, const String& comment,
double startTime, double endTime, bool fixed, double startTime, double endTime, bool fixed,
const String& triggeredBy, double duration) const String& triggeredBy, double duration)
@ -86,6 +97,9 @@ String Service::AddDowntime(const String& author, const String& comment,
return id; return id;
} }
/**
* @threadsafety Always.
*/
void Service::RemoveDowntime(const String& id) void Service::RemoveDowntime(const String& id)
{ {
Service::Ptr owner = GetOwnerByDowntimeID(id); Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -93,22 +107,23 @@ void Service::RemoveDowntime(const String& id)
if (!owner) if (!owner)
return; return;
Dictionary::Ptr downtimes = owner->m_Downtimes; ObjectLock olock(owner);
Dictionary::Ptr downtimes = owner->GetDowntimes();
if (!downtimes) if (!downtimes)
return; return;
{ downtimes->Remove(id);
ObjectLock olock(downtimes);
downtimes->Remove(id);
}
owner->Touch("downtimes"); owner->Touch("downtimes");
} }
/**
* @threadsafety Always.
*/
void Service::TriggerDowntimes(void) void Service::TriggerDowntimes(void)
{ {
Dictionary::Ptr downtimes = m_Downtimes; Dictionary::Ptr downtimes = GetDowntimes();
if (!downtimes) if (!downtimes)
return; return;
@ -121,6 +136,9 @@ void Service::TriggerDowntimes(void)
} }
} }
/**
* @threadsafety Always.
*/
void Service::TriggerDowntime(const String& id) void Service::TriggerDowntime(const String& id)
{ {
Service::Ptr owner = GetOwnerByDowntimeID(id); Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -150,6 +168,9 @@ void Service::TriggerDowntime(const String& id)
owner->Touch("downtimes"); owner->Touch("downtimes");
} }
/**
* @threadsafety Always.
*/
String Service::GetDowntimeIDFromLegacyID(int id) String Service::GetDowntimeIDFromLegacyID(int id)
{ {
boost::mutex::scoped_lock lock(m_DowntimeMutex); boost::mutex::scoped_lock lock(m_DowntimeMutex);
@ -162,12 +183,18 @@ String Service::GetDowntimeIDFromLegacyID(int id)
return it->second; return it->second;
} }
/**
* @threadsafety Always.
*/
Service::Ptr Service::GetOwnerByDowntimeID(const String& id) Service::Ptr Service::GetOwnerByDowntimeID(const String& id)
{ {
boost::mutex::scoped_lock lock(m_DowntimeMutex); boost::mutex::scoped_lock lock(m_DowntimeMutex);
return m_DowntimesCache[id].lock(); return m_DowntimesCache[id].lock();
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetDowntimeByID(const String& id) Dictionary::Ptr Service::GetDowntimeByID(const String& id)
{ {
Service::Ptr owner = GetOwnerByDowntimeID(id); Service::Ptr owner = GetOwnerByDowntimeID(id);
@ -175,17 +202,17 @@ Dictionary::Ptr Service::GetDowntimeByID(const String& id)
if (!owner) if (!owner)
return Dictionary::Ptr(); return Dictionary::Ptr();
Dictionary::Ptr downtimes = owner->m_Downtimes; Dictionary::Ptr downtimes = owner->GetDowntimes();
if (downtimes) { if (downtimes)
ObjectLock olock(downtimes); return downtimes->Get(id);
Dictionary::Ptr downtime = downtimes->Get(id);
return downtime;
}
return Dictionary::Ptr(); return Dictionary::Ptr();
} }
/**
* @threadsafety Always.
*/
bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime) bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
{ {
double now = Utility::GetTime(); double now = Utility::GetTime();
@ -207,24 +234,30 @@ bool Service::IsDowntimeActive(const Dictionary::Ptr& downtime)
return (triggerTime + downtime->Get("duration") < now); return (triggerTime + downtime->Get("duration") < now);
} }
/**
* @threadsafety Always.
*/
bool Service::IsDowntimeExpired(const Dictionary::Ptr& downtime) bool Service::IsDowntimeExpired(const Dictionary::Ptr& downtime)
{ {
ObjectLock olock(downtime);
return (downtime->Get("end_time") < Utility::GetTime()); return (downtime->Get("end_time") < Utility::GetTime());
} }
/**
* @threadsafety Always.
*/
void Service::InvalidateDowntimesCache(void) void Service::InvalidateDowntimesCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_DowntimeMutex);
boost::mutex::scoped_lock lock(m_DowntimeMutex);
if (m_DowntimesCacheValid) if (m_DowntimesCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshDowntimesCache)); Utility::QueueAsyncCallback(boost::bind(&Service::RefreshDowntimesCache));
m_DowntimesCacheValid = false; m_DowntimesCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void Service::RefreshDowntimesCache(void) void Service::RefreshDowntimesCache(void)
{ {
{ {
@ -289,16 +322,21 @@ void Service::RefreshDowntimesCache(void)
} }
} }
/**
* @threadsafety Always.
*/
void Service::RemoveExpiredDowntimes(void) void Service::RemoveExpiredDowntimes(void)
{ {
Dictionary::Ptr downtimes = m_Downtimes; ObjectLock olock(this);
Dictionary::Ptr downtimes = GetDowntimes();
if (!downtimes) if (!downtimes)
return; return;
vector<String> expiredDowntimes; vector<String> expiredDowntimes;
ObjectLock olock(downtimes); ObjectLock dlock(downtimes);
String id; String id;
Dictionary::Ptr downtime; Dictionary::Ptr downtime;
@ -316,15 +354,20 @@ void Service::RemoveExpiredDowntimes(void)
} }
} }
/**
* @threadsafety Always.
*/
void Service::DowntimesExpireTimerHandler(void) void Service::DowntimesExpireTimerHandler(void)
{ {
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Service")) {
Service::Ptr service = dynamic_pointer_cast<Service>(object); Service::Ptr service = dynamic_pointer_cast<Service>(object);
ObjectLock slock(service);
service->RemoveExpiredDowntimes(); service->RemoveExpiredDowntimes();
} }
} }
/**
* @threadsafety Always.
*/
bool Service::IsInDowntime(void) const bool Service::IsInDowntime(void) const
{ {
Dictionary::Ptr downtimes = GetDowntimes(); Dictionary::Ptr downtimes = GetDowntimes();

View File

@ -25,8 +25,13 @@ boost::mutex Service::m_NotificationMutex;
map<String, set<Notification::WeakPtr> > Service::m_NotificationsCache; map<String, set<Notification::WeakPtr> > Service::m_NotificationsCache;
bool Service::m_NotificationsCacheValid = true; bool Service::m_NotificationsCacheValid = true;
/**
* @threadsafety Always.
*/
void Service::RequestNotifications(NotificationType type) void Service::RequestNotifications(NotificationType type)
{ {
SetLastNotification(Utility::GetTime());
RequestMessage msg; RequestMessage msg;
msg.SetMethod("icinga::SendNotifications"); msg.SetMethod("icinga::SendNotifications");
@ -38,40 +43,32 @@ void Service::RequestNotifications(NotificationType type)
Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'"); Logger::Write(LogDebug, "icinga", "Sending notification anycast request for service '" + GetName() + "'");
EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg); EndpointManager::GetInstance()->SendAnycastMessage(Endpoint::Ptr(), msg);
SetLastNotification(Utility::GetTime());
} }
void Service::SendNotifications(const Service::Ptr& self, NotificationType type) /**
* @threadsafety Always.
*/
void Service::SendNotifications(NotificationType type)
{ {
String service_name; if (!GetEnableNotifications()) {
bool enable_notifications; Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + GetName() + "'.");
{
ObjectLock olock(self);
service_name = self->GetName();
enable_notifications = self->GetEnableNotifications();
}
if (!enable_notifications) {
Logger::Write(LogInformation, "icinga", "Notifications are disabled for service '" + service_name + "'.");
return; return;
} }
Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + service_name + "'"); Logger::Write(LogInformation, "icinga", "Sending notifications for service '" + GetName() + "'");
set<Notification::Ptr> notifications = GetNotifications(self); set<Notification::Ptr> notifications = GetNotifications();
if (notifications.size() == 0) if (notifications.size() == 0)
Logger::Write(LogInformation, "icinga", "Service '" + service_name + "' does not have any notifications."); Logger::Write(LogInformation, "icinga", "Service '" + GetName() + "' does not have any notifications.");
BOOST_FOREACH(const Notification::Ptr& notification, notifications) { BOOST_FOREACH(const Notification::Ptr& notification, notifications) {
try { try {
Notification::BeginExecuteNotification(notification, type); notification->BeginExecuteNotification(type);
} catch (const exception& ex) { } catch (const exception& ex) {
stringstream msgbuf; stringstream msgbuf;
msgbuf << "Exception occured during notification for service '" msgbuf << "Exception occured during notification for service '"
<< service_name << "': " << diagnostic_information(ex); << GetName() << "': " << diagnostic_information(ex);
String message = msgbuf.str(); String message = msgbuf.str();
Logger::Write(LogWarning, "icinga", message); Logger::Write(LogWarning, "icinga", message);
@ -79,18 +76,22 @@ void Service::SendNotifications(const Service::Ptr& self, NotificationType type)
} }
} }
/**
* @threadsafety Always.
*/
void Service::InvalidateNotificationsCache(void) void Service::InvalidateNotificationsCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_NotificationMutex);
boost::mutex::scoped_lock lock(m_NotificationMutex);
if (m_NotificationsCacheValid) if (m_NotificationsCacheValid)
Utility::QueueAsyncCallback(boost::bind(&Service::RefreshNotificationsCache)); Utility::QueueAsyncCallback(boost::bind(&Service::RefreshNotificationsCache));
m_NotificationsCacheValid = false; m_NotificationsCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void Service::RefreshNotificationsCache(void) void Service::RefreshNotificationsCache(void)
{ {
{ {
@ -107,42 +108,29 @@ void Service::RefreshNotificationsCache(void)
BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) { BOOST_FOREACH(const DynamicObject::Ptr& object, DynamicType::GetObjects("Notification")) {
const Notification::Ptr& notification = static_pointer_cast<Notification>(object); const Notification::Ptr& notification = static_pointer_cast<Notification>(object);
Service::Ptr service; Service::Ptr service = notification->GetService();
{ if (!service)
ObjectLock olock(notification); continue;
service = notification->GetService();
}
String service_name; newNotificationsCache[service->GetName()].insert(notification);
{
ObjectLock olock(service);
service_name = service->GetName();
}
newNotificationsCache[service_name].insert(notification);
} }
boost::mutex::scoped_lock lock(m_NotificationMutex); boost::mutex::scoped_lock lock(m_NotificationMutex);
m_NotificationsCache.swap(newNotificationsCache); m_NotificationsCache.swap(newNotificationsCache);
} }
set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self) /**
* @threadsafety Always.
*/
set<Notification::Ptr> Service::GetNotifications(void) const
{ {
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Notification::Ptr> notifications; set<Notification::Ptr> notifications;
{ {
boost::mutex::scoped_lock lock(m_NotificationMutex); boost::mutex::scoped_lock lock(m_NotificationMutex);
BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[name]) { BOOST_FOREACH(const Notification::WeakPtr& wservice, m_NotificationsCache[GetName()]) {
Notification::Ptr notification = wservice.lock(); Notification::Ptr notification = wservice.lock();
if (!notification) if (!notification)
@ -155,6 +143,9 @@ set<Notification::Ptr> Service::GetNotifications(const Service::Ptr& self)
return notifications; return notifications;
} }
/**
* @threadsafety Always.
*/
template<typename TDict> template<typename TDict>
static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemBuilder::Ptr& builder) static void CopyNotificationAttributes(TDict notificationDesc, const ConfigItemBuilder::Ptr& builder)
{ {
@ -276,7 +267,7 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
} }
ConfigItem::Ptr notificationItem = builder->Compile(); ConfigItem::Ptr notificationItem = builder->Compile();
ConfigItem::Commit(notificationItem); notificationItem->Commit();
newNotifications->Set(name, notificationItem); newNotifications->Set(name, notificationItem);
} }
@ -301,36 +292,61 @@ void Service::UpdateSlaveNotifications(const Service::Ptr& self)
} }
} }
/**
* @threadsafety Always.
*/
double Service::GetLastNotification(void) const double Service::GetLastNotification(void) const
{ {
ObjectLock olock(this);
if (m_LastNotification.IsEmpty()) if (m_LastNotification.IsEmpty())
return 0; return 0;
else else
return m_LastNotification; return m_LastNotification;
} }
/**
* @threadsafety Always.
*/
void Service::SetLastNotification(double time) void Service::SetLastNotification(double time)
{ {
ObjectLock olock(this);
m_LastNotification = time; m_LastNotification = time;
Touch("last_notification"); Touch("last_notification");
} }
/**
* @threadsafety Always.
*/
bool Service::GetEnableNotifications(void) const bool Service::GetEnableNotifications(void) const
{ {
ObjectLock olock(this);
if (m_EnableNotifications.IsEmpty()) if (m_EnableNotifications.IsEmpty())
return true; return true;
else else
return m_EnableNotifications; return m_EnableNotifications;
} }
/**
* @threadsafety Always.
*/
void Service::SetEnableNotifications(bool enabled) void Service::SetEnableNotifications(bool enabled)
{ {
ObjectLock olock(this);
m_EnableNotifications = enabled; m_EnableNotifications = enabled;
Touch("enable_notifications"); Touch("enable_notifications");
} }
/**
* @threadsafety Always.
*/
double Service::GetNotificationInterval(void) const double Service::GetNotificationInterval(void) const
{ {
ObjectLock olock(this);
if (m_NotificationInterval.IsEmpty()) if (m_NotificationInterval.IsEmpty())
return 300; return 300;
else else

View File

@ -76,13 +76,25 @@ Service::~Service(void)
Service::InvalidateCommentsCache(); Service::InvalidateCommentsCache();
} }
/**
* @threadsafety Always.
*/
void Service::OnRegistrationCompleted(void) void Service::OnRegistrationCompleted(void)
{ {
assert(!OwnsLock());
DynamicObject::OnRegistrationCompleted(); DynamicObject::OnRegistrationCompleted();
InvalidateNotificationsCache();
} }
/**
* @threadsafety Always.
*/
String Service::GetDisplayName(void) const String Service::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (m_DisplayName.IsEmpty()) if (m_DisplayName.IsEmpty())
return GetShortName(); return GetShortName();
else else
@ -113,66 +125,99 @@ Service::Ptr Service::GetByNamePair(const String& hostName, const String& servic
if (!host) if (!host)
return Service::Ptr(); return Service::Ptr();
return Host::GetServiceByShortName(host, serviceName); return host->GetServiceByShortName(serviceName);
} else { } else {
return Service::GetByName(serviceName); return Service::GetByName(serviceName);
} }
} }
/**
* @threadsafety Always.
*/
Host::Ptr Service::GetHost(void) const Host::Ptr Service::GetHost(void) const
{ {
ObjectLock olock(this);
return Host::GetByName(m_HostName); return Host::GetByName(m_HostName);
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetMacros(void) const Dictionary::Ptr Service::GetMacros(void) const
{ {
ObjectLock olock(this);
return m_Macros; return m_Macros;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetHostDependencies(void) const Dictionary::Ptr Service::GetHostDependencies(void) const
{ {
ObjectLock olock(this);
return m_HostDependencies; return m_HostDependencies;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetServiceDependencies(void) const Dictionary::Ptr Service::GetServiceDependencies(void) const
{ {
ObjectLock olock(this);
return m_ServiceDependencies; return m_ServiceDependencies;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr Service::GetGroups(void) const Dictionary::Ptr Service::GetGroups(void) const
{ {
ObjectLock olock(this);
return m_ServiceGroups; return m_ServiceGroups;
} }
/**
* @threadsafety Always.
*/
String Service::GetHostName(void) const String Service::GetHostName(void) const
{ {
ObjectLock olock(this);
return m_HostName; return m_HostName;
} }
/**
* @threadsafety Always.
*/
String Service::GetShortName(void) const String Service::GetShortName(void) const
{ {
ObjectLock olock(this);
if (m_ShortName.IsEmpty()) if (m_ShortName.IsEmpty())
return GetName(); return GetName();
else else
return m_ShortName; return m_ShortName;
} }
bool Service::IsReachable(const Service::Ptr& self) /**
* @threadsafety Always.
*/
bool Service::IsReachable(void) const
{ {
String service_name; assert(!OwnsLock());
{
ObjectLock olock(self);
service_name = self->GetName();
}
BOOST_FOREACH(const Service::Ptr& service, Service::GetParentServices(self)) {
ObjectLock olock(service);
BOOST_FOREACH(const Service::Ptr& service, GetParentServices()) {
/* ignore ourselves */ /* ignore ourselves */
if (service->GetName() == service_name) if (service->GetName() == GetName())
continue; continue;
ObjectLock olock(service);
/* ignore pending services */ /* ignore pending services */
if (!service->GetLastCheckResult()) if (!service->GetLastCheckResult())
continue; continue;
@ -189,21 +234,25 @@ bool Service::IsReachable(const Service::Ptr& self)
return false; return false;
} }
BOOST_FOREACH(const Host::Ptr& host, Service::GetParentHosts(self)) { BOOST_FOREACH(const Host::Ptr& host, GetParentHosts()) {
Service::Ptr hc = Host::GetHostCheckService(host); Service::Ptr hc = host->GetHostCheckService();
/* ignore hosts that don't have a hostcheck */ /* ignore hosts that don't have a hostcheck */
if (!hc) if (!hc)
continue; continue;
/* ignore ourselves */
if (hc->GetName() == GetName())
continue;
ObjectLock olock(hc); ObjectLock olock(hc);
/* ignore ourselves */ /* ignore soft states */
if (hc->GetName() == service_name) if (hc->GetStateType() == StateTypeSoft)
continue; continue;
/* ignore hosts that are up */ /* ignore hosts that are up */
if (hc && hc->GetState() == StateOK) if (hc->GetState() == StateOK)
continue; continue;
return false; return false;
@ -212,8 +261,13 @@ bool Service::IsReachable(const Service::Ptr& self)
return true; return true;
} }
/**
* @threadsafety Always.
*/
AcknowledgementType Service::GetAcknowledgement(void) AcknowledgementType Service::GetAcknowledgement(void)
{ {
ObjectLock olock(this);
if (m_Acknowledgement.IsEmpty()) if (m_Acknowledgement.IsEmpty())
return AcknowledgementNone; return AcknowledgementNone;
@ -233,47 +287,78 @@ AcknowledgementType Service::GetAcknowledgement(void)
return avalue; return avalue;
} }
/**
* @threadsafety Always.
*/
void Service::SetAcknowledgement(AcknowledgementType acknowledgement) void Service::SetAcknowledgement(AcknowledgementType acknowledgement)
{ {
ObjectLock olock(this);
m_Acknowledgement = acknowledgement; m_Acknowledgement = acknowledgement;
Touch("acknowledgement"); Touch("acknowledgement");
} }
/**
* @threadsafety Always.
*/
bool Service::IsAcknowledged(void) bool Service::IsAcknowledged(void)
{ {
return GetAcknowledgement() != AcknowledgementNone; return GetAcknowledgement() != AcknowledgementNone;
} }
/**
* @threadsafety Always.
*/
double Service::GetAcknowledgementExpiry(void) const double Service::GetAcknowledgementExpiry(void) const
{ {
ObjectLock olock(this);
if (m_AcknowledgementExpiry.IsEmpty()) if (m_AcknowledgementExpiry.IsEmpty())
return 0; return 0;
return static_cast<double>(m_AcknowledgementExpiry); return static_cast<double>(m_AcknowledgementExpiry);
} }
/**
* @threadsafety Always.
*/
void Service::SetAcknowledgementExpiry(double timestamp) void Service::SetAcknowledgementExpiry(double timestamp)
{ {
ObjectLock olock(this);
m_AcknowledgementExpiry = timestamp; m_AcknowledgementExpiry = timestamp;
Touch("acknowledgement_expiry"); Touch("acknowledgement_expiry");
} }
/**
* @threadsafety Always.
*/
void Service::AcknowledgeProblem(AcknowledgementType type, double expiry) void Service::AcknowledgeProblem(AcknowledgementType type, double expiry)
{ {
ObjectLock olock(this);
SetAcknowledgement(type); SetAcknowledgement(type);
SetAcknowledgementExpiry(expiry); SetAcknowledgementExpiry(expiry);
RequestNotifications(NotificationAcknowledgement); RequestNotifications(NotificationAcknowledgement);
} }
/**
* @threadsafety Always.
*/
void Service::ClearAcknowledgement(void) void Service::ClearAcknowledgement(void)
{ {
SetAcknowledgement(AcknowledgementNone); SetAcknowledgement(AcknowledgementNone);
SetAcknowledgementExpiry(0); SetAcknowledgementExpiry(0);
} }
/**
* @threadsafety Always.
*/
void Service::OnAttributeChanged(const String& name, const Value& oldValue) void Service::OnAttributeChanged(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
Service::Ptr self; Service::Ptr self;
String service_name; String service_name;
bool abstract; bool abstract;
@ -311,23 +396,24 @@ void Service::OnAttributeChanged(const String& name, const Value& oldValue)
} }
} }
set<Host::Ptr> Service::GetParentHosts(const Service::Ptr& self) /**
* @threadsafety Always.
*/
set<Host::Ptr> Service::GetParentHosts(void) const
{ {
set<Host::Ptr> parents; set<Host::Ptr> parents;
Dictionary::Ptr dependencies; Host::Ptr host = GetHost();
{ /* The service's host is implicitly a parent. */
ObjectLock olock(self); if (host)
parents.insert(host);
/* The service's host is implicitly a parent. */
parents.insert(self->GetHost());
dependencies = self->GetHostDependencies();
}
Dictionary::Ptr dependencies = GetHostDependencies();
if (dependencies) { if (dependencies) {
ObjectLock olock(dependencies);
String key; String key;
BOOST_FOREACH(tie(key, tuples::ignore), dependencies) { BOOST_FOREACH(tie(key, tuples::ignore), dependencies) {
Host::Ptr host = Host::GetByName(key); Host::Ptr host = Host::GetByName(key);
@ -342,29 +428,26 @@ set<Host::Ptr> Service::GetParentHosts(const Service::Ptr& self)
return parents; return parents;
} }
set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self) /**
* @threadsafety Always.
*/
set<Service::Ptr> Service::GetParentServices(void) const
{ {
set<Service::Ptr> parents; set<Service::Ptr> parents;
Dictionary::Ptr dependencies; Host::Ptr host = GetHost();
Host::Ptr host; Dictionary::Ptr dependencies = GetServiceDependencies();
String service_name;
{ if (host && dependencies) {
ObjectLock olock(self);
dependencies = self->GetServiceDependencies();
host = self->GetHost();
service_name = self->GetName();
}
if (dependencies) {
String key; String key;
Value value; Value value;
BOOST_FOREACH(tie(key, value), dependencies) { BOOST_FOREACH(tie(key, value), dependencies) {
Service::Ptr service = Host::GetServiceByShortName(host, value); Service::Ptr service = host->GetServiceByShortName(value);
ObjectLock olock(service);
if (service->GetName() == service_name) if (!service)
continue;
if (service->GetName() == GetName())
continue; continue;
parents.insert(service); parents.insert(service);
@ -374,25 +457,27 @@ set<Service::Ptr> Service::GetParentServices(const Service::Ptr& self)
return parents; return parents;
} }
Dictionary::Ptr Service::CalculateDynamicMacros(const Service::Ptr& self) /**
* @threadsafety Always.
*/
Dictionary::Ptr Service::CalculateDynamicMacros(void) const
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); Dictionary::Ptr macros = boost::make_shared<Dictionary>();
ObjectLock mlock(macros);
Dictionary::Ptr cr; Dictionary::Ptr cr;
{ {
ObjectLock olock(self); ObjectLock olock(this);
macros->Set("SERVICEDESC", self->GetShortName()); macros->Set("SERVICEDESC", GetShortName());
macros->Set("SERVICEDISPLAYNAME", self->GetDisplayName()); macros->Set("SERVICEDISPLAYNAME", GetDisplayName());
macros->Set("SERVICESTATE", StateToString(self->GetState())); macros->Set("SERVICESTATE", StateToString(GetState()));
macros->Set("SERVICESTATEID", self->GetState()); macros->Set("SERVICESTATEID", GetState());
macros->Set("SERVICESTATETYPE", StateTypeToString(self->GetStateType())); macros->Set("SERVICESTATETYPE", StateTypeToString(GetStateType()));
macros->Set("SERVICEATTEMPT", self->GetCurrentCheckAttempt()); macros->Set("SERVICEATTEMPT", GetCurrentCheckAttempt());
macros->Set("MAXSERVICEATTEMPT", self->GetMaxCheckAttempts()); macros->Set("MAXSERVICEATTEMPT", GetMaxCheckAttempts());
macros->Set("SERVICECHECKCOMMAND", "check_i2"); macros->Set("SERVICECHECKCOMMAND", "check_i2");
cr = self->GetLastCheckResult(); cr = GetLastCheckResult();
} }
if (cr) { if (cr) {

View File

@ -106,12 +106,12 @@ public:
String GetHostName(void) const; String GetHostName(void) const;
String GetShortName(void) const; String GetShortName(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const Service::Ptr& self); Dictionary::Ptr CalculateDynamicMacros(void) const;
static set<Host::Ptr> GetParentHosts(const Service::Ptr& self); set<Host::Ptr> GetParentHosts(void) const;
static set<Service::Ptr> GetParentServices(const Service::Ptr& self); set<Service::Ptr> GetParentServices(void) const;
static bool IsReachable(const Service::Ptr& self); bool IsReachable(void) const;
AcknowledgementType GetAcknowledgement(void); AcknowledgementType GetAcknowledgement(void);
void SetAcknowledgement(AcknowledgementType acknowledgement); void SetAcknowledgement(AcknowledgementType acknowledgement);
@ -165,7 +165,6 @@ public:
double GetAcknowledgementExpiry(void) const; double GetAcknowledgementExpiry(void) const;
void SetAcknowledgementExpiry(double timestamp); void SetAcknowledgementExpiry(double timestamp);
void ApplyCheckResult(const Dictionary::Ptr& cr);
static void UpdateStatistics(const Dictionary::Ptr& cr); static void UpdateStatistics(const Dictionary::Ptr& cr);
void AcknowledgeProblem(AcknowledgementType type, double expiry = 0); void AcknowledgeProblem(AcknowledgementType type, double expiry = 0);
@ -238,9 +237,9 @@ public:
double GetNotificationInterval(void) const; double GetNotificationInterval(void) const;
void RequestNotifications(NotificationType type); void RequestNotifications(NotificationType type);
static void SendNotifications(const Service::Ptr& self, NotificationType type); void SendNotifications(NotificationType type);
static set<Notification::Ptr> GetNotifications(const Service::Ptr& self); set<Notification::Ptr> GetNotifications(void) const;
static void InvalidateNotificationsCache(void); static void InvalidateNotificationsCache(void);

View File

@ -37,29 +37,49 @@ ServiceGroup::ServiceGroup(const Dictionary::Ptr& properties)
ServiceGroup::~ServiceGroup(void) ServiceGroup::~ServiceGroup(void)
{ {
RefreshMembersCache(); InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
void ServiceGroup::OnRegistrationCompleted(void) void ServiceGroup::OnRegistrationCompleted(void)
{ {
RefreshMembersCache(); assert(!OwnsLock());
InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
String ServiceGroup::GetDisplayName(void) const String ServiceGroup::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (!m_DisplayName.Get().IsEmpty()) if (!m_DisplayName.Get().IsEmpty())
return m_DisplayName; return m_DisplayName;
else else
return GetName(); return GetName();
} }
/**
* @threadsafety Always.
*/
String ServiceGroup::GetNotesUrl(void) const String ServiceGroup::GetNotesUrl(void) const
{ {
ObjectLock olock(this);
return m_NotesUrl; return m_NotesUrl;
} }
/**
* @threadsafety Always.
*/
String ServiceGroup::GetActionUrl(void) const String ServiceGroup::GetActionUrl(void) const
{ {
ObjectLock olock(this);
return m_ActionUrl; return m_ActionUrl;
} }
@ -76,21 +96,17 @@ ServiceGroup::Ptr ServiceGroup::GetByName(const String& name)
return dynamic_pointer_cast<ServiceGroup>(configObject); return dynamic_pointer_cast<ServiceGroup>(configObject);
} }
set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self) /**
* @threadsafety Always.
*/
set<Service::Ptr> ServiceGroup::GetMembers(void) const
{ {
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<Service::Ptr> services; set<Service::Ptr> services;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const Service::WeakPtr& wservice, m_MembersCache[name]) { BOOST_FOREACH(const Service::WeakPtr& wservice, m_MembersCache[GetName()]) {
Service::Ptr service = wservice.lock(); Service::Ptr service = wservice.lock();
if (!service) if (!service)
@ -103,18 +119,22 @@ set<Service::Ptr> ServiceGroup::GetMembers(const ServiceGroup::Ptr& self)
return services; return services;
} }
/**
* @threadsafety Always.
*/
void ServiceGroup::InvalidateMembersCache(void) void ServiceGroup::InvalidateMembersCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid) if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&ServiceGroup::RefreshMembersCache)); Utility::QueueAsyncCallback(boost::bind(&ServiceGroup::RefreshMembersCache));
m_MembersCacheValid = false; m_MembersCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void ServiceGroup::RefreshMembersCache(void) void ServiceGroup::RefreshMembersCache(void)
{ {
{ {

View File

@ -43,7 +43,7 @@ public:
String GetNotesUrl(void) const; String GetNotesUrl(void) const;
String GetActionUrl(void) const; String GetActionUrl(void) const;
static set<Service::Ptr> GetMembers(const ServiceGroup::Ptr& self); set<Service::Ptr> GetMembers(void) const;
static void InvalidateMembersCache(void); static void InvalidateMembersCache(void);

View File

@ -36,12 +36,20 @@ User::~User(void)
UserGroup::InvalidateMembersCache(); UserGroup::InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
void User::OnAttributeChanged(const String& name, const Value& oldValue) void User::OnAttributeChanged(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
if (name == "groups") if (name == "groups")
UserGroup::InvalidateMembersCache(); UserGroup::InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
User::Ptr User::GetByName(const String& name) User::Ptr User::GetByName(const String& name)
{ {
DynamicObject::Ptr configObject = DynamicObject::GetObject("User", name); DynamicObject::Ptr configObject = DynamicObject::GetObject("User", name);
@ -49,33 +57,48 @@ User::Ptr User::GetByName(const String& name)
return dynamic_pointer_cast<User>(configObject); return dynamic_pointer_cast<User>(configObject);
} }
/**
* @threadsafety Always.
*/
String User::GetDisplayName(void) const String User::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty()) if (!m_DisplayName.IsEmpty())
return m_DisplayName; return m_DisplayName;
else else
return GetName(); return GetName();
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr User::GetGroups(void) const Dictionary::Ptr User::GetGroups(void) const
{ {
ObjectLock olock(this);
return m_Groups; return m_Groups;
} }
/**
* @threadsafety Always.
*/
Dictionary::Ptr User::GetMacros(void) const Dictionary::Ptr User::GetMacros(void) const
{ {
ObjectLock olock(this);
return m_Macros; return m_Macros;
} }
Dictionary::Ptr User::CalculateDynamicMacros(const User::Ptr& self) /**
* @threadsafety Always.
*/
Dictionary::Ptr User::CalculateDynamicMacros(void) const
{ {
Dictionary::Ptr macros = boost::make_shared<Dictionary>(); Dictionary::Ptr macros = boost::make_shared<Dictionary>();
{ macros->Set("CONTACTNAME", GetName());
ObjectLock olock(self); macros->Set("CONTACTALIAS", GetName());
macros->Set("CONTACTNAME", self->GetName());
macros->Set("CONTACTALIAS", self->GetName());
}
macros->Seal(); macros->Seal();

View File

@ -43,7 +43,7 @@ public:
Dictionary::Ptr GetGroups(void) const; Dictionary::Ptr GetGroups(void) const;
Dictionary::Ptr GetMacros(void) const; Dictionary::Ptr GetMacros(void) const;
static Dictionary::Ptr CalculateDynamicMacros(const User::Ptr& self); Dictionary::Ptr CalculateDynamicMacros(void) const;
protected: protected:
void OnAttributeChanged(const String& name, const Value& oldValue); void OnAttributeChanged(const String& name, const Value& oldValue);

View File

@ -38,13 +38,23 @@ UserGroup::~UserGroup(void)
InvalidateMembersCache(); InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
void UserGroup::OnRegistrationCompleted(void) void UserGroup::OnRegistrationCompleted(void)
{ {
assert(!OwnsLock());
InvalidateMembersCache(); InvalidateMembersCache();
} }
/**
* @threadsafety Always.
*/
String UserGroup::GetDisplayName(void) const String UserGroup::GetDisplayName(void) const
{ {
ObjectLock olock(this);
if (!m_DisplayName.IsEmpty()) if (!m_DisplayName.IsEmpty())
return m_DisplayName; return m_DisplayName;
else else
@ -64,21 +74,17 @@ UserGroup::Ptr UserGroup::GetByName(const String& name)
return dynamic_pointer_cast<UserGroup>(configObject); return dynamic_pointer_cast<UserGroup>(configObject);
} }
set<User::Ptr> UserGroup::GetMembers(const UserGroup::Ptr& self) /**
* @threadsafety Always.
*/
set<User::Ptr> UserGroup::GetMembers(void) const
{ {
String name;
{
ObjectLock olock(self);
name = self->GetName();
}
set<User::Ptr> users; set<User::Ptr> users;
{ {
boost::mutex::scoped_lock lock(m_Mutex); boost::mutex::scoped_lock lock(m_Mutex);
BOOST_FOREACH(const User::WeakPtr& wuser, m_MembersCache[name]) { BOOST_FOREACH(const User::WeakPtr& wuser, m_MembersCache[GetName()]) {
User::Ptr user = wuser.lock(); User::Ptr user = wuser.lock();
if (!user) if (!user)
@ -91,18 +97,22 @@ set<User::Ptr> UserGroup::GetMembers(const UserGroup::Ptr& self)
return users; return users;
} }
/**
* @threadsafety Always.
*/
void UserGroup::InvalidateMembersCache(void) void UserGroup::InvalidateMembersCache(void)
{ {
{ boost::mutex::scoped_lock lock(m_Mutex);
boost::mutex::scoped_lock lock(m_Mutex);
if (m_MembersCacheValid) if (m_MembersCacheValid)
Utility::QueueAsyncCallback(boost::bind(&UserGroup::RefreshMembersCache)); Utility::QueueAsyncCallback(boost::bind(&UserGroup::RefreshMembersCache));
m_MembersCacheValid = false; m_MembersCacheValid = false;
}
} }
/**
* @threadsafety Always.
*/
void UserGroup::RefreshMembersCache(void) void UserGroup::RefreshMembersCache(void)
{ {
{ {

View File

@ -41,7 +41,7 @@ public:
String GetDisplayName(void) const; String GetDisplayName(void) const;
static set<User::Ptr> GetMembers(const UserGroup::Ptr& self); set<User::Ptr> GetMembers(void) const;
static void InvalidateMembersCache(void); static void InvalidateMembersCache(void);

View File

@ -54,6 +54,8 @@ PythonInterpreter::~PythonInterpreter(void)
void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *function) void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *function)
{ {
ObjectLock olock(this);
SubscribeFunction(name); SubscribeFunction(name);
Py_INCREF(function); Py_INCREF(function);
@ -62,6 +64,8 @@ void PythonInterpreter::RegisterPythonFunction(const String& name, PyObject *fun
void PythonInterpreter::UnregisterPythonFunction(const String& name) void PythonInterpreter::UnregisterPythonFunction(const String& name)
{ {
ObjectLock olock(this);
UnsubscribeFunction(name); UnsubscribeFunction(name);
m_Functions.erase(name); m_Functions.erase(name);
@ -70,6 +74,8 @@ void PythonInterpreter::UnregisterPythonFunction(const String& name)
void PythonInterpreter::ProcessCall(const ScriptTask::Ptr& task, const String& function, void PythonInterpreter::ProcessCall(const ScriptTask::Ptr& task, const String& function,
const vector<Value>& arguments) const vector<Value>& arguments)
{ {
ObjectLock olock(this);
PyEval_AcquireThread(m_ThreadState); PyEval_AcquireThread(m_ThreadState);
PythonInterpreter *interp = m_Language->GetCurrentInterpreter(); PythonInterpreter *interp = m_Language->GetCurrentInterpreter();
m_Language->SetCurrentInterpreter(this); m_Language->SetCurrentInterpreter(this);

View File

@ -36,6 +36,8 @@ PythonLanguage::PythonLanguage(void)
void PythonLanguage::InitializeOnce(void) void PythonLanguage::InitializeOnce(void)
{ {
ObjectLock olock(this);
if (m_Initialized) if (m_Initialized)
return; return;
@ -85,6 +87,8 @@ ScriptInterpreter::Ptr PythonLanguage::CreateInterpreter(const Script::Ptr& scri
PyThreadState *PythonLanguage::GetMainThreadState(void) const PyThreadState *PythonLanguage::GetMainThreadState(void) const
{ {
ObjectLock olock(this);
return m_MainThreadState; return m_MainThreadState;
} }
@ -139,6 +143,8 @@ PyObject *PythonLanguage::MarshalToPython(const Value& value)
return result; return result;
} else if (value.IsObjectType<Dictionary>()) { } else if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value; Dictionary::Ptr dict = value;
ObjectLock olock(dict);
PyObject *pdict = PyDict_New(); PyObject *pdict = PyDict_New();
String key; String key;
@ -214,6 +220,8 @@ Value PythonLanguage::MarshalFromPython(PyObject *value)
String PythonLanguage::ExceptionInfoToString(PyObject *type, PyObject *exc, PyObject *tb) const String PythonLanguage::ExceptionInfoToString(PyObject *type, PyObject *exc, PyObject *tb) const
{ {
ObjectLock olock(this);
PyObject *tb_dict = PyModule_GetDict(m_TracebackModule); PyObject *tb_dict = PyModule_GetDict(m_TracebackModule);
PyObject *format_exception = PyDict_GetItemString(tb_dict, "format_exception"); PyObject *format_exception = PyDict_GetItemString(tb_dict, "format_exception");
@ -304,6 +312,8 @@ PyObject *PythonLanguage::PyCallNativeFunction(PyObject *self, PyObject *args)
*/ */
void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunction::Ptr& function) void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunction::Ptr& function)
{ {
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState); PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pname = PyString_FromString(name.CStr()); PyObject *pname = PyString_FromString(name.CStr());
@ -327,6 +337,8 @@ void PythonLanguage::RegisterNativeFunction(const String& name, const ScriptFunc
*/ */
void PythonLanguage::UnregisterNativeFunction(const String& name) void PythonLanguage::UnregisterNativeFunction(const String& name)
{ {
ObjectLock olock(this);
PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState); PyThreadState *tstate = PyThreadState_Swap(m_MainThreadState);
PyObject *pdict = PyModule_GetDict(m_NativeModule); PyObject *pdict = PyModule_GetDict(m_NativeModule);
@ -378,6 +390,8 @@ PyObject *PythonLanguage::PyRegisterFunction(PyObject *self, PyObject *args)
*/ */
PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void) PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void)
{ {
ObjectLock olock(this);
return m_CurrentInterpreter; return m_CurrentInterpreter;
} }
@ -388,5 +402,7 @@ PythonInterpreter *PythonLanguage::GetCurrentInterpreter(void)
*/ */
void PythonLanguage::SetCurrentInterpreter(PythonInterpreter *interpreter) void PythonLanguage::SetCurrentInterpreter(PythonInterpreter *interpreter)
{ {
ObjectLock olock(this);
m_CurrentInterpreter = interpreter; m_CurrentInterpreter = interpreter;
} }

View File

@ -72,7 +72,8 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
endpointConfig->SetLocal(!replicated); endpointConfig->SetLocal(!replicated);
endpointConfig->AddExpression("local", OperatorSet, local); endpointConfig->AddExpression("local", OperatorSet, local);
DynamicObject::Ptr object = ConfigItem::Commit(endpointConfig->Compile()); ConfigItem::Ptr item = endpointConfig->Compile();
DynamicObject::Ptr object = item->Commit();
return dynamic_pointer_cast<Endpoint>(object); return dynamic_pointer_cast<Endpoint>(object);
} }
@ -83,6 +84,8 @@ Endpoint::Ptr Endpoint::MakeEndpoint(const String& name, bool replicated, bool l
*/ */
bool Endpoint::IsLocalEndpoint(void) const bool Endpoint::IsLocalEndpoint(void) const
{ {
ObjectLock olock(this);
return m_Local; return m_Local;
} }
@ -104,15 +107,22 @@ bool Endpoint::IsConnected(void) const
JsonRpcConnection::Ptr Endpoint::GetClient(void) const JsonRpcConnection::Ptr Endpoint::GetClient(void) const
{ {
ObjectLock olock(this);
return m_Client; return m_Client;
} }
void Endpoint::SetClient(const JsonRpcConnection::Ptr& client) void Endpoint::SetClient(const JsonRpcConnection::Ptr& client)
{ {
m_Client = client;
client->OnNewMessage.connect(boost::bind(&Endpoint::NewMessageHandler, this, _2)); client->OnNewMessage.connect(boost::bind(&Endpoint::NewMessageHandler, this, _2));
client->OnClosed.connect(boost::bind(&Endpoint::ClientClosedHandler, this)); client->OnClosed.connect(boost::bind(&Endpoint::ClientClosedHandler, this));
{
ObjectLock olock(this);
m_Client = client;
}
OnConnected(GetSelf()); OnConnected(GetSelf());
} }
@ -128,11 +138,8 @@ void Endpoint::RegisterSubscription(const String& topic)
if (!subscriptions) if (!subscriptions)
subscriptions = boost::make_shared<Dictionary>(); subscriptions = boost::make_shared<Dictionary>();
ObjectLock olock(subscriptions);
if (!subscriptions->Contains(topic)) { if (!subscriptions->Contains(topic)) {
Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone(); Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
ObjectLock nlock(newSubscriptions);
newSubscriptions->Set(topic, topic); newSubscriptions->Set(topic, topic);
SetSubscriptions(newSubscriptions); SetSubscriptions(newSubscriptions);
} }
@ -150,11 +157,8 @@ void Endpoint::UnregisterSubscription(const String& topic)
if (!subscriptions) if (!subscriptions)
return; return;
ObjectLock olock(subscriptions);
if (subscriptions->Contains(topic)) { if (subscriptions->Contains(topic)) {
Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone(); Dictionary::Ptr newSubscriptions = subscriptions->ShallowClone();
ObjectLock nlock(newSubscriptions);
newSubscriptions->Remove(topic); newSubscriptions->Remove(topic);
SetSubscriptions(newSubscriptions); SetSubscriptions(newSubscriptions);
} }
@ -178,6 +182,8 @@ bool Endpoint::HasSubscription(const String& topic) const
*/ */
void Endpoint::ClearSubscriptions(void) void Endpoint::ClearSubscriptions(void)
{ {
ObjectLock olock(this);
m_Subscriptions = Empty; m_Subscriptions = Empty;
Touch("subscriptions"); Touch("subscriptions");
} }
@ -189,12 +195,17 @@ Dictionary::Ptr Endpoint::GetSubscriptions(void) const
void Endpoint::SetSubscriptions(const Dictionary::Ptr& subscriptions) void Endpoint::SetSubscriptions(const Dictionary::Ptr& subscriptions)
{ {
ObjectLock olock(this);
subscriptions->Seal();
m_Subscriptions = subscriptions; m_Subscriptions = subscriptions;
Touch("subscriptions"); Touch("subscriptions");
} }
void Endpoint::RegisterTopicHandler(const String& topic, const function<Endpoint::Callback>& callback) void Endpoint::RegisterTopicHandler(const String& topic, const function<Endpoint::Callback>& callback)
{ {
ObjectLock olock(this);
map<String, shared_ptr<signals2::signal<Endpoint::Callback> > >::iterator it; map<String, shared_ptr<signals2::signal<Endpoint::Callback> > >::iterator it;
it = m_TopicHandlers.find(topic); it = m_TopicHandlers.find(topic);
@ -223,6 +234,8 @@ void Endpoint::UnregisterTopicHandler(const String& topic, const function<Endpoi
void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue) void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
{ {
assert(!OwnsLock());
if (name == "subscriptions") { if (name == "subscriptions") {
Dictionary::Ptr oldSubscriptions, newSubscriptions; Dictionary::Ptr oldSubscriptions, newSubscriptions;
@ -231,10 +244,9 @@ void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
newSubscriptions = GetSubscriptions(); newSubscriptions = GetSubscriptions();
ObjectLock olock(oldSubscriptions);
ObjectLock nlock(newSubscriptions);
if (oldSubscriptions) { if (oldSubscriptions) {
ObjectLock olock(oldSubscriptions);
String subscription; String subscription;
BOOST_FOREACH(tie(tuples::ignore, subscription), oldSubscriptions) { BOOST_FOREACH(tie(tuples::ignore, subscription), oldSubscriptions) {
if (!newSubscriptions || !newSubscriptions->Contains(subscription)) { if (!newSubscriptions || !newSubscriptions->Contains(subscription)) {
@ -245,6 +257,8 @@ void Endpoint::OnAttributeChanged(const String& name, const Value& oldValue)
} }
if (newSubscriptions) { if (newSubscriptions) {
ObjectLock olock(newSubscriptions);
String subscription; String subscription;
BOOST_FOREACH(tie(tuples::ignore, subscription), newSubscriptions) { BOOST_FOREACH(tie(tuples::ignore, subscription), newSubscriptions) {
if (!oldSubscriptions || !oldSubscriptions->Contains(subscription)) { if (!oldSubscriptions || !oldSubscriptions->Contains(subscription)) {
@ -264,6 +278,8 @@ void Endpoint::ProcessRequest(const Endpoint::Ptr& sender, const RequestMessage&
} }
if (IsLocalEndpoint()) { if (IsLocalEndpoint()) {
ObjectLock olock(this);
String method; String method;
if (!request.GetMethod(&method)) if (!request.GetMethod(&method))
return; return;
@ -317,6 +333,8 @@ void Endpoint::NewMessageHandler(const MessagePart& message)
void Endpoint::ClientClosedHandler(void) void Endpoint::ClientClosedHandler(void)
{ {
assert(!OwnsLock());
/*try { /*try {
GetClient()->CheckException(); GetClient()->CheckException();
} catch (const exception& ex) { } catch (const exception& ex) {
@ -328,12 +346,16 @@ void Endpoint::ClientClosedHandler(void)
Logger::Write(LogWarning, "jsonrpc", "Lost connection to endpoint: identity=" + GetName()); Logger::Write(LogWarning, "jsonrpc", "Lost connection to endpoint: identity=" + GetName());
// TODO: _only_ clear non-persistent subscriptions {
// unregister ourselves if no persistent subscriptions are left (use a ObjectLock olock(this);
// timer for that, once we have a TTL property for the topics)
ClearSubscriptions();
m_Client.reset(); // TODO: _only_ clear non-persistent subscriptions
// unregister ourselves if no persistent subscriptions are left (use a
// timer for that, once we have a TTL property for the topics)
ClearSubscriptions();
m_Client.reset();
}
OnDisconnected(GetSelf()); OnDisconnected(GetSelf());
} }
@ -345,6 +367,8 @@ void Endpoint::ClientClosedHandler(void)
*/ */
String Endpoint::GetNode(void) const String Endpoint::GetNode(void) const
{ {
ObjectLock olock(this);
return m_Node; return m_Node;
} }
@ -355,5 +379,7 @@ String Endpoint::GetNode(void) const
*/ */
String Endpoint::GetService(void) const String Endpoint::GetService(void) const
{ {
ObjectLock olock(this);
return m_Service; return m_Service;
} }

View File

@ -50,6 +50,8 @@ EndpointManager::EndpointManager(void)
*/ */
void EndpointManager::SetSSLContext(const shared_ptr<SSL_CTX>& sslContext) void EndpointManager::SetSSLContext(const shared_ptr<SSL_CTX>& sslContext)
{ {
ObjectLock olock(this);
m_SSLContext = sslContext; m_SSLContext = sslContext;
} }
@ -60,6 +62,8 @@ void EndpointManager::SetSSLContext(const shared_ptr<SSL_CTX>& sslContext)
*/ */
shared_ptr<SSL_CTX> EndpointManager::GetSSLContext(void) const shared_ptr<SSL_CTX> EndpointManager::GetSSLContext(void) const
{ {
ObjectLock olock(this);
return m_SSLContext; return m_SSLContext;
} }
@ -71,6 +75,8 @@ shared_ptr<SSL_CTX> EndpointManager::GetSSLContext(void) const
*/ */
void EndpointManager::SetIdentity(const String& identity) void EndpointManager::SetIdentity(const String& identity)
{ {
ObjectLock olock(this);
m_Identity = identity; m_Identity = identity;
if (m_Endpoint) if (m_Endpoint)
@ -91,6 +97,8 @@ void EndpointManager::SetIdentity(const String& identity)
*/ */
String EndpointManager::GetIdentity(void) const String EndpointManager::GetIdentity(void) const
{ {
ObjectLock olock(this);
return m_Identity; return m_Identity;
} }
@ -101,6 +109,8 @@ String EndpointManager::GetIdentity(void) const
*/ */
void EndpointManager::AddListener(const String& service) void EndpointManager::AddListener(const String& service)
{ {
ObjectLock olock(this);
shared_ptr<SSL_CTX> sslContext = GetSSLContext(); shared_ptr<SSL_CTX> sslContext = GetSSLContext();
if (!sslContext) if (!sslContext)
@ -128,6 +138,8 @@ void EndpointManager::AddListener(const String& service)
* @param service The remote port. * @param service The remote port.
*/ */
void EndpointManager::AddConnection(const String& node, const String& service) { void EndpointManager::AddConnection(const String& node, const String& service) {
ObjectLock olock(this);
shared_ptr<SSL_CTX> sslContext = GetSSLContext(); shared_ptr<SSL_CTX> sslContext = GetSSLContext();
if (!sslContext) if (!sslContext)
@ -145,6 +157,8 @@ void EndpointManager::AddConnection(const String& node, const String& service) {
*/ */
void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role) void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role)
{ {
ObjectLock olock(this);
String peerAddress = client->GetPeerAddress(); String peerAddress = client->GetPeerAddress();
TlsStream::Ptr tlsStream = boost::make_shared<TlsStream>(client, role, GetSSLContext()); TlsStream::Ptr tlsStream = boost::make_shared<TlsStream>(client, role, GetSSLContext());
tlsStream->Start(); tlsStream->Start();
@ -158,6 +172,8 @@ void EndpointManager::NewClientHandler(const Socket::Ptr& client, TlsRole role)
void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const String& peerAddress) void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const String& peerAddress)
{ {
ObjectLock olock(this);
TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client); TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client);
JsonRpcConnection::Ptr jclient = boost::make_shared<JsonRpcConnection>(tlsStream); JsonRpcConnection::Ptr jclient = boost::make_shared<JsonRpcConnection>(tlsStream);
@ -178,6 +194,8 @@ void EndpointManager::ClientConnectedHandler(const Stream::Ptr& client, const St
void EndpointManager::ClientClosedHandler(const Stream::Ptr& client) void EndpointManager::ClientClosedHandler(const Stream::Ptr& client)
{ {
ObjectLock olock(this);
TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client); TlsStream::Ptr tlsStream = static_pointer_cast<TlsStream>(client);
m_PendingClients.erase(tlsStream); m_PendingClients.erase(tlsStream);
} }
@ -293,6 +311,8 @@ void EndpointManager::SendAPIMessage(const Endpoint::Ptr& sender, const Endpoint
RequestMessage& message, RequestMessage& message,
const EndpointManager::APICallback& callback, double timeout) const EndpointManager::APICallback& callback, double timeout)
{ {
ObjectLock olock(this);
m_NextMessageID++; m_NextMessageID++;
stringstream idstream; stringstream idstream;
@ -337,7 +357,7 @@ void EndpointManager::SubscriptionTimerHandler(void)
ObjectLock olock(endpointSubscriptions); ObjectLock olock(endpointSubscriptions);
String topic; String topic;
BOOST_FOREACH(tie(tuples::ignore, topic), endpoint->GetSubscriptions()) { BOOST_FOREACH(tie(tuples::ignore, topic), endpointSubscriptions) {
subscriptions->Set(topic, topic); subscriptions->Set(topic, topic);
} }
} }
@ -374,6 +394,8 @@ void EndpointManager::ReconnectTimerHandler(void)
void EndpointManager::RequestTimerHandler(void) void EndpointManager::RequestTimerHandler(void)
{ {
ObjectLock olock(this);
map<String, PendingRequest>::iterator it; map<String, PendingRequest>::iterator it;
for (it = m_Requests.begin(); it != m_Requests.end(); it++) { for (it = m_Requests.begin(); it != m_Requests.end(); it++) {
if (it->second.HasTimedOut()) { if (it->second.HasTimedOut()) {
@ -390,6 +412,8 @@ void EndpointManager::RequestTimerHandler(void)
void EndpointManager::ProcessResponseMessage(const Endpoint::Ptr& sender, void EndpointManager::ProcessResponseMessage(const Endpoint::Ptr& sender,
const ResponseMessage& message) const ResponseMessage& message)
{ {
ObjectLock olock(this);
String id; String id;
if (!message.GetID(&id)) if (!message.GetID(&id))
BOOST_THROW_EXCEPTION(invalid_argument("Response message must have a message ID.")); BOOST_THROW_EXCEPTION(invalid_argument("Response message must have a message ID."));

View File

@ -37,6 +37,8 @@ JsonRpcConnection::JsonRpcConnection(const Stream::Ptr& stream)
*/ */
void JsonRpcConnection::SendMessage(const MessagePart& message) void JsonRpcConnection::SendMessage(const MessagePart& message)
{ {
ObjectLock olock(this);
Value value = message.GetDictionary(); Value value = message.GetDictionary();
String json = value.Serialize(); String json = value.Serialize();
//std::cerr << ">> " << json << std::endl; //std::cerr << ">> " << json << std::endl;
@ -48,6 +50,8 @@ void JsonRpcConnection::SendMessage(const MessagePart& message)
*/ */
void JsonRpcConnection::ProcessData(void) void JsonRpcConnection::ProcessData(void)
{ {
ObjectLock olock(this);
String jsonString; String jsonString;
while (NetString::ReadStringFromStream(GetStream(), &jsonString)) { while (NetString::ReadStringFromStream(GetStream(), &jsonString)) {