[asterisk-scf-commits] asterisk-scf/integration/util-cpp.git branch "route_replica" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Sat Apr 16 21:14:38 CDT 2011


branch "route_replica" has been updated
       via  d2ea2f1f04fd9ad34552d5c79f806d2b9bd952af (commit)
      from  841b6f6da15190289390c5b4ba900793a497dc7f (commit)

Summary of changes:
 .../AsteriskSCF/StateMachine/SimpleStateMachine.h  |  108 ++++++++++++++++----
 1 files changed, 87 insertions(+), 21 deletions(-)


- Log -----------------------------------------------------------------
commit d2ea2f1f04fd9ad34552d5c79f806d2b9bd952af
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Sat Apr 16 21:12:38 2011 -0500

    Added thread safety for execute() operation.

diff --git a/StateMachine/include/AsteriskSCF/StateMachine/SimpleStateMachine.h b/StateMachine/include/AsteriskSCF/StateMachine/SimpleStateMachine.h
index 538c941..673c93b 100644
--- a/StateMachine/include/AsteriskSCF/StateMachine/SimpleStateMachine.h
+++ b/StateMachine/include/AsteriskSCF/StateMachine/SimpleStateMachine.h
@@ -15,6 +15,7 @@
  */
 #pragma once
 
+#include <boost/thread.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/function.hpp>
 #include <map>
@@ -26,13 +27,12 @@ namespace StateMachine
 {
 
 /**
- * A simple state machine. User's provide a definition of the state type (probably an enum type) and 
- * a type that can be executed using operator() to handle execution for a given state. 
+ * A simple state machine. User's provide a definition of the enum type that defines the
+ * valid states. 
  * A listener interface is provided to allow monitoring state changes and state execution. 
- *   - typename S State type
- *   - typename F An executable operation for state handler
+ *   - typename S Enum type that identifies all valid states.
  */
-template<typename S, typename F>
+template<typename S>
 class SimpleStateMachine 
 {
 public:
@@ -40,7 +40,6 @@ public:
     /** 
      * Listener interface for monitoring the state machine. 
      */
-
     class StateMachineListener
     {
     public:
@@ -48,21 +47,37 @@ public:
         virtual void stateExecutionStart(S state) = 0;
         virtual void stateExecutionComplete(S state) = 0;
         virtual void stateTransition(S oldState, S newState) = 0;
+        virtual void shutdown() = 0;
 
     protected:
         StateMachineListener() {}
     };
 
-    //typedef StateMachineListener<S> StateMachineListenerType;
+    /**
+     * RAII setter for a boolean. 
+     */
+    class ExecutionGuard
+    {
+    public:
+        ExecutionGuard(bool &val) : mGuard(val) {mGuard = true;}
+        ~ExecutionGuard() {mGuard = false;}
+
+    private:
+        bool &mGuard;
+    };
 
 public:
     /**
      * Constructor. 
      *  @param defaultState The default state for the state machine. 
      */
-    SimpleStateMachine(S defaultState)
+    SimpleStateMachine(S defaultState) 
+            : mCurrentState(defaultState),
+              mNextState(defaultState),
+              mShutdown(false),
+              mInExecution(false)
+                         
     {
-        mCurrentState = mNextState = defaultState;
     }
 
     ~SimpleStateMachine()
@@ -87,7 +102,7 @@ public:
     /** 
      * Sets the execution handler for a given state. 
      */
-    void addState(S state, const F& handler)
+    void addState(S state, const boost::function<void ()>& handler)
     {
         mStates[state] = handler;
     }
@@ -105,10 +120,14 @@ public:
      */
     void execute()
     {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+
+        ExecutionGuard guard(mInExecution);
+
         // Notify all listeners that execution is starting.
         sendExecutionStartNotice(mCurrentState);
 
-        std::map<S, F>::iterator it = mStates.find(mCurrentState);
+        std::map<S, boost::function<void ()> >::iterator it = mStates.find(mCurrentState);
         if (it != mStates.end())
         {
             // Execute
@@ -125,8 +144,31 @@ public:
             sendTransitionNotice(mCurrentState, mNextState);
             mCurrentState = mNextState;
         }
+
+        if (mShutdown)
+        {
+            // Send shutdown notice to the listeners. 
+            sendShutdownNotice();
+        }
     }
 
+    /**
+     * Shutdown the state machine. 
+     */
+    void shutdown()
+    {
+        // If we being called as a result of state execution (as expected),
+        // mark the state machine for shutdown, and let execution() handle it. 
+        if (mInExecution)
+        {
+            mShutdown = true;
+        }
+        else
+        {
+            // Send shutdown notice to the listeners. 
+            sendShutdownNotice();
+        }
+    }
 
 private: 
 
@@ -146,9 +188,6 @@ private:
             {
                 x->stateExecutionStart(mState);
             }
-            catch(const Ice::Exception&)
-            {
-            }
             catch(...)
             {
             }
@@ -181,9 +220,6 @@ private:
             {
                 x->stateExecutionComplete(mState);
             }
-            catch(const Ice::Exception&)
-            {
-            }
             catch(...)
             {
             }
@@ -215,9 +251,6 @@ private:
             {
                 x->stateTransition(mOldState, mNewState);
             }
-            catch(const Ice::Exception&)
-            {
-            }
             catch(...)
             {
             }
@@ -234,11 +267,44 @@ private:
          std::for_each(mListeners.begin(), mListeners.end(), TransitionNotice<S> (oldState, newState));
     }
 
+    /**
+     * Functor for forwarding shutdown() notices.
+     */
+    template<typename S> 
+    class ShutdownNotice
+    {
+        // Types: S - State
+    public:
+        ShutdownNotice()  {}
+        ~ShutdownNotice() {}
+        void operator() (boost::shared_ptr<StateMachineListener >& x)
+        {
+            try
+            {
+                x->shutdown();
+            }
+            catch(...)
+            {
+            }
+        }
+    };
+
+    /** 
+     * Forward the state transition notice to all registered listeners.
+     */
+    void sendShutdownNotice()
+    {
+         std::for_each(mListeners.begin(), mListeners.end(), ShutdownNotice<S> ());
+    }
+
     /// Class state
 
-    std::map<S, F> mStates;
+    std::map<S, boost::function<void ()> > mStates;
     S mCurrentState;
     S mNextState;
+    bool mShutdown;
+    bool mInExecution;
+    boost::shared_mutex mLock;
     std::vector<boost::shared_ptr<StateMachineListener > > mListeners;
 };
 

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/util-cpp.git



More information about the asterisk-scf-commits mailing list