diff options
author | Larina DSouza <larsouza@in.ibm.com> | 2012-03-20 00:32:52 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-04-24 09:40:04 -0500 |
commit | 5ac7921a5f77d7d33e7cc86f91522de4751f98b0 (patch) | |
tree | 24d6148d99b05f351bcff1a1ad633365cc724532 | |
parent | 85b30189df1a0c9cffb0a83900c62a78780b5521 (diff) | |
download | talos-hostboot-5ac7921a5f77d7d33e7cc86f91522de4751f98b0.tar.gz talos-hostboot-5ac7921a5f77d7d33e7cc86f91522de4751f98b0.zip |
Initial commit of the Maintenance Cmd Monitor with unit test file.
RTC: 22610
Change-Id: I6e08afda4d658bccf2baa15830dd366a187b54b1
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/775
Tested-by: Jenkins Server
Reviewed-by: Bradley W. Bishop <bradleyb@us.ibm.com>
Reviewed-by: Zane Shelley <zshelle@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
-rw-r--r-- | src/usr/diag/mdia/makefile | 2 | ||||
-rw-r--r-- | src/usr/diag/mdia/mdiafwd.H | 1 | ||||
-rwxr-xr-x | src/usr/diag/mdia/mdiamonitor.C | 278 | ||||
-rwxr-xr-x | src/usr/diag/mdia/mdiamonitor.H | 181 | ||||
-rw-r--r-- | src/usr/diag/mdia/mdiasm.H | 10 | ||||
-rw-r--r-- | src/usr/diag/mdia/test/mdiatestmonitor.H | 206 |
6 files changed, 676 insertions, 2 deletions
diff --git a/src/usr/diag/mdia/makefile b/src/usr/diag/mdia/makefile index 23600acf1..1cd9e0dc2 100644 --- a/src/usr/diag/mdia/makefile +++ b/src/usr/diag/mdia/makefile @@ -26,7 +26,7 @@ EXTRAINCDIR += ${ROOTPATH}/src/include/usr/diag MODULE = mdia -OBJS = mdiatrace.o mdiaworkitem.o +OBJS = mdiamonitor.o mdiatrace.o mdiaworkitem.o SUBDIRS = test.d diff --git a/src/usr/diag/mdia/mdiafwd.H b/src/usr/diag/mdia/mdiafwd.H index bb7efb98a..8763dbcd2 100644 --- a/src/usr/diag/mdia/mdiafwd.H +++ b/src/usr/diag/mdia/mdiafwd.H @@ -34,6 +34,7 @@ /** * @brief forwards */ +class MdiaCommandMonitorTest; namespace MDIA { diff --git a/src/usr/diag/mdia/mdiamonitor.C b/src/usr/diag/mdia/mdiamonitor.C new file mode 100755 index 000000000..17ed1a942 --- /dev/null +++ b/src/usr/diag/mdia/mdiamonitor.C @@ -0,0 +1,278 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/diag/mdia/mdiamonitor.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include <sys/time.h> +#include <targeting/util.H> +#include <vector> +#include "mdiamonitor.H" +#include "mdiasm.H" + +namespace MDIA +{ + +uint64_t CommandMonitor::addMonitor(uint64_t i_to) +{ + uint64_t monitor = 0; + + mutex_lock(&iv_mutex); + + monitor = ++iv_nextMonitor; + + // add a new monitor to our map + + iv_monitors[monitor] = i_to; + + mutex_unlock(&iv_mutex); + + return monitor; +} + +void CommandMonitor::removeMonitor(uint64_t i_monitor) +{ + mutex_lock(&iv_mutex); + + // remove the specified monitor + + iv_monitors.erase(i_monitor); + + mutex_unlock(&iv_mutex); +} + +tid_t CommandMonitor::getTID() +{ + tid_t tid = 0; + + mutex_lock(&iv_mutex); + + tid = iv_tid; + + mutex_unlock(&iv_mutex); + + return tid; +} + +bool CommandMonitor::isShutdown() +{ + bool shutdown = false; + + mutex_lock(&iv_mutex); + + shutdown = iv_shutdown; + + mutex_unlock(&iv_mutex); + + return shutdown; +} + +uint64_t CommandMonitor::getMonitorID() +{ + uint64_t monitor = 0; + + mutex_lock(&iv_mutex); + + monitor = iv_nextMonitor; + + mutex_unlock(&iv_mutex); + + return monitor; +} + +uint64_t CommandMonitor::getMonitorMapTimeoutEntry(uint64_t i_monitor) +{ + uint64_t timeout = 0; + + mutex_lock(&iv_mutex); + + timeout = iv_monitors[i_monitor]; + + mutex_unlock(&iv_mutex); + + return timeout; +} + +void CommandMonitor::threadMain(StateMachine & i_sm) +{ + static const uint64_t singleStepPauseSecs = 0; + static const uint64_t singleStepPauseNSecs = 10000000; + static uint64_t wakeupIntervalNanoSecs = 0; + + // periodically wakeup and check for any command + // timeouts + + if(TARGETING::is_vpo()) + { + wakeupIntervalNanoSecs = TEN_CTX_SWITCHES_NS; + } + else + { + wakeupIntervalNanoSecs = singleStepPauseNSecs; + } + + bool shutdown = false, callbackNeeded = false; + std::vector<uint64_t> monitorsTimedout; + + while(true) + { + if( TARGETING::is_vpo() ) + { + nanosleep(0, wakeupIntervalNanoSecs); + } + else + { + // sleep for 10 ms + nanosleep(singleStepPauseSecs, wakeupIntervalNanoSecs); + } + + mutex_lock(&iv_mutex); + + // check to see if the istep is finished + + shutdown = iv_shutdown; + + if(!shutdown) + { + // scan the monitor map and if any + // timed out, inform the state machine + + iterator it = iv_monitors.begin(); + + while(it != iv_monitors.end()) + { + if(it->second >= wakeupIntervalNanoSecs) + { + it->second -= wakeupIntervalNanoSecs; + it++; + } + + else + { + callbackNeeded = true; + monitorsTimedout.push_back(it->first); + + // remove the monitor + + iv_monitors.erase(it++); + } + } + } + + mutex_unlock(&iv_mutex); + + if(callbackNeeded) + { + i_sm.processCommandTimeout(monitorsTimedout); + callbackNeeded = false; + } + + // istep finished...shutdown + + if(shutdown) + break; + } +} + +namespace CommandMonitorImpl +{ +struct ThreadArgs +{ + CommandMonitor * obj; + StateMachine * sm; +}; +} + +void CommandMonitor::start(StateMachine & i_sm) +{ + using namespace CommandMonitorImpl; + + // start the monitor thread + + mutex_lock(&iv_mutex); + + // no-op if already started + + if(!iv_tid) + { + ThreadArgs * args = new ThreadArgs; + if(NULL != args) + { + args->obj = this; + args->sm = &i_sm; + + iv_shutdown = false; + iv_tid = task_create(&CommandMonitor::staticMain, args); + + } + } + + mutex_unlock(&iv_mutex); +} + +void CommandMonitor::shutdown() +{ + mutex_lock(&iv_mutex); + + // instruct the monitor thread to shutdown + + iv_shutdown = true; + + // wait for it to exit + // unless it was stopped already + + tid_t tid = iv_tid; + iv_tid = 0; + + mutex_unlock(&iv_mutex); + + if(tid) + task_wait_tid(tid, 0, 0); +} + +void CommandMonitor::staticMain(void * i_args) +{ + using namespace CommandMonitorImpl; + + if(NULL != i_args) + { + ThreadArgs * args = static_cast<ThreadArgs *>(i_args); + + args->obj->threadMain(*args->sm); + + delete args; + args = NULL; + } +} + +CommandMonitor::CommandMonitor() : + iv_tid(0), + iv_shutdown(false), + iv_nextMonitor(0) +{ + mutex_init(&iv_mutex); +} + +CommandMonitor::~CommandMonitor() +{ + shutdown(); + + mutex_destroy(&iv_mutex); +} +} diff --git a/src/usr/diag/mdia/mdiamonitor.H b/src/usr/diag/mdia/mdiamonitor.H new file mode 100755 index 000000000..8a955dda9 --- /dev/null +++ b/src/usr/diag/mdia/mdiamonitor.H @@ -0,0 +1,181 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/diag/mdia/mdiamonitor.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __MSS_MEMDIAG_MDIAMONITOR_H +#define __MSS_MEMDIAG_MDIAMONITOR_H + +#include <map> +#include <sys/sync.h> +#include <sys/task.h> +#include <stdint.h> +#include "mdiafwd.H" + +/** + * @file mdiamonitor.H + * @brief mdia Maintenance Command Monitor + */ + +namespace MDIA +{ + +/** + * @brief maint command timeout monitor + * + * provides an interface for the workflow state machine + * to register / unregister for a monitor and receive a callback + * if the monitor times out. when the state machine callback is + * made the monitor is automatically removed + */ +class CommandMonitor +{ + public: + /** + * @brief add a new monitor with specified timeout value + * + * @param[in] i_to Maint Cmd timeout value + * + * @retval Monitor ID + */ + uint64_t addMonitor(uint64_t i_to); + + /** + * @brief remove a monitor + * + * @param[in] i_monitor MonitorMap's key, monitor ID + */ + void removeMonitor(uint64_t i_monitor); + + /** + * @brief start the thread up, specify callback + * + * @param[in] i_sm state machine to which call is made + */ + void start(StateMachine & i_sm); + + /** + * @brief shut the thread down + */ + void shutdown(); + + /** + * @brief ctor + */ + CommandMonitor(); + + /** + * @brief dtor + */ + ~CommandMonitor(); + + private: + + /** + * @brief main thread function + */ + static void staticMain(void *); + + /** + * @brief main thread function + * + * @param[in] i_sm state machine provided for callback + */ + void threadMain(StateMachine & i_sm); + + /** + * @brief Get the thread id + * + * @retval ThreadID of CommandMonitor + */ + tid_t getTID(); + + /** + * @brief Is the CommandMonitor shut down + * + * @retval true if shutdown + * false if not shutdown + */ + bool isShutdown(); + + /** + * @brief Get the monitor id counter + * + * @retval Monitor ID counter + */ + uint64_t getMonitorID(); + + /** + * @brief Get MonitorMap Timeout entry + * + * @param[in] i_monitor Monitor ID + * + * @retval Timeout value associated with monitor ID i_monitor + */ + uint64_t getMonitorMapTimeoutEntry(uint64_t i_monitor); + + /** + * @brief serialization mutex + */ + mutex_t iv_mutex; + + /** + * @brief thread number + */ + tid_t iv_tid; + + /** + * @brief shutdown request indicator + */ + bool iv_shutdown; + + /** + * @brief monitor ID counter + */ + uint64_t iv_nextMonitor; + + /** + * @brief aliases. Map containing monitorID key and timeout entries. + */ + typedef std::map<uint64_t, uint64_t> MonitorMap; + typedef MonitorMap::iterator iterator; + + /** + * @brief maint command monitors + */ + MonitorMap iv_monitors; + + /** + * @brief copy disabled + */ + CommandMonitor(const CommandMonitor &); + + /** + * @brief assignment disabled + */ + CommandMonitor & operator=(const CommandMonitor &); + + /** + * @brief friend class + */ + friend class ::MdiaCommandMonitorTest; +}; +} +#endif diff --git a/src/usr/diag/mdia/mdiasm.H b/src/usr/diag/mdia/mdiasm.H index b320f72f6..e83acf89b 100644 --- a/src/usr/diag/mdia/mdiasm.H +++ b/src/usr/diag/mdia/mdiasm.H @@ -49,6 +49,14 @@ class StateMachine void executeWorkItem(TARGETING::TargetHandle_t i_target, WorkFlowPhase i_phase) {} /** + * @brief used by Maint cmd monitor to notify that + * maint cmd timed out - called in monitor thread context + * + * @param[in] i_monitorIDs Vector of monitorIDs + */ + virtual void processCommandTimeout(std::vector<uint64_t> i_monitorIDs) {} + + /** * @brief ctor */ StateMachine() {} @@ -56,7 +64,7 @@ class StateMachine /** * @brief dtor */ - ~StateMachine() {} + virtual ~StateMachine() {} private: diff --git a/src/usr/diag/mdia/test/mdiatestmonitor.H b/src/usr/diag/mdia/test/mdiatestmonitor.H new file mode 100644 index 000000000..db491f22b --- /dev/null +++ b/src/usr/diag/mdia/test/mdiatestmonitor.H @@ -0,0 +1,206 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/diag/mdia/test/mdiatestmonitor.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#ifndef __TEST_MDIATESTMONITOR_H +#define __TEST_MDIATESTMONITOR_H + +#include <cxxtest/TestSuite.H> +#include <sys/task.h> +#include <sys/time.h> +#include <stdint.h> +#include <targeting/util.H> +#include "../mdiafwd.H" +#include "../mdiamonitor.H" +#include "../mdiasm.H" + +using namespace MDIA; + +class MdiaStateMachineTest: public StateMachine +{ + public: + void processCommandTimeout(std::vector<uint64_t>) + { + iv_processedTimeout = true; + } + + bool timeoutProcessed() + { + return iv_processedTimeout; + } + + MdiaStateMachineTest() : iv_processedTimeout(false) {} + + ~MdiaStateMachineTest() + { + iv_processedTimeout = false; + } + + private: + + bool iv_processedTimeout; +}; + +class MdiaCommandMonitorTest: public CxxTest::TestSuite +{ + public: + void testCommandMonitor(void) + { + + CommandMonitor l_cm; + do + { + if( 0 != l_cm.getTID()) + { + TS_FAIL("Thread id != 0"); + break; + } + else if(true == l_cm.isShutdown()) + { + TS_FAIL("Var iv_shutdown != false"); + break; + } + else if(0 != l_cm.getMonitorID()) + { + TS_FAIL("Monitor ID counter != 0"); + break; + } + else + { + TS_TRACE("SUCCESS:Dflt CommandMonitor ctor"); + } + }while(0); + } + + void teststart(void) + { + tid_t l_tid = 0; + StateMachine l_sm; + CommandMonitor* l_cm1 = new CommandMonitor(); + l_cm1->start(l_sm); + l_tid = l_cm1->getTID(); + if(0 == l_cm1->getTID()) + { + TS_FAIL("Command Monitor task not started"); + } + else + { + l_cm1->start(l_sm); + if(l_tid != l_cm1->getTID()) + { + TS_FAIL("Command Monitor task started again"); + } + else + { + TS_TRACE("SUCCESS: CommandMonitor::start"); + } + } + + delete l_cm1; + l_cm1 = NULL; + } + + void testaddMonitor(void) + { + uint64_t l_timeout = 10; + CommandMonitor l_cm1; + uint64_t l_mon = l_cm1.addMonitor(l_timeout); + if(1 != l_mon) + { + TS_FAIL("Key monitor ID not set corretly"); + } + else + { + l_mon = l_cm1.addMonitor(++l_timeout); + + if(l_timeout != l_cm1.getMonitorMapTimeoutEntry(l_mon)) + { + TS_FAIL("Map entries not set right"); + } + else + { + TS_TRACE("SUCCESS: CommandMonitor::addMonitor"); + } + } + } + + void testthreadMainTimeout(void) + { + uint64_t timeoutNanosecs = 10000000; + MdiaStateMachineTest l_sm; + CommandMonitor l_cm; + l_cm.start(l_sm); + l_cm.addMonitor(timeoutNanosecs); + l_cm.addMonitor(timeoutNanosecs); + if( TARGETING::is_vpo() ) + { + nanosleep(0, TEN_CTX_SWITCHES_NS); + } + else + { + //sleep for 100ms + nanosleep(0, 100000000); + } + if(true != l_sm.timeoutProcessed()) + { + TS_FAIL("Not a timeout"); + } + else + { + TS_TRACE("SUCCESS: testthreadMainTimeout"); + } + } + + void testremoveMonitor(void) + { + uint64_t l_timeout = 20; + CommandMonitor l_cm1; + l_cm1.addMonitor(l_timeout); + l_cm1.addMonitor(++l_timeout); + l_cm1.removeMonitor(2); + if(0 != l_cm1.getMonitorMapTimeoutEntry(2)) + { + TS_FAIL("Map entry not removed"); + } + else + { + TS_TRACE("SUCCESS: CommandMonitor::removeMonitor"); + } + } + + void testshutdown(void) + { + StateMachine l_sm; + CommandMonitor l_cm; + l_cm.start(l_sm); + l_cm.shutdown(); + if(false == l_cm.isShutdown() && (0 != l_cm.getTID())) + { + TS_FAIL("Command Monitor not shutdown"); + } + else + { + TS_TRACE("SUCCESS: CommandMonitor::shutdown"); + } + } + +}; +#endif |