[vlmc-devel] ClipWorkflow: Rework the state locking model

Hugo Beauzée-Luyssen git at videolan.org
Sun Jan 26 22:08:42 CET 2014


vlmc | branch: master | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | Sat Jan 25 17:35:03 2014 +0200| [c5e0682bf95805d7c5bd1cb794d06a68dfe60a6a] | committer: Hugo Beauzée-Luyssen

ClipWorkflow: Rework the state locking model

> http://git.videolan.org/gitweb.cgi/vlmc.git/?a=commit;h=c5e0682bf95805d7c5bd1cb794d06a68dfe60a6a
---

 src/Workflow/ClipWorkflow.cpp  |   45 +++++++++++++++---------------------
 src/Workflow/ClipWorkflow.h    |   18 +++++----------
 src/Workflow/TrackWorkflow.cpp |   50 +++++++++++-----------------------------
 3 files changed, 39 insertions(+), 74 deletions(-)

diff --git a/src/Workflow/ClipWorkflow.cpp b/src/Workflow/ClipWorkflow.cpp
index 3fc5ee6..80020c4 100644
--- a/src/Workflow/ClipWorkflow.cpp
+++ b/src/Workflow/ClipWorkflow.cpp
@@ -58,7 +58,8 @@ ClipWorkflow::~ClipWorkflow()
 void
 ClipWorkflow::initialize()
 {
-    setState( ClipWorkflow::Initializing );
+    QWriteLocker lock( m_stateLock );
+    m_state = ClipWorkflow::Initializing;
 
     m_vlcMedia = new LibVLCpp::Media( m_clipHelper->clip()->getMedia()->mrl() );
     initializeVlcOutput();
@@ -112,7 +113,7 @@ ClipWorkflow::getState() const
 void
 ClipWorkflow::clipEndReached()
 {
-    setState( EndReached );
+    m_state = EndReached;
 }
 
 void
@@ -164,19 +165,6 @@ ClipWorkflow::setTime( qint64 time )
     }
 }
 
-void
-ClipWorkflow::setState( State state )
-{
-    QWriteLocker    lock( m_stateLock );
-    m_state = state;
-}
-
-QReadWriteLock*
-ClipWorkflow::getStateLock()
-{
-    return m_stateLock;
-}
-
 bool
 ClipWorkflow::waitForCompleteInit()
 {
@@ -211,8 +199,10 @@ ClipWorkflow::postGetOutput()
         if ( m_state == ClipWorkflow::Paused )
         {
             m_state = ClipWorkflow::UnpauseRequired;
-//            This will act like an "unpause";
+            //This will act like an "unpause";
             m_mediaPlayer->pause();
+            // Since we use DirectConnection for mediaPlayerUnpaused(), the media player should be
+            // "Rendering" at this point.
         }
     }
 }
@@ -224,8 +214,11 @@ ClipWorkflow::commonUnlock()
     //no one is available : we would spawn a new buffer, thus modifying the number of available buffers
     if ( getNbComputedBuffers() >= getMaxComputedBuffers() )
     {
-        setState( ClipWorkflow::PauseRequired );
+        QWriteLocker lock( m_stateLock );
+        m_state = ClipWorkflow::PauseRequired;
         m_mediaPlayer->pause();
+        // Since we use DirectConnection for mediaPlayerPaused(), the media player should be
+        // "Paused" at this point.
     }
 }
 
@@ -247,14 +240,14 @@ ClipWorkflow::computePtsDiff( qint64 pts )
 void
 ClipWorkflow::mediaPlayerPaused()
 {
-    setState( ClipWorkflow::Paused );
+    m_state = ClipWorkflow::Paused;
     m_beginPausePts = mdate();
 }
 
 void
 ClipWorkflow::mediaPlayerUnpaused()
 {
-    setState( ClipWorkflow::Rendering );
+    m_state = ClipWorkflow::Rendering;
     m_pauseDuration = mdate() - m_beginPausePts;
 }
 
