Fix the issue that indicator is not updated & ensure UpdateOnce works if we're asleep
[platform/core/uifw/dali-adaptor.git] / adaptors / base / thread-synchronization.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "thread-synchronization.h"
20
21 // INTERNAL INCLUDES
22 #include <base/interfaces/adaptor-internal-services.h>
23 #include <base/thread-synchronization-debug.h>
24
25 namespace Dali
26 {
27
28 namespace Internal
29 {
30
31 namespace Adaptor
32 {
33
34 namespace
35 {
36 const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
37 const int TOTAL_THREAD_COUNT = 3;
38 const unsigned int TRUE = 1u;
39 const unsigned int FALSE = 0u;
40 } // unnamed namespace
41
42 ThreadSynchronization::ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender)
43 : mFrameTime( adaptorInterfaces.GetPlatformAbstractionInterface() ),
44   mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
45   mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
46   mReplaceSurfaceRequest(),
47   mUpdateThreadWaitCondition(),
48   mRenderThreadWaitCondition(),
49   mVSyncThreadWaitCondition(),
50   mEventThreadWaitCondition(),
51   mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
52   mNumberOfVSyncsPerRender( numberOfVSyncsPerRender ),
53   mTryToSleepCount( 0u ),
54   mState( State::STOPPED ),
55   mVSyncAheadOfUpdate( 0u ),
56   mUpdateAheadOfRender( 0u ),
57   mNumberOfThreadsStarted( 0u ),
58   mUpdateThreadResuming( FALSE ),
59   mVSyncThreadRunning( FALSE ),
60   mVSyncThreadStop( FALSE ),
61   mRenderThreadStop( FALSE ),
62   mRenderThreadReplacingSurface( FALSE ),
63   mEventThreadSurfaceReplaced( FALSE ),
64   mVSyncThreadInitialised( FALSE ),
65   mRenderThreadInitialised( FALSE ),
66   mRenderThreadSurfaceReplaced( FALSE )
67 {
68 }
69
70 ThreadSynchronization::~ThreadSynchronization()
71 {
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////////////////////////
75 // EVENT THREAD
76 ///////////////////////////////////////////////////////////////////////////////////////////////////
77
78 void ThreadSynchronization::Initialise()
79 {
80   LOG_EVENT_TRACE;
81
82   ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
83   if( mState == State::STOPPED )
84   {
85     LOG_EVENT( "INITIALISING" );
86     mState = State::INITIALISING;
87   }
88 }
89
90 void ThreadSynchronization::Start()
91 {
92   LOG_EVENT_TRACE;
93
94   bool start = false;
95   {
96     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
97     if( mState == State::INITIALISING )
98     {
99       start = true;
100     }
101   }
102
103   // Not atomic, but does not matter here as we just want to ensure we only start from State::INITIALISING
104   if( start )
105   {
106     LOG_EVENT( "STARTING" );
107     mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
108
109     {
110       ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
111       while( mNumberOfThreadsStarted < TOTAL_THREAD_COUNT )
112       {
113         mEventThreadWaitCondition.Wait( lock );
114       }
115     }
116
117     {
118       ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
119       mState = State::RUNNING;
120     }
121     mUpdateThreadWaitCondition.Notify();
122   }
123 }
124
125 void ThreadSynchronization::Stop()
126 {
127   LOG_EVENT_TRACE;
128
129   bool stop = false;
130   {
131     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
132     if( mState != State::STOPPED )
133     {
134       stop = true;
135       mState = State::STOPPED;
136     }
137   }
138
139   // Not atomic, but does not matter here as we just want to ensure we do not stop more than once
140   if( stop )
141   {
142     LOG_EVENT( "STOPPING" );
143
144     // Notify update-thread so that it continues and sets up the other threads to stop as well
145     mUpdateThreadWaitCondition.Notify();
146
147     mFrameTime.Suspend();
148   }
149 }
150
151 void ThreadSynchronization::Pause()
152 {
153   LOG_EVENT_TRACE;
154
155   bool addPerformanceMarker = false;
156   {
157     // Only pause if we're RUNNING or SLEEPING
158     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
159     if( ( mState == State::RUNNING ) ||
160         ( mState == State::SLEEPING ) )
161     {
162       LOG_EVENT( "PAUSING" );
163
164       mState = State::PAUSED;
165
166       mUpdateThreadResuming = FALSE;
167
168       mFrameTime.Suspend();
169
170       addPerformanceMarker = true;
171     }
172   }
173
174   if( addPerformanceMarker )
175   {
176     // Can lock so we do not want to have a lock when calling this to avoid deadlocks
177     AddPerformanceMarker( PerformanceInterface::PAUSED );
178   }
179 }
180
181 void ThreadSynchronization::Resume()
182 {
183   LOG_EVENT_TRACE;
184
185   // Only resume if we're PAUSED
186   bool resume = false;
187   {
188     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
189     if( mState == State::PAUSED )
190     {
191       resume = true;
192       mState = State::RUNNING;
193       mUpdateThreadResuming = TRUE;
194     }
195   }
196
197   // Not atomic, but does not matter here as we just want to ensure we only resume if we're paused
198   if( resume )
199   {
200     LOG_EVENT( "RESUMING" );
201
202     mFrameTime.Resume();
203
204     // Start up Update thread again
205     mUpdateThreadWaitCondition.Notify();
206
207     // Can lock so we do not want to have a lock when calling this to avoid deadlocks
208     AddPerformanceMarker( PerformanceInterface::RESUME);
209   }
210 }
211
212 void ThreadSynchronization::UpdateRequest()
213 {
214   LOG_EVENT_TRACE;
215
216   bool update = false;
217   {
218     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
219     if( mState == State::SLEEPING )
220     {
221       mState = State::RUNNING;
222       update = true;
223     }
224     mTryToSleepCount = 0;
225   }
226
227   if( update )
228   {
229     LOG_EVENT( "UPDATE REQUEST" );
230     mUpdateThreadWaitCondition.Notify();
231   }
232 }
233
234 void ThreadSynchronization::UpdateOnce()
235 {
236   LOG_EVENT_TRACE;
237   LOG_EVENT( "UPDATE ONCE" );
238
239   // If we're sleeping then change state to running as this will also wake up the v-sync-thread
240   {
241     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
242     if( mState == State::SLEEPING )
243     {
244       mState = State::RUNNING;
245     }
246   }
247
248   mUpdateThreadWaitCondition.Notify();
249 }
250
251 void ThreadSynchronization::ReplaceSurface( RenderSurface* newSurface )
252 {
253   LOG_EVENT_TRACE;
254
255   State::Type previousState( State::STOPPED );
256   {
257     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
258     previousState = mState;
259     mState = State::REPLACING_SURFACE;
260   }
261
262   {
263     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
264     mEventThreadSurfaceReplaced = FALSE;
265   }
266
267   {
268     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
269     mReplaceSurfaceRequest.SetSurface( newSurface );
270     mRenderThreadReplacingSurface = TRUE;
271   }
272
273   // Notify the RenderThread in case it's waiting
274   mRenderThreadWaitCondition.Notify();
275
276   {
277     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
278
279     // Wait for RenderThread to replace the surface
280     while( ! mEventThreadSurfaceReplaced )
281     {
282       LOG_EVENT( "Waiting for Surface to be Replaced" );
283
284       mEventThreadWaitCondition.Wait( lock );
285     }
286   }
287
288   {
289     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
290     mState = previousState;
291   }
292   mUpdateThreadWaitCondition.Notify();
293 }
294
295 void ThreadSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
296 {
297   LOG_EVENT_TRACE;
298   LOG_EVENT( "SET RENDER REFRESH RATE" );
299
300   mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
301 }
302
303 ///////////////////////////////////////////////////////////////////////////////////////////////////
304 // UPDATE THREAD
305 ///////////////////////////////////////////////////////////////////////////////////////////////////
306
307 bool ThreadSynchronization::UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
308 {
309   LOG_UPDATE_TRACE;
310
311   State::Type state = State::STOPPED;
312   {
313     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
314     state = mState;
315   }
316
317   switch( state )
318   {
319     case State::STOPPED:
320     {
321       StopAllThreads();
322       return false; // Stop update-thread
323     }
324
325     case State::INITIALISING:
326     {
327       UpdateInitialising();
328       break;
329     }
330
331     case State::PAUSED:
332     {
333       LOG_UPDATE_TRACE_FMT( "PAUSED" );
334
335       // Just pause the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
336       PauseVSyncThread();
337     }
338     // No break, fall through
339
340     case State::RUNNING:
341     {
342       LOG_UPDATE_TRACE_FMT( "RUNNING" );
343
344       if( IsUpdateThreadResuming() )
345       {
346         LOG_UPDATE( "Restarting VSyncThread" );
347
348         {
349           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
350           mUpdateThreadResuming = FALSE;
351         }
352
353         // Restart the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
354         RunVSyncThread();
355       }
356
357       if( notifyEvent )
358       {
359         LOG_UPDATE( "Notify Event Thread" );
360
361         // Do the notifications first so the event thread can start processing them
362         // Tell the event-thread to wake up (if asleep) and send a notification event to Core
363         mNotificationTrigger.Trigger();
364       }
365
366       // Inform render thread
367       {
368         ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
369         ++mUpdateAheadOfRender;
370         LOG_UPDATE_COUNTER_UPDATE( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
371       }
372       mRenderThreadWaitCondition.Notify();
373
374       // Wait if we've reached the maximum-ahead-of-render count.
375       while( MaximumUpdateAheadOfRenderReached() )
376       {
377         LOG_UPDATE( "Maximum Update Ahead of Render: WAIT" );
378
379         mRenderThreadWaitCondition.Notify(); // Notify the render thread in case it was waiting
380
381         {
382           // Ensure we did not stop while we were waiting previously.
383           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
384           if( mState == State::STOPPED )
385           {
386             break; // Break out of while loop
387           }
388           mUpdateThreadWaitCondition.Wait( updateLock );
389         }
390       }
391
392       // Ensure we have had at least 1 V-Sync before we continue
393       // Ensure we didn't stop while we were previously waiting
394       {
395         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
396         if( ( mState != State::STOPPED ) &&
397             ( mVSyncAheadOfUpdate == 0 ) &&
398             ( !mUpdateThreadResuming ) ) // Ensure we don't wait if the update-thread is JUST resuming
399         {
400           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d) WAIT", mVSyncAheadOfUpdate );
401           mUpdateThreadWaitCondition.Wait( updateLock );
402         }
403         else
404         {
405           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
406         }
407         mVSyncAheadOfUpdate = 0;
408       }
409
410       // Try to sleep if we do not require any more updates
411       UpdateTryToSleep( runUpdate );
412
413       break;
414     }
415
416     case State::SLEEPING:
417     case State::REPLACING_SURFACE:
418     {
419       break;
420     }
421   }
422
423   // Ensure we didn't stop while we were waiting
424   if( IsUpdateThreadStopping() )
425   {
426     // Locks so we shouldn't have a scoped-lock when calling this
427     StopAllThreads();
428     return false; // Stop update-thread
429   }
430
431   // Just wait if we're replacing the surface as the render-thread is busy
432   UpdateWaitIfReplacingSurface();
433
434   mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds );
435
436   return true; // Keep update-thread running
437 }
438
439 ///////////////////////////////////////////////////////////////////////////////////////////////////
440 // RENDER THREAD
441 ///////////////////////////////////////////////////////////////////////////////////////////////////
442
443 bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr )
444 {
445   LOG_RENDER_TRACE;
446
447   if( ! IsRenderThreadReplacingSurface() ) // Call to this function locks so should not be called if we have a scoped-lock
448   {
449     if( ! mRenderThreadInitialised )
450     {
451       LOG_RENDER( "Initialised" );
452
453       mRenderThreadInitialised = TRUE;
454
455       // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
456       NotifyThreadInitialised();
457     }
458     else
459     {
460       if( mRenderThreadSurfaceReplaced )
461       {
462         mRenderThreadSurfaceReplaced = FALSE;
463       }
464       else
465       {
466         // decrement update-ahead-of-render
467         ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
468         --mUpdateAheadOfRender;
469       }
470     }
471
472     // Check if we've had an update, if we haven't then we just wait
473     // Ensure we do not wait if we're supposed to stop
474     {
475       ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
476       if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop )
477       {
478         LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender );
479         mRenderThreadWaitCondition.Wait( renderLock );
480       }
481       else
482       {
483         LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
484       }
485     }
486   }
487   else
488   {
489     LOG_RENDER( "Just Rendered, now Replacing surface" );
490
491     // ... also decrement update-ahead-of-render
492     ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
493     --mUpdateAheadOfRender;
494   }
495
496   // We may have been asked to replace the surface while we were waiting so check again here
497   if( IsRenderThreadReplacingSurface() )
498   {
499     // Replacing surface
500     LOG_RENDER( "REPLACE SURFACE" );
501
502     ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
503     requestPtr = &mReplaceSurfaceRequest;
504     mRenderThreadReplacingSurface = FALSE;
505     mRenderThreadSurfaceReplaced = FALSE;
506   }
507
508   return IsRenderThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
509 }
510
511 void ThreadSynchronization::RenderInformSurfaceReplaced()
512 {
513   LOG_RENDER_TRACE;
514
515   mRenderThreadSurfaceReplaced = TRUE;
516   {
517     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
518     mEventThreadSurfaceReplaced = TRUE;
519   }
520   mEventThreadWaitCondition.Notify();
521 }
522
523 ///////////////////////////////////////////////////////////////////////////////////////////////////
524 // V-SYNC THREAD
525 ///////////////////////////////////////////////////////////////////////////////////////////////////
526
527 bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender )
528 {
529   LOG_VSYNC_TRACE;
530
531   {
532     ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
533     if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender )
534     {
535       numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back
536       mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
537     }
538
539     if( validSync )
540     {
541       mFrameTime.SetSyncTime( frameNumber );
542     }
543   }
544
545   if( ! mVSyncThreadInitialised )
546   {
547     LOG_VSYNC( "Initialised" );
548
549     mVSyncThreadInitialised = TRUE;
550
551     // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
552     NotifyThreadInitialised();
553   }
554   else
555   {
556     // Increment v-sync-ahead-of-update count and inform update-thread
557     {
558       ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
559       ++mVSyncAheadOfUpdate;
560       LOG_VSYNC_COUNTER_VSYNC( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
561     }
562     mUpdateThreadWaitCondition.Notify();
563   }
564
565   // Ensure update-thread has set us to run before continuing
566   // Ensure we do not wait if we're supposed to stop
567   {
568     ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
569     while( ! mVSyncThreadRunning && ! mVSyncThreadStop )
570     {
571       LOG_VSYNC( "WAIT" );
572       mVSyncThreadWaitCondition.Wait( vSyncLock );
573     }
574   }
575
576   return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
577 }
578
579 ///////////////////////////////////////////////////////////////////////////////////////////////////
580 // ALL THREADS: Performance Marker
581 ///////////////////////////////////////////////////////////////////////////////////////////////////
582
583 void ThreadSynchronization::AddPerformanceMarker( PerformanceInterface::MarkerType type )
584 {
585   if( mPerformanceInterface )
586   {
587     mPerformanceInterface->AddMarker( type );
588   }
589 }
590
591 ///////////////////////////////////////////////////////////////////////////////////////////////////
592 //
593 // PRIVATE METHODS
594 //
595 ///////////////////////////////////////////////////////////////////////////////////////////////////
596
597 ///////////////////////////////////////////////////////////////////////////////////////////////////
598 // Called by ALL Threads
599 ///////////////////////////////////////////////////////////////////////////////////////////////////
600
601 void ThreadSynchronization::NotifyThreadInitialised()
602 {
603   {
604     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
605     ++mNumberOfThreadsStarted;
606   }
607   mEventThreadWaitCondition.Notify();
608 }
609
610 ///////////////////////////////////////////////////////////////////////////////////////////////////
611 // Called by Update Thread
612 ///////////////////////////////////////////////////////////////////////////////////////////////////
613
614 void ThreadSynchronization::UpdateInitialising()
615 {
616   LOG_UPDATE_TRACE;
617
618   // Notify event thread that this thread is up and running, locks so we shouldn't have a scoped-lock when calling this
619   NotifyThreadInitialised();
620
621   // Wait for first thread-sync point
622   {
623     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
624
625     while( mState == State::INITIALISING )
626     {
627       mUpdateThreadWaitCondition.Wait( updateLock );
628     }
629   }
630
631   // Locks so we shouldn't have a scoped-lock when calling this
632   RunVSyncThread();
633 }
634
635 void ThreadSynchronization::UpdateTryToSleep( bool runUpdate )
636 {
637   LOG_UPDATE_TRACE;
638
639   if( ! runUpdate &&
640       ! IsUpdateThreadResuming() ) // Locks so we shouldn't have a lock, we shouldn't try to sleep if we're JUST resuming
641   {
642     LOG_UPDATE( "TryToSleep" );
643
644     if( ++mTryToSleepCount >= 3 )
645     {
646       LOG_UPDATE( "Going to sleep" );
647
648       // Locks so we shouldn't have a scoped-lock when calling this
649       PauseVSyncThread();
650
651       // Render thread will automatically wait as it relies on update-ahead-of-render count
652
653       // Change the state
654       {
655         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
656
657         // Ensure we weren't stopped while we have been processing
658         if( mState != State::STOPPED )
659         {
660           mState = State::SLEEPING;
661         }
662       }
663
664       // Inform FrameTime that we're going to sleep
665       mFrameTime.Sleep();
666
667       // Wait while we're SLEEPING
668       {
669         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
670         while( mState == State::SLEEPING )
671         {
672           mUpdateThreadWaitCondition.Wait( updateLock );
673         }
674       }
675
676       ////////////////////////
677       // WAKE UP
678       ////////////////////////
679
680       LOG_UPDATE( "Waking Up" );
681
682       // Clear V-Sync-ahead-of-update-count
683       {
684         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
685         mVSyncAheadOfUpdate = 0;
686       }
687
688       // Restart the v-sync-thread, locks so we shouldn't have a scoped-lock
689       RunVSyncThread();
690
691       // Reset try-to-sleep count
692       mTryToSleepCount = 0;
693
694       // Inform frame timer that we've woken up
695       mFrameTime.WakeUp();
696     }
697   }
698   else
699   {
700     mTryToSleepCount = 0;
701   }
702 }
703
704 void ThreadSynchronization::UpdateWaitIfReplacingSurface()
705 {
706   bool replacingSurface = false;
707   {
708     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
709     replacingSurface = ( mState == State::REPLACING_SURFACE );
710   }
711   while( replacingSurface )
712   {
713     LOG_UPDATE_TRACE_FMT( "REPLACING SURFACE" );
714
715     // Locks so should not be called while we have a scoped-lock
716     PauseVSyncThread();
717
718     // One last check before we actually wait in case the state has changed since we checked earlier
719     {
720       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
721       replacingSurface = ( mState == State::REPLACING_SURFACE );
722       if( replacingSurface )
723       {
724         mUpdateThreadWaitCondition.Wait( updateLock );
725       }
726     }
727
728     {
729       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
730       mVSyncAheadOfUpdate = 0;
731     }
732
733     // Locks so should not be called while we have a scoped-lock
734     RunVSyncThread();
735   }
736 }
737
738 bool ThreadSynchronization::IsUpdateThreadResuming()
739 {
740   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
741   return mUpdateThreadResuming;
742 }
743
744 bool ThreadSynchronization::IsUpdateThreadStopping()
745 {
746   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
747   return ( mState == State::STOPPED );
748 }
749
750 bool ThreadSynchronization::MaximumUpdateAheadOfRenderReached()
751 {
752   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
753   return mUpdateAheadOfRender >= mMaximumUpdateCount;
754 }
755
756 void ThreadSynchronization::StopAllThreads()
757 {
758   LOG_UPDATE_TRACE;
759
760   // Lock so we shouldn't have a scoped-lock when calling these methods
761   StopVSyncThread();
762   StopRenderThread();
763 }
764
765 void ThreadSynchronization::RunVSyncThread()
766 {
767   {
768     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
769     mVSyncThreadRunning = TRUE;
770   }
771   mVSyncThreadWaitCondition.Notify();
772 }
773
774 void ThreadSynchronization::PauseVSyncThread()
775 {
776   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
777   mVSyncThreadRunning = FALSE;
778 }
779
780 void ThreadSynchronization::StopVSyncThread()
781 {
782   {
783     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
784     mVSyncThreadStop = TRUE;
785   }
786   mVSyncThreadWaitCondition.Notify();
787 }
788
789 void ThreadSynchronization::StopRenderThread()
790 {
791   {
792     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
793     mRenderThreadStop = TRUE;
794   }
795   mRenderThreadWaitCondition.Notify();
796 }
797
798 ///////////////////////////////////////////////////////////////////////////////////////////////////
799 // Called by V-Sync Thread
800 ///////////////////////////////////////////////////////////////////////////////////////////////////
801
802 bool ThreadSynchronization::IsVSyncThreadRunning()
803 {
804   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
805   return ! mVSyncThreadStop;
806 }
807
808 ///////////////////////////////////////////////////////////////////////////////////////////////////
809 // Called by Render Thread
810 ///////////////////////////////////////////////////////////////////////////////////////////////////
811
812 bool ThreadSynchronization::IsRenderThreadRunning()
813 {
814   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
815   return ! mRenderThreadStop;
816 }
817
818 bool ThreadSynchronization::IsRenderThreadReplacingSurface()
819 {
820   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
821   return mRenderThreadReplacingSurface;
822 }
823
824 } // namespace Adaptor
825
826 } // namespace Internal
827
828 } // namespace Dali