From 84a6684a9c219e3bc3768058853748dd8437e901 Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Wed, 28 Feb 2024 02:19:13 -0500 Subject: [PATCH] Monitor: syncup from metro version --- Monitor/CMakeLists.txt | 7 +- Monitor/Monitor.config | 81 +++++++ Monitor/Monitor.cpp | 30 ++- Monitor/Monitor.h | 444 ++++++++++++++++++------------------- Monitor/MonitorJsonRpc.cpp | 8 +- 5 files changed, 320 insertions(+), 250 deletions(-) diff --git a/Monitor/CMakeLists.txt b/Monitor/CMakeLists.txt index e90191511c..ffacbd7931 100644 --- a/Monitor/CMakeLists.txt +++ b/Monitor/CMakeLists.txt @@ -21,9 +21,12 @@ cmake_minimum_required(VERSION 3.3) find_package(WPEFramework) -set(PLUGIN_NAME Monitor) +project_version(1.0.0) + set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) +message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") + set(PLUGIN_MONITOR_AUTOSTART "true" CACHE STRING "Automatically start Monitor plugin") set(PLUGIN_MONITOR_STARTUPORDER "" CACHE STRING "Automatically start Monitor plugin") # Plugins built from this repository that can be autmatically enabled or enabled manually when built externally @@ -90,4 +93,4 @@ target_link_libraries(${MODULE_NAME} install(TARGETS ${MODULE_NAME} DESTINATION lib/${STORAGE_DIRECTORY}/plugins) -write_config(${PROJECT_NAME}) +write_config() diff --git a/Monitor/Monitor.config b/Monitor/Monitor.config index 24d6d6b3f4..8dad98f48d 100644 --- a/Monitor/Monitor.config +++ b/Monitor/Monitor.config @@ -176,6 +176,21 @@ if(PLUGIN_MONITOR_OPENCDMI) map_append(${configuration} observables ${OPENCDMI_MONITOR_CONFIG}) endif() +if(PLUGIN_MONITOR_TEXTTOSPEECH) + map() + kv(callsign org.rdk.TextToSpeech) + kv(operational 1) + key(restart) + map() + kv(window 60) + kv(limit 3) + end() + end() + ans(TEXTTOSPEECH_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${TEXTTOSPEECH_MONITOR_CONFIG}) +endif() + if(PLUGIN_MONITOR_SYSTEMAUDIOPLAYER) map() kv(callsign org.rdk.SystemAudioPlayer) @@ -208,6 +223,72 @@ if(PLUGIN_MONITOR_WEBKITBROWSER_RESIDENT_APP) map_append(${configuration} observables ${RESIDENT_APP_MONITOR_CONFIG}) endif() +if(PLUGIN_MONITOR_CLONED_APPS) + map() + kv(callsign "SearchAndDiscovery") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_SEARCH_AND_DISCOVERY_MEMORYLIMIT}) + end() + ans(SAD_APP_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${SAD_APP_MONITOR_CONFIG}) + + foreach(N RANGE 0 3) + map() + kv(callsign "HtmlApp-${N}") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT}) + end() + ans(HTML_APP_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${HTML_APP_MONITOR_CONFIG}) + endforeach() + + foreach(N RANGE 0 3) + map() + kv(callsign "LightningApp-${N}") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT}) + end() + ans(LIGHTNING_APP_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${LIGHTNING_APP_MONITOR_CONFIG}) + endforeach() + + map() + kv(callsign "Cobalt-0") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT}) + end() + ans(COBALT_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${COBALT_MONITOR_CONFIG}) + + map() + kv(callsign "Netflix-0") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_NETFLIX_APP_MEMORYLIMIT}) + end() + ans(NETFLIX_APP_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${NETFLIX_APP_MONITOR_CONFIG}) + + map() + kv(callsign "JSPP") + kv(operational -1) + kv(memory 5) + kv(memorylimit ${PLUGIN_MONITOR_CLONED_APP_MEMORYLIMIT}) + end() + ans(JSPP_MONITOR_CONFIG) + map_append(${configuration} observables ___array___) + map_append(${configuration} observables ${JSPP_MONITOR_CONFIG}) +endif() + if(PLUGIN_MONITOR_INSTANCES_LIST) # 'PLUGIN_MONITOR_INSTANCES_LIST' contains a semi-colon (';') separated list of Monitor observable diff --git a/Monitor/Monitor.cpp b/Monitor/Monitor.cpp index c042010ba6..d46403dd17 100644 --- a/Monitor/Monitor.cpp +++ b/Monitor/Monitor.cpp @@ -49,6 +49,7 @@ namespace Plugin { /* virtual */ const string Monitor::Initialize(PluginHost::IShell* service) { + ASSERT(service != nullptr); _config.FromString(service->ConfigLine()); @@ -57,10 +58,12 @@ namespace Plugin { Core::JSON::ArrayType::Iterator index(_config.Observables.Elements()); // Create a list of plugins to monitor.. - _monitor->Open(service, index); + _monitor.Open(service, index); // During the registartion, all Plugins, currently active are reported to the sink. - service->Register(_monitor); + service->Register(&_monitor); + + RegisterAll(); // On succes return a name as a Callsign to be used in the URL, after the "service"prefix return (_T("")); @@ -68,10 +71,13 @@ namespace Plugin { /* virtual */ void Monitor::Deinitialize(PluginHost::IShell* service) { + ASSERT(service != nullptr); + + UnregisterAll(); - _monitor->Close(); + service->Unregister(&_monitor); - service->Unregister(_monitor); + _monitor.Close(); } /* virtual */ string Monitor::Information() const @@ -106,10 +112,10 @@ namespace Plugin { if (request.Verb == Web::Request::HTTP_GET) { // Let's list them all.... if (index.Next() == false) { - if (_monitor->Length() > 0) { + if (_monitor.Length() > 0) { Core::ProxyType>> response(jsonBodyDataFactory.Element()); - _monitor->Snapshot(*response); + _monitor.Snapshot(*response); #ifndef USE_THUNDER_R4 result->Body(Core::proxy_cast(response)); #else @@ -118,12 +124,13 @@ namespace Plugin { } } else { MetaData memoryInfo; + bool operational = false; // Seems we only want 1 name - if (_monitor->Snapshot(index.Current().Text(), memoryInfo) == true) { + if (_monitor.Snapshot(index.Current().Text(), memoryInfo, operational) == true) { Core::ProxyType> response(jsonMemoryBodyDataFactory.Element()); - *response = memoryInfo; + *response = Monitor::Data::MetaData(memoryInfo, operational); #ifndef USE_THUNDER_R4 result->Body(Core::proxy_cast(response)); #else @@ -135,12 +142,13 @@ namespace Plugin { result->ContentType = Web::MIME_JSON; } else if ((request.Verb == Web::Request::HTTP_PUT) && (index.Next() == true)) { MetaData memoryInfo; + bool operational = false; // Seems we only want 1 name - if (_monitor->Reset(index.Current().Text(), memoryInfo) == true) { + if (_monitor.Reset(index.Current().Text(), memoryInfo, operational) == true) { Core::ProxyType> response(jsonMemoryBodyDataFactory.Element()); - *response = memoryInfo; + *response = Monitor::Data::MetaData(memoryInfo, operational); #ifndef USE_THUNDER_R4 result->Body(Core::proxy_cast(response)); #else @@ -161,7 +169,7 @@ namespace Plugin { restartLimit = body->Restart.Limit; } TRACE(Trace::Information, (_T("Sets Restart Limits:[LIMIT:%d, WINDOW:%d]"), restartLimit, restartWindow)); - _monitor->Update(observable, restartWindow, restartLimit); + _monitor.Update(observable, restartWindow, restartLimit); } else { result->ErrorCode = Web::STATUS_BAD_REQUEST; result->Message = _T(" could not handle your request."); diff --git a/Monitor/Monitor.h b/Monitor/Monitor.h index 4045a385c3..a658033d0c 100644 --- a/Monitor/Monitor.h +++ b/Monitor/Monitor.h @@ -70,7 +70,6 @@ namespace Plugin { , _allocated() , _shared() , _process() - , _operational(false) { } MetaData(const MetaData& copy) @@ -78,7 +77,6 @@ namespace Plugin { , _allocated(copy._allocated) , _shared(copy._shared) , _process(copy._process) - , _operational(copy._operational) { } ~MetaData() @@ -91,23 +89,30 @@ namespace Plugin { _allocated = rhs._allocated; _shared = rhs._shared; _process = rhs._process; - _operational = rhs._operational; return (*this); } public: + bool HasMeasurements() const { + return ((_resident.Measurements() != 0) || (_allocated.Measurements() != 0) || (_shared.Measurements() != 0) || (_process.Measurements() != 0)); + } + + void AddMeasurements(const uint64_t resident, const uint64_t allocated, const uint64_t shared, const uint64_t process) { + _resident.Set(resident); + _allocated.Set(allocated); + _shared.Set(shared); + _process.Set(process); + } + void Measure(Exchange::IMemory* memInterface) { + ASSERT(memInterface != nullptr); _resident.Set(memInterface->Resident()); _allocated.Set(memInterface->Allocated()); _shared.Set(memInterface->Shared()); _process.Set(memInterface->Processes()); } - void Operational(const bool operational) - { - _operational = operational; - } void Reset() { _resident.Reset(); @@ -133,17 +138,11 @@ namespace Plugin { { return (_process); } - inline bool Operational() const - { - return (_operational); - } - private: Core::MeasurementType _resident; Core::MeasurementType _allocated; Core::MeasurementType _shared; Core::MeasurementType _process; - bool _operational; }; class Data : public Core::JSON::Container { @@ -259,7 +258,7 @@ namespace Plugin { Add(_T("operational"), &Operational); Add(_T("count"), &Count); } - MetaData(const Monitor::MetaData& input) + MetaData(const Monitor::MetaData& input, const bool operational) : Core::JSON::Container() { Add(_T("allocated"), &Allocated); @@ -273,7 +272,7 @@ namespace Plugin { Resident = input.Resident(); Shared = input.Shared(); Process = input.Process(); - Operational = input.Operational(); + Operational = operational; Count = input.Allocated().Measurements(); } MetaData(const MetaData& copy) @@ -307,17 +306,6 @@ namespace Plugin { return (*this); } - MetaData& operator=(const Monitor::MetaData& RHS) - { - Allocated = RHS.Allocated(); - Resident = RHS.Resident(); - Shared = RHS.Shared(); - Process = RHS.Process(); - Operational = RHS.Operational(); - Count = RHS.Allocated().Measurements(); - - return (*this); - } public: Measurement Allocated; @@ -344,10 +332,10 @@ namespace Plugin { Add(_T("observable"), &Observable); Add(_T("restart"), &Restart); } - Data(const string& name, const Monitor::MetaData& info) + Data(const string& name, const Monitor::MetaData& info, const bool operational) : Core::JSON::Container() , Name() - , Measurement() + , Measurement(info, operational) , Observable() , Restart() { @@ -357,7 +345,6 @@ namespace Plugin { Add(_T("restart"), &Restart); Name = name; - Measurement = info; } Data(const Data& copy) : Core::JSON::Container() @@ -486,33 +473,14 @@ namespace Plugin { , _restartCount(0) , _restartLimit(restartLimit) , _measurement() + , _operational(false) , _operationalEvaluate(actOnOperational) , _source(nullptr) + , _interval( ((operationalInterval != 0) || (_memoryInterval != 0)) ? gcd(_operationalInterval, _memoryInterval) : 0 ) , _active{ false } + , _adminLock() { ASSERT((_operationalInterval != 0) || (_memoryInterval != 0)); - _interval = gcd(_operationalInterval, _memoryInterval); - } - MonitorObject(const MonitorObject& copy) - : _operationalInterval(copy._operationalInterval) - , _memoryInterval(copy._memoryInterval) - , _memoryThreshold(copy._memoryThreshold) - , _operationalSlots(copy._operationalSlots) - , _memorySlots(copy._memorySlots) - , _nextSlot(copy._nextSlot) - , _restartWindow(copy._restartWindow) - , _restartWindowStart(copy._restartWindowStart) - , _restartCount(copy._restartCount) - , _restartLimit(copy._restartLimit) - , _measurement(copy._measurement) - , _operationalEvaluate(copy._operationalEvaluate) - , _source(copy._source) - , _interval(copy._interval) - , _active{ copy._active } - { - if (_source != nullptr) { - _source->AddRef(); - } } ~MonitorObject() { @@ -522,6 +490,11 @@ namespace Plugin { } } + MonitorObject(MonitorObject&) = delete; + MonitorObject& operator=(MonitorObject&) = delete; + MonitorObject(MonitorObject&&) = delete; + MonitorObject& operator=(MonitorObject&&) = delete; + public: inline bool RegisterRestart(PluginHost::IShell::reason why VARIABLE_IS_NOT_USED) { @@ -543,11 +516,11 @@ namespace Plugin { return result; } - inline uint8_t RestartLimit() + inline uint8_t RestartLimit() const { return _restartLimit; } - inline uint16_t RestartWindow() + inline uint16_t RestartWindow() const { return _restartWindow; } @@ -566,14 +539,14 @@ namespace Plugin { { return (_interval); } - inline const MetaData& Measurement() const + inline uint32_t Operational() const { - return (_measurement); + return (_operational); } - inline bool HasMeasurement() const + inline const MetaData& Measurement() const { - return (((_measurement.Allocated().Min() == Core::NumberType::Max()) && - (_measurement.Allocated().Max() == Core::NumberType::Min())) ? false : true); + Core::SafeSyncType guard(_adminLock); + return (_measurement); } inline uint64_t TimeSlot() const { @@ -581,6 +554,7 @@ namespace Plugin { } inline void Reset() { + Core::SafeSyncType guard(_adminLock); _measurement.Reset(); } inline void Retrigger(uint64_t currentSlot) @@ -591,6 +565,7 @@ namespace Plugin { } inline void Set(Exchange::IMemory* memory) { + _adminLock.Lock(); if (_source != nullptr) { _source->Release(); _source = nullptr; @@ -600,29 +575,55 @@ namespace Plugin { _source = memory; _source->AddRef(); } + _adminLock.Unlock(); + + _operational = (memory != nullptr); + } - _measurement.Operational(_source != nullptr); + Core::ProxyType Source() const + { + Core::ProxyType source; + _adminLock.Lock(); + if (_source != nullptr) { +#ifdef USE_THUNDER_R4 + source = Core::ProxyType(*_source, *_source); +#else + source = Core::ProxyType(*_source); +#endif + } + _adminLock.Unlock(); + return source; } + inline uint32_t Evaluate() { + Core::ProxyType source = Source(); + uint32_t status(SUCCESFULL); - if (_source != nullptr) { + if (source.IsValid() == true) { _operationalSlots -= _interval; _memorySlots -= _interval; if ((_operationalInterval != 0) && (_operationalSlots == 0)) { - bool operational = _source->IsOperational(); - _measurement.Operational(operational); - if (operational == false) { + _operational = source->IsOperational(); + if (_operational == false) { status |= NOT_OPERATIONAL; TRACE(Trace::Error, (_T("Status not operational. %d"), __LINE__)); } _operationalSlots = _operationalInterval; } if ((_memoryInterval != 0) && (_memorySlots == 0)) { - _measurement.Measure(_source); - if ((_memoryThreshold != 0) && (_measurement.Resident().Last() > _memoryThreshold)) { + uint64_t resident = source->Resident(); + uint64_t allocated = source->Allocated(); + uint64_t shared = source->Shared(); + uint64_t process = source->Processes(); + + _adminLock.Lock(); + _measurement.AddMeasurements(resident, allocated, shared, process); + _adminLock.Unlock(); + + if ((_memoryThreshold != 0) && (resident > _memoryThreshold)) { status |= EXCEEDED_MEMORY; TRACE(Trace::Error, (_T("Status MetaData Exceeded. %d"), __LINE__)); } @@ -639,18 +640,20 @@ namespace Plugin { const uint32_t _operationalInterval; //!< Interval (s) to check the monitored processes const uint32_t _memoryInterval; //!< Interval (s) for a memory measurement. const uint64_t _memoryThreshold; //!< MetaData threshold in bytes for all processes. - uint32_t _operationalSlots; - uint32_t _memorySlots; - uint64_t _nextSlot; - uint16_t _restartWindow; - Core::Time _restartWindowStart; - uint32_t _restartCount; - uint8_t _restartLimit; + uint32_t _operationalSlots; // does not need protection, only touched in job evaluate + uint32_t _memorySlots; // does not need protection, only touched in job evaluate + std::atomic _nextSlot; // no ordering needed, atomic should suffice + std::atomic _restartWindow; // no ordering needed, atomic should suffice + Core::Time _restartWindowStart; // only used in job (indirectly), no protection needed + uint32_t _restartCount; // only used in job (indirectly), no protection needed + std::atomic _restartLimit; // no ordering needed, atomic should suffice MetaData _measurement; - bool _operationalEvaluate; + std::atomic _operational; // no ordering needed, atomic should suffice + const bool _operationalEvaluate; Exchange::IMemory* _source; - uint32_t _interval; //!< The greatest possible interval to check both memory and processes. - bool _active; + const uint32_t _interval; //!< The greatest possible interval to check both memory and processes. + std::atomic _active; + mutable Core::CriticalSection _adminLock; }; public: @@ -661,8 +664,7 @@ namespace Plugin { #pragma warning(disable : 4355) #endif MonitorObjects(Monitor* parent) - : _adminLock() - , _monitor() + : _monitor() , _job(*this) , _service(nullptr) , _parent(*parent) @@ -671,7 +673,7 @@ namespace Plugin { #ifdef __WINDOWS__ #pragma warning(default : 4355) #endif - virtual ~MonitorObjects() + ~MonitorObjects() override { ASSERT(_monitor.size() == 0); } @@ -686,16 +688,12 @@ namespace Plugin { const uint16_t restartWindow, const uint8_t restartLimit) { - _adminLock.Lock(); - - std::map::iterator index(_monitor.find(observable)); + MonitorObjectContainer::iterator index(_monitor.find(observable)); if (index != _monitor.end()) { index->second.UpdateRestartLimits( restartWindow, restartLimit); } - - _adminLock.Unlock(); } inline void Open(PluginHost::IShell* service, Core::JSON::ArrayType::Iterator& index) { @@ -706,8 +704,6 @@ namespace Plugin { _service = service; _service->AddRef(); - _adminLock.Lock(); - while (index.Next() == true) { Config::Entry& element(index.Current()); string callSign(element.Callsign.Value()); @@ -724,20 +720,21 @@ namespace Plugin { } SYSLOG(Logging::Startup, (_T("Monitoring: %s (%d,%d)."), callSign.c_str(), (interval / 1000000), (memory / 1000000))); if ((interval != 0) || (memory != 0)) { - _monitor.insert( - std::pair(callSign, MonitorObject( - element.Operational.Value() >= 0, - interval, - memory, - memoryThreshold, - baseTime, - restartWindow, - restartLimit))); + + _monitor.emplace(std::piecewise_construct, + std::forward_as_tuple(callSign), + std::forward_as_tuple( + element.Operational.Value() >= 0, + interval, + memory, + memoryThreshold, + baseTime, + restartWindow, + restartLimit) + ); } } - _adminLock.Unlock(); - _job.Submit(); } inline void Close() @@ -746,88 +743,16 @@ namespace Plugin { _job.Revoke(); - _adminLock.Lock(); _monitor.clear(); - _adminLock.Unlock(); _service->Release(); _service = nullptr; } -#if (THUNDER_VERSION_MAJOR >= 4) -#if (THUNDER_VERSION_MINOR == 2) - void Activation(const string& name, PluginHost::IShell* service) override - { - //No Opp - } - - void Deactivation(const string& name, PluginHost::IShell* service) override - { - //No Opp - } -#endif - void Activated (const string& callsign, PluginHost::IShell* service) override - { - _adminLock.Lock(); - - std::map::iterator index(_monitor.find(callsign)); - - - if (index != _monitor.end()) { - - index->second.Active(true); - - if (_job.Submit() == true) { - TRACE(Trace::Information, (_T("Starting to probe as active observee appeared."))); - } - - // Get the MetaData interface - Exchange::IMemory* memory = service->QueryInterface(); - - if (memory != nullptr) { - index->second.Set(memory); - memory->Release(); - } - } - - _adminLock.Unlock(); - } - void Deactivated (const string& callsign, PluginHost::IShell* service) override - { - _adminLock.Lock(); - - std::map::iterator index(_monitor.find(callsign)); - - if (index != _monitor.end()) { - - index->second.Set(nullptr); - index->second.Active(false); - if ((index->second.HasRestartAllowed() == true) && ((service->Reason() == PluginHost::IShell::MEMORY_EXCEEDED) || (service->Reason() == PluginHost::IShell::FAILURE))) { - if (index->second.RegisterRestart(service->Reason()) == false) { - TRACE(Trace::Fatal, (_T("Giving up restarting of %s: Failed more than %d times within %d seconds."), callsign.c_str(), index->second.RestartLimit(), index->second.RestartWindow())); - const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Restart\", \"reason\":\"" + (std::to_string(index->second.RestartLimit())).c_str() + " Attempts Failed within the restart window\"}"); - _service->Notify(message); - _parent.event_action(callsign, "StoppedRestaring", std::to_string(index->second.RestartLimit()) + " attempts failed within the restart window"); - } else { - const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Activate\", \"reason\": \"Automatic\" }"); - _service->Notify(message); - _parent.event_action(callsign, "Activate", "Automatic"); - TRACE(Trace::Error, (_T("Restarting %s again because we detected it misbehaved."), callsign.c_str())); - Core::IWorkerPool::Instance().Schedule(Core::Time::Now(), PluginHost::IShell::Job::Create(service, PluginHost::IShell::ACTIVATED, PluginHost::IShell::AUTOMATIC)); - } - } - } - - _adminLock.Unlock(); - } - void Unavailable(const string&, PluginHost::IShell*) override +#ifndef USE_THUNDER_R4 + void StateChange(PluginHost::IShell* service) override { - } -#else - virtual void StateChange(PluginHost::IShell* service) - { - _adminLock.Lock(); - std::map::iterator index(_monitor.find(service->Callsign())); + MonitorObjectContainer::iterator index(_monitor.find(service->Callsign())); if (index != _monitor.end()) { @@ -837,7 +762,7 @@ namespace Plugin { if (currentState == PluginHost::IShell::ACTIVATED) { bool is_active = index->second.IsActive(); index->second.Active(true); - if (is_active == false && std::count_if(_monitor.begin(), _monitor.end(), [](const std::pair& v) { + if (is_active == false && std::count_if(_monitor.begin(), _monitor.end(), [](const std::pair& v) { return v.second.IsActive(); }) == 1) { @@ -883,50 +808,121 @@ namespace Plugin { } } } + } + +#else + void Activated (const string& callsign, PluginHost::IShell* service) override + { + MonitorObjectContainer::iterator index(_monitor.find(callsign)); + + if (index != _monitor.end()) { + + index->second.Active(true); - _adminLock.Unlock(); + // Get the MetaData interface + Exchange::IMemory* memory = service->QueryInterface(); + + if (memory != nullptr) { + index->second.Set(memory); + memory->Release(); + } + + if (_job.Submit() == true) { + TRACE(Trace::Information, (_T("Starting to probe as active observee appeared."))); + } + } } -#endif - void Snapshot(Core::JSON::ArrayType& snapshot) + void Deactivated (const string& callsign, PluginHost::IShell* service) override { - _adminLock.Lock(); + MonitorObjectContainer::iterator index(_monitor.find(callsign)); + + if (index != _monitor.end()) { + + index->second.Set(nullptr); + index->second.Active(false); + + PluginHost::IShell::reason reason = service->Reason(); - std::map::iterator element(_monitor.begin()); + if ((index->second.HasRestartAllowed() == true) && ((reason == PluginHost::IShell::MEMORY_EXCEEDED) || (reason == PluginHost::IShell::FAILURE))) { + if (index->second.RegisterRestart(reason) == false) { + uint8_t restartlimit = index->second.RestartLimit(); + uint16_t restartwindow = index->second.RestartWindow(); + TRACE(Trace::Fatal, (_T("Giving up restarting of %s: Failed more than %d times within %d seconds."), callsign.c_str(), restartlimit, restartwindow)); + const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Restart\", \"reason\":\"" + (std::to_string(restartlimit)).c_str() + " Attempts Failed within the restart window\"}"); + _service->Notify(message); + _parent.event_action(callsign, "StoppedRestaring", std::to_string(index->second.RestartLimit()) + " attempts failed within the restart window"); + } else { + const string message("{\"callsign\": \"" + callsign + "\", \"action\": \"Activate\", \"reason\": \"Automatic\" }"); + _service->Notify(message); + _parent.event_action(callsign, "Activate", "Automatic"); + TRACE(Trace::Error, (_T("Restarting %s again because we detected it misbehaved."), callsign.c_str())); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(service, PluginHost::IShell::ACTIVATED, PluginHost::IShell::AUTOMATIC)); + } + } + } + } + void Unavailable(const string&, PluginHost::IShell*) override + { + } +#endif + void Snapshot(Core::JSON::ArrayType& snapshot) const + { + MonitorObjectContainer::const_iterator element(_monitor.cbegin()); // Go through the list of observations... - while (element != _monitor.end()) { - if (element->second.HasMeasurement() == true) { - snapshot.Add(Monitor::Data(element->first, element->second.Measurement())); + while (element != _monitor.cend()) { + MetaData data = element->second.Measurement(); + if (data.HasMeasurements() == true) { + snapshot.Add(Monitor::Data(element->first, data, element->second.Operational())); } element++; } - _adminLock.Unlock(); } - bool Snapshot(const string& name, Monitor::MetaData& result) + bool Snapshot(const string& name, Monitor::MetaData& result, bool& operational) const { bool found = false; - _adminLock.Lock(); - std::map::iterator index(_monitor.find(name)); + MonitorObjectContainer::const_iterator index(_monitor.find(name)); - if (index != _monitor.end()) { - if (index->second.HasMeasurement() == true) { - result = index->second.Measurement(); + if (index != _monitor.cend()) { + MetaData data = index->second.Measurement(); + if (data.HasMeasurements() == true) { + result = data; + operational = index->second.Operational(); found = true; } } - _adminLock.Unlock(); - return (found); } - void Snapshot(const string& callsign, Core::JSON::ArrayType* response) - { - _adminLock.Lock(); + void AddElementToResponse( Core::JSON::ArrayType& response, const string& callsign, const MonitorObject& object) const { + const MetaData& metaData = object.Measurement(); + JsonData::Monitor::InfoInfo info; + info.Observable = callsign; + + if (object.HasRestartAllowed()) { + info.Restart.Limit = object.RestartLimit(); + info.Restart.Window = object.RestartWindow(); + } + if (metaData.HasMeasurements() == true) { + translate(metaData.Allocated(), &info.Measurements.Allocated); + translate(metaData.Resident(), &info.Measurements.Resident); + translate(metaData.Shared(), &info.Measurements.Shared); + translate(metaData.Process(), &info.Measurements.Process); + } + info.Measurements.Operational = object.Operational(); + info.Measurements.Count = metaData.Allocated().Measurements(); + + response.Add(info); + }; + + void Snapshot(const string& callsign, Core::JSON::ArrayType* response) const + { + ASSERT(response != nullptr); auto AddElement = [this, &response](const string& callsignE, MonitorObject& object) { const MetaData& metaData = object.Measurement(); JsonData::Monitor::InfoInfo info; @@ -952,33 +948,28 @@ namespace Plugin { if (callsign.empty() == false) { auto element = _monitor.find(callsign); if (element != _monitor.end()) { - AddElement(element->first, element->second); + AddElementToResponse(*response, element->first, element->second); } } else { for (auto& element : _monitor) { - AddElement(element.first, element.second); + AddElementToResponse(*response, element.first, element.second); } } - - _adminLock.Unlock(); } - bool Reset(const string& name, Monitor::MetaData& result) + bool Reset(const string& name, Monitor::MetaData& result, bool& operational) { bool found = false; - _adminLock.Lock(); - - std::map::iterator index(_monitor.find(name)); + MonitorObjectContainer::iterator index(_monitor.find(name)); if (index != _monitor.end()) { result = index->second.Measurement(); + operational = index->second.Operational(); index->second.Reset(); found = true; } - _adminLock.Unlock(); - return (found); } @@ -986,17 +977,13 @@ namespace Plugin { { bool found = false; - _adminLock.Lock(); - - std::map::iterator index(_monitor.find(name)); + MonitorObjectContainer::iterator index(_monitor.find(name)); if (index != _monitor.end()) { index->second.Reset(); found = true; } - _adminLock.Unlock(); - return (found); } @@ -1012,10 +999,7 @@ namespace Plugin { uint64_t scheduledTime(Core::Time::Now().Ticks()); uint64_t nextSlot(static_cast(~0)); - // Other methods (like StateChange()) can modify internals of MonitorObjects elements that is not thread safe - _adminLock.Lock(); - - std::map::iterator index(_monitor.begin()); + MonitorObjectContainer::iterator index(_monitor.begin()); // Go through the list of pending observations... while (index != _monitor.end()) { @@ -1036,6 +1020,7 @@ namespace Plugin { const string message("{\"callsign\": \"" + plugin->Callsign() + "\", \"action\": \"Deactivate\", \"reason\": \"" + why.Data() + "\" }"); SYSLOG(Logging::Fatal, (_T("FORCED Shutdown: %s by reason: %s."), plugin->Callsign().c_str(), why.Data())); + _service->Notify(message); _parent.event_action(plugin->Callsign(), "Deactivate", why.Data()); @@ -1055,8 +1040,6 @@ namespace Plugin { index++; } - _adminLock.Unlock(); - if (nextSlot != static_cast(~0)) { if (nextSlot < Core::Time::Now().Ticks()) { _job.Submit(); @@ -1075,16 +1058,20 @@ namespace Plugin { private: template - void translate(const Core::MeasurementType& from, JsonData::Monitor::MeasurementInfo* to) + void translate(const Core::MeasurementType& from, JsonData::Monitor::MeasurementInfo* to) const { + ASSERT(to != nullptr); to->Min = from.Min(); to->Max = from.Max(); to->Average = from.Average(); to->Last = from.Last(); } - Core::CriticalSection _adminLock; - std::map _monitor; + private: + + using MonitorObjectContainer = std::unordered_map; + + MonitorObjectContainer _monitor; Core::WorkerPool::JobType _job; PluginHost::IShell* _service; Monitor& _parent; @@ -1096,18 +1083,13 @@ namespace Plugin { #endif Monitor() : _skipURL(0) - , _monitor(Core::Service::Create(this)) + , _monitor(this) { - RegisterAll(); } #ifdef __WINDOWS__ #pragma warning(default : 4355) #endif - virtual ~Monitor() - { - UnregisterAll(); - _monitor->Release(); - } + ~Monitor() = default; BEGIN_INTERFACE_MAP(Monitor) INTERFACE_ENTRY(PluginHost::IPlugin) @@ -1125,38 +1107,34 @@ namespace Plugin { // If there is an error, return a string describing the issue why the initialisation failed. // The Service object is *NOT* reference counted, lifetime ends if the plugin is deactivated. // The lifetime of the Service object is guaranteed till the deinitialize method is called. - virtual const string Initialize(PluginHost::IShell* service); + const string Initialize(PluginHost::IShell* service) override; // The plugin is unloaded from WPEFramework. This is call allows the module to notify clients // or to persist information if needed. After this call the plugin will unlink from the service path // and be deactivated. The Service object is the same as passed in during the Initialize. // After theis call, the lifetime of the Service object ends. - virtual void Deinitialize(PluginHost::IShell* service); + void Deinitialize(PluginHost::IShell* service) override; // Returns an interface to a JSON struct that can be used to return specific metadata information with respect // to this plugin. This Metadata can be used by the MetData plugin to publish this information to the ouside world. - virtual string Information() const; + string Information() const override; // IWeb methods // ------------------------------------------------------------------------------------------------------- // Whenever a request is received, it might carry some additional data in the body. This method allows // the plugin to attach a deserializable data object (ref counted) to be loaded with any potential found // in the body of the request. - virtual void Inbound(Web::Request& request); + void Inbound(Web::Request& request) override; // If everything is received correctly, the request is passed on to us, through a thread from the thread pool, to // do our thing and to return the result in the response object. Here the actual specific module work, // based on a a request is handled. - virtual Core::ProxyType Process(const Web::Request& request); - - private: - bool Activated(const string& className, const string& callSign, IPlugin* plugin); - bool Deactivated(const string& className, const string& callSign, IPlugin* plugin); + Core::ProxyType Process(const Web::Request& request) override; private: uint8_t _skipURL; Config _config; - MonitorObjects* _monitor; + Core::Sink _monitor; private: void RegisterAll(); diff --git a/Monitor/MonitorJsonRpc.cpp b/Monitor/MonitorJsonRpc.cpp index a269e2fae0..7ab40aa381 100644 --- a/Monitor/MonitorJsonRpc.cpp +++ b/Monitor/MonitorJsonRpc.cpp @@ -53,7 +53,7 @@ namespace Plugin { uint32_t Monitor::endpoint_restartlimits(const RestartlimitsParamsData& params) { const string& callsign = params.Callsign.Value(); - _monitor->Update( + _monitor.Update( callsign, params.Restart.Window.Value(), params.Restart.Limit.Value()); return Core::ERROR_NONE; @@ -67,9 +67,9 @@ namespace Plugin { const string& callsign = params.Callsign.Value(); Core::JSON::ArrayType info; - _monitor->Snapshot(callsign, &info); + _monitor.Snapshot(callsign, &info); if (info.Length() == 1) { - _monitor->Reset(callsign); + _monitor.Reset(callsign); response = info[0]; } return Core::ERROR_NONE; @@ -81,7 +81,7 @@ namespace Plugin { uint32_t Monitor::get_status(const string& index, Core::JSON::ArrayType& response) const { const string& callsign = index; - _monitor->Snapshot(callsign, &response); + _monitor.Snapshot(callsign, &response); return Core::ERROR_NONE; }