@@ -276,13 +269,13 @@ void
 ClipWorkflow::mute()
 {
     stop();
-    setState( Muted );
+    m_state = Muted;
 }
 
 void
 ClipWorkflow::unmute()
 {
-    setState( Stopped );
+    m_state = Stopped;
 }
 
 void
@@ -306,17 +299,17 @@ void
 ClipWorkflow::errorEncountered()
 {
     stopRenderer();
-    setState( Error );
+    m_state = Error;
     emit error();
 }
 
 bool
 ClipWorkflow::shouldRender() const
 {
-    QReadLocker lock( m_stateLock );
-    return ( m_state != ClipWorkflow::Error &&
-             m_state != ClipWorkflow::Stopped &&
-             m_state != ClipWorkflow::Stopping );
+    ClipWorkflow::State state = getState();
+    return ( state != ClipWorkflow::Error &&
+             state != ClipWorkflow::Stopped &&
+             state != ClipWorkflow::Stopping );
 }
 
 void
diff --git a/src/Workflow/ClipWorkflow.h b/src/Workflow/ClipWorkflow.h
index 4f86922..7fa1afc 100644
--- a/src/Workflow/ClipWorkflow.h
+++ b/src/Workflow/ClipWorkflow.h
@@ -74,7 +74,7 @@ class   ClipWorkflow : public EffectUser
             /// \brief  Used when end is reached, IE no more frame has to be rendered, but the trackworkflow
             ///         may eventually ask for some.
             EndReached,         //4
-            // Here starts internal states :
+            // Here start internal states :
             /// \brief  This state will be used when an unpause
             ///         has been required
             UnpauseRequired,    //5
@@ -135,9 +135,6 @@ class   ClipWorkflow : public EffectUser
 
         /**
          *  Returns the current workflow state.
-         *  Be carrefull, as this function is NOT thread safe, and return the
-         *  state without locking the state.
-         *  It's your job to do it, by calling the getStateLock() method.
          */
         State                   getState() const;
 
@@ -175,13 +172,6 @@ class   ClipWorkflow : public EffectUser
          */
         void                    queryStateChange( State newState );
 
-        /**
-         *  This returns the QReadWriteLock that protects the ClipWorkflow's state.
-         *  It should be use to lock the value when checking states from outside this
-         *  class.
-         */
-        QReadWriteLock*         getStateLock();
-
         bool                    waitForCompleteInit();
 
         virtual void*           getLockCallback() const = 0;
@@ -218,7 +208,6 @@ class   ClipWorkflow : public EffectUser
         virtual Type            effectType() const;
 
     private:
-        void                    setState( State state );
         void                    adjustBegin();
 
     protected:
@@ -244,6 +233,11 @@ class   ClipWorkflow : public EffectUser
         virtual void            releasePrealocated() = 0;
 
     private:
+        /**
+         * @brief m_initWaitCond Used to synchronize initialization.
+         *
+         * The associated lock is m_stateLock
+         */
         QWaitCondition          *m_initWaitCond;
         /**
          *  \brief              Used by the trackworkflow to query a clipworkflow resync.
diff --git a/src/Workflow/TrackWorkflow.cpp b/src/Workflow/TrackWorkflow.cpp
index 88d84d5..61712ed 100644
--- a/src/Workflow/TrackWorkflow.cpp
+++ b/src/Workflow/TrackWorkflow.cpp
@@ -176,21 +176,18 @@ TrackWorkflow::renderClip( ClipWorkflow* cw, qint64 currentFrame,
     ClipWorkflow::GetMode       mode = ( paused == false || renderOneFrame == true ?
                                          ClipWorkflow::Pop : ClipWorkflow::Get );
 
-    cw->getStateLock()->lockForRead();
-    if ( cw->getState() == ClipWorkflow::Rendering ||
-         cw->getState() == ClipWorkflow::Paused ||
-         cw->getState() == ClipWorkflow::PauseRequired ||
-         cw->getState() == ClipWorkflow::UnpauseRequired )
+    ClipWorkflow::State state = cw->getState();
+    if ( state == ClipWorkflow::Rendering ||
+         state == ClipWorkflow::Paused ||
+         state == ClipWorkflow::PauseRequired ||
+         state == ClipWorkflow::UnpauseRequired )
     {
-        cw->getStateLock()->unlock();
-
         if ( cw->isResyncRequired() == true || needRepositioning == true )
             adjustClipTime( currentFrame, start, cw );
         return cw->getOutput( mode, currentFrame - start );
     }
-    else if ( cw->getState() == ClipWorkflow::Stopped )
+    else if ( state == ClipWorkflow::Stopped )
     {
-        cw->getStateLock()->unlock();
         cw->initialize();
         //If the init failed, don't even try to call getOutput.
         if ( cw->waitForCompleteInit() == false )
@@ -203,17 +200,15 @@ TrackWorkflow::renderClip( ClipWorkflow* cw, qint64 currentFrame,
         }
         return cw->getOutput( mode, currentFrame - start );
     }
-    else if ( cw->getState() == ClipWorkflow::EndReached ||
-              cw->getState() == ClipWorkflow::Muted ||
-              cw->getState() == ClipWorkflow::Error )
+    else if ( state == ClipWorkflow::EndReached ||
+              state == ClipWorkflow::Muted ||
+              state == ClipWorkflow::Error )
     {
-        cw->getStateLock()->unlock();
         //The stopClipWorkflow() method will take care of that.
     }
     else
     {
-        qCritical() << "Unexpected state:" << cw->getState();
-        cw->getStateLock()->unlock();
+        qCritical() << "Unexpected state:" << state;
     }
     return NULL;
 }
@@ -221,31 +216,18 @@ TrackWorkflow::renderClip( ClipWorkflow* cw, qint64 currentFrame,
 void
 TrackWorkflow::preloadClip( ClipWorkflow* cw )
 {
-    cw->getStateLock()->lockForRead();
-
     if ( cw->getState() == ClipWorkflow::Stopped )
-    {
-        cw->getStateLock()->unlock();
         cw->initialize();
-        return ;
-    }
-    cw->getStateLock()->unlock();
 }
 
 void
 TrackWorkflow::stopClipWorkflow( ClipWorkflow* cw )
 {
 //    qDebug() << "Stopping clip workflow";
-    cw->getStateLock()->lockForRead();
-
     if ( cw->getState() == ClipWorkflow::Stopped ||
          cw->getState() == ClipWorkflow::Muted ||
          cw->getState() == ClipWorkflow::Error )
-    {
-        cw->getStateLock()->unlock();
         return ;
-    }
-    cw->getStateLock()->unlock();
     cw->stop();
 }
 
@@ -259,7 +241,6 @@ TrackWorkflow::hasNoMoreFrameToRender( qint64 currentFrame ) const
     ClipWorkflow* cw = it.value();
     //Check if the Clip is in error state. If so, don't bother checking anything else.
     {
-        QReadLocker     lock( cw->getStateLock() );
         if ( cw->getState() == ClipWorkflow::Error )
             return true;
     }
@@ -632,16 +613,13 @@ TrackWorkflow::stopFrameComputing()
     {
         ClipWorkflow*   cw = it.value();
 
-        cw->getStateLock()->lockForRead();
-
-        if ( cw->getState() == ClipWorkflow::Stopped ||
-             cw->getState() == ClipWorkflow::Muted ||
-             cw->getState() == ClipWorkflow::Error )
+        ClipWorkflow::State state = cw->getState();
+        if ( state == ClipWorkflow::Stopped ||
+             state == ClipWorkflow::Muted ||
+             state == ClipWorkflow::Error )
         {
-            cw->getStateLock()->unlock();
             return ;
         }
-        cw->getStateLock()->unlock();
         cw->stopRenderer();
         ++it;
     }



More information about the Vlmc-devel mailing list