8a27ecb84d69ab9378eba2f7da333c5a921d1a5d
[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   mUpdateThreadWaitCondition.Notify();
240 }
241
242 void ThreadSynchronization::ReplaceSurface( RenderSurface* newSurface )
243 {
244   LOG_EVENT_TRACE;
245
246   State::Type previousState( State::STOPPED );
247   {
248     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
249     previousState = mState;
250     mState = State::REPLACING_SURFACE;
251   }
252
253   {
254     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
255     mEventThreadSurfaceReplaced = FALSE;
256   }
257
258   {
259     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
260     mReplaceSurfaceRequest.SetSurface( newSurface );
261     mRenderThreadReplacingSurface = TRUE;
262   }
263
264   // Notify the RenderThread in case it's waiting
265   mRenderThreadWaitCondition.Notify();
266
267   {
268     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
269
270     // Wait for RenderThread to replace the surface
271     while( ! mEventThreadSurfaceReplaced )
272     {
273       LOG_EVENT( "Waiting for Surface to be Replaced" );
274
275       mEventThreadWaitCondition.Wait( lock );
276     }
277   }
278
279   {
280     ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
281     mState = previousState;
282   }
283   mUpdateThreadWaitCondition.Notify();
284 }
285
286 void ThreadSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
287 {
288   LOG_EVENT_TRACE;
289   LOG_EVENT( "SET RENDER REFRESH RATE" );
290
291   mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
292 }
293
294 ///////////////////////////////////////////////////////////////////////////////////////////////////
295 // UPDATE THREAD
296 ///////////////////////////////////////////////////////////////////////////////////////////////////
297
298 bool ThreadSynchronization::UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
299 {
300   LOG_UPDATE_TRACE;
301
302   State::Type state = State::STOPPED;
303   {
304     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
305     state = mState;
306   }
307
308   switch( state )
309   {
310     case State::STOPPED:
311     {
312       StopAllThreads();
313       return false; // Stop update-thread
314     }
315
316     case State::INITIALISING:
317     {
318       UpdateInitialising();
319       break;
320     }
321
322     case State::PAUSED:
323     {
324       LOG_UPDATE_TRACE_FMT( "PAUSED" );
325
326       // Just pause the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
327       PauseVSyncThread();
328     }
329     // No break, fall through
330
331     case State::RUNNING:
332     {
333       LOG_UPDATE_TRACE_FMT( "RUNNING" );
334
335       if( IsUpdateThreadResuming() )
336       {
337         LOG_UPDATE( "Restarting VSyncThread" );
338
339         {
340           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
341           mUpdateThreadResuming = FALSE;
342         }
343
344         // Restart the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
345         RunVSyncThread();
346       }
347
348       if( notifyEvent )
349       {
350         LOG_UPDATE( "Notify Event Thread" );
351
352         // Do the notifications first so the event thread can start processing them
353         // Tell the event-thread to wake up (if asleep) and send a notification event to Core
354         mNotificationTrigger.Trigger();
355       }
356
357       // Inform render thread
358       {
359         ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
360         ++mUpdateAheadOfRender;
361         LOG_UPDATE_COUNTER_UPDATE( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
362       }
363       mRenderThreadWaitCondition.Notify();
364
365       // Wait if we've reached the maximum-ahead-of-render count.
366       while( MaximumUpdateAheadOfRenderReached() )
367       {
368         LOG_UPDATE( "Maximum Update Ahead of Render: WAIT" );
369
370         mRenderThreadWaitCondition.Notify(); // Notify the render thread in case it was waiting
371
372         {
373           // Ensure we did not stop while we were waiting previously.
374           ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
375           if( mState == State::STOPPED )
376           {
377             break; // Break out of while loop
378           }
379           mUpdateThreadWaitCondition.Wait( updateLock );
380         }
381       }
382
383       // Ensure we have had at least 1 V-Sync before we continue
384       // Ensure we didn't stop while we were previously waiting
385       {
386         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
387         if( ( mState != State::STOPPED ) &&
388             ( mVSyncAheadOfUpdate == 0 ) )
389         {
390           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d) WAIT", mVSyncAheadOfUpdate );
391           mUpdateThreadWaitCondition.Wait( updateLock );
392         }
393         else
394         {
395           LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
396         }
397         mVSyncAheadOfUpdate = 0;
398       }
399
400       // Try to sleep if we do not require any more updates
401       UpdateTryToSleep( runUpdate );
402
403       break;
404     }
405
406     case State::SLEEPING:
407     case State::REPLACING_SURFACE:
408     {
409       break;
410     }
411   }
412
413   // Ensure we didn't stop while we were waiting
414   if( IsUpdateThreadStopping() )
415   {
416     // Locks so we shouldn't have a scoped-lock when calling this
417     StopAllThreads();
418     return false; // Stop update-thread
419   }
420
421   // Just wait if we're replacing the surface as the render-thread is busy
422   UpdateWaitIfReplacingSurface();
423
424   mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds );
425
426   return true; // Keep update-thread running
427 }
428
429 ///////////////////////////////////////////////////////////////////////////////////////////////////
430 // RENDER THREAD
431 ///////////////////////////////////////////////////////////////////////////////////////////////////
432
433 bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr )
434 {
435   LOG_RENDER_TRACE;
436
437   if( ! IsRenderThreadReplacingSurface() ) // Call to this function locks so should not be called if we have a scoped-lock
438   {
439     if( ! mRenderThreadInitialised )
440     {
441       LOG_RENDER( "Initialised" );
442
443       mRenderThreadInitialised = TRUE;
444
445       // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
446       NotifyThreadInitialised();
447     }
448     else
449     {
450       if( mRenderThreadSurfaceReplaced )
451       {
452         mRenderThreadSurfaceReplaced = FALSE;
453       }
454       else
455       {
456         // decrement update-ahead-of-render
457         ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
458         --mUpdateAheadOfRender;
459       }
460     }
461
462     // Check if we've had an update, if we haven't then we just wait
463     // Ensure we do not wait if we're supposed to stop
464     {
465       ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
466       if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop )
467       {
468         LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender );
469         mRenderThreadWaitCondition.Wait( renderLock );
470       }
471       else
472       {
473         LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
474       }
475     }
476   }
477   else
478   {
479     LOG_RENDER( "Just Rendered, now Replacing surface" );
480
481     // ... also decrement update-ahead-of-render
482     ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
483     --mUpdateAheadOfRender;
484   }
485
486   // We may have been asked to replace the surface while we were waiting so check again here
487   if( IsRenderThreadReplacingSurface() )
488   {
489     // Replacing surface
490     LOG_RENDER( "REPLACE SURFACE" );
491
492     ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
493     requestPtr = &mReplaceSurfaceRequest;
494     mRenderThreadReplacingSurface = FALSE;
495     mRenderThreadSurfaceReplaced = FALSE;
496   }
497
498   return IsRenderThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
499 }
500
501 void ThreadSynchronization::RenderInformSurfaceReplaced()
502 {
503   LOG_RENDER_TRACE;
504
505   mRenderThreadSurfaceReplaced = TRUE;
506   {
507     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
508     mEventThreadSurfaceReplaced = TRUE;
509   }
510   mEventThreadWaitCondition.Notify();
511 }
512
513 ///////////////////////////////////////////////////////////////////////////////////////////////////
514 // V-SYNC THREAD
515 ///////////////////////////////////////////////////////////////////////////////////////////////////
516
517 bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender )
518 {
519   LOG_VSYNC_TRACE;
520
521   {
522     ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
523     if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender )
524     {
525       numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back
526       mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
527     }
528
529     if( validSync )
530     {
531       mFrameTime.SetSyncTime( frameNumber );
532     }
533   }
534
535   if( ! mVSyncThreadInitialised )
536   {
537     LOG_VSYNC( "Initialised" );
538
539     mVSyncThreadInitialised = TRUE;
540
541     // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
542     NotifyThreadInitialised();
543   }
544   else
545   {
546     // Increment v-sync-ahead-of-update count and inform update-thread
547     {
548       ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
549       ++mVSyncAheadOfUpdate;
550       LOG_VSYNC_COUNTER_VSYNC( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
551     }
552     mUpdateThreadWaitCondition.Notify();
553   }
554
555   // Ensure update-thread has set us to run before continuing
556   // Ensure we do not wait if we're supposed to stop
557   {
558     ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
559     while( ! mVSyncThreadRunning && ! mVSyncThreadStop )
560     {
561       LOG_VSYNC( "WAIT" );
562       mVSyncThreadWaitCondition.Wait( vSyncLock );
563     }
564   }
565
566   return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
567 }
568
569 ///////////////////////////////////////////////////////////////////////////////////////////////////
570 // ALL THREADS: Performance Marker
571 ///////////////////////////////////////////////////////////////////////////////////////////////////
572
573 void ThreadSynchronization::AddPerformanceMarker( PerformanceInterface::MarkerType type )
574 {
575   if( mPerformanceInterface )
576   {
577     mPerformanceInterface->AddMarker( type );
578   }
579 }
580
581 ///////////////////////////////////////////////////////////////////////////////////////////////////
582 //
583 // PRIVATE METHODS
584 //
585 ///////////////////////////////////////////////////////////////////////////////////////////////////
586
587 ///////////////////////////////////////////////////////////////////////////////////////////////////
588 // Called by ALL Threads
589 ///////////////////////////////////////////////////////////////////////////////////////////////////
590
591 void ThreadSynchronization::NotifyThreadInitialised()
592 {
593   {
594     ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
595     ++mNumberOfThreadsStarted;
596   }
597   mEventThreadWaitCondition.Notify();
598 }
599
600 ///////////////////////////////////////////////////////////////////////////////////////////////////
601 // Called by Update Thread
602 ///////////////////////////////////////////////////////////////////////////////////////////////////
603
604 void ThreadSynchronization::UpdateInitialising()
605 {
606   LOG_UPDATE_TRACE;
607
608   // Notify event thread that this thread is up and running, locks so we shouldn't have a scoped-lock when calling this
609   NotifyThreadInitialised();
610
611   // Wait for first thread-sync point
612   {
613     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
614
615     while( mState == State::INITIALISING )
616     {
617       mUpdateThreadWaitCondition.Wait( updateLock );
618     }
619   }
620
621   // Locks so we shouldn't have a scoped-lock when calling this
622   RunVSyncThread();
623 }
624
625 void ThreadSynchronization::UpdateTryToSleep( bool runUpdate )
626 {
627   LOG_UPDATE_TRACE;
628
629   if( ! runUpdate )
630   {
631     LOG_UPDATE( "TryToSleep" );
632
633     if( ++mTryToSleepCount >= 3 )
634     {
635       LOG_UPDATE( "Going to sleep" );
636
637       // Locks so we shouldn't have a scoped-lock when calling this
638       PauseVSyncThread();
639
640       // Render thread will automatically wait as it relies on update-ahead-of-render count
641
642       // Change the state
643       {
644         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
645
646         // Ensure we weren't stopped while we have been processing
647         if( mState != State::STOPPED )
648         {
649           mState = State::SLEEPING;
650         }
651       }
652
653       // Inform FrameTime that we're going to sleep
654       mFrameTime.Sleep();
655
656       // Wait while we're SLEEPING
657       {
658         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
659         while( mState == State::SLEEPING )
660         {
661           mUpdateThreadWaitCondition.Wait( updateLock );
662         }
663       }
664
665       ////////////////////////
666       // WAKE UP
667       ////////////////////////
668
669       LOG_UPDATE( "Waking Up" );
670
671       // Clear V-Sync-ahead-of-update-count
672       {
673         ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
674         mVSyncAheadOfUpdate = 0;
675       }
676
677       // Restart the v-sync-thread, locks so we shouldn't have a scoped-lock
678       RunVSyncThread();
679
680       // Reset try-to-sleep count
681       mTryToSleepCount = 0;
682
683       // Inform frame timer that we've woken up
684       mFrameTime.WakeUp();
685     }
686   }
687   else
688   {
689     mTryToSleepCount = 0;
690   }
691 }
692
693 void ThreadSynchronization::UpdateWaitIfReplacingSurface()
694 {
695   bool replacingSurface = false;
696   {
697     ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
698     replacingSurface = ( mState == State::REPLACING_SURFACE );
699   }
700   while( replacingSurface )
701   {
702     LOG_UPDATE_TRACE_FMT( "REPLACING SURFACE" );
703
704     // Locks so should not be called while we have a scoped-lock
705     PauseVSyncThread();
706
707     // One last check before we actually wait in case the state has changed since we checked earlier
708     {
709       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
710       replacingSurface = ( mState == State::REPLACING_SURFACE );
711       if( replacingSurface )
712       {
713         mUpdateThreadWaitCondition.Wait( updateLock );
714       }
715     }
716
717     {
718       ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
719       mVSyncAheadOfUpdate = 0;
720     }
721
722     // Locks so should not be called while we have a scoped-lock
723     RunVSyncThread();
724   }
725 }
726
727 bool ThreadSynchronization::IsUpdateThreadResuming()
728 {
729   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
730   return mUpdateThreadResuming;
731 }
732
733 bool ThreadSynchronization::IsUpdateThreadStopping()
734 {
735   ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
736   return ( mState == State::STOPPED );
737 }
738
739 bool ThreadSynchronization::MaximumUpdateAheadOfRenderReached()
740 {
741   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
742   return mUpdateAheadOfRender >= mMaximumUpdateCount;
743 }
744
745 void ThreadSynchronization::StopAllThreads()
746 {
747   LOG_UPDATE_TRACE;
748
749   // Lock so we shouldn't have a scoped-lock when calling these methods
750   StopVSyncThread();
751   StopRenderThread();
752 }
753
754 void ThreadSynchronization::RunVSyncThread()
755 {
756   {
757     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
758     mVSyncThreadRunning = TRUE;
759   }
760   mVSyncThreadWaitCondition.Notify();
761 }
762
763 void ThreadSynchronization::PauseVSyncThread()
764 {
765   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
766   mVSyncThreadRunning = FALSE;
767 }
768
769 void ThreadSynchronization::StopVSyncThread()
770 {
771   {
772     ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
773     mVSyncThreadStop = TRUE;
774   }
775   mVSyncThreadWaitCondition.Notify();
776 }
777
778 void ThreadSynchronization::StopRenderThread()
779 {
780   {
781     ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
782     mRenderThreadStop = TRUE;
783   }
784   mRenderThreadWaitCondition.Notify();
785 }
786
787 ///////////////////////////////////////////////////////////////////////////////////////////////////
788 // Called by V-Sync Thread
789 ///////////////////////////////////////////////////////////////////////////////////////////////////
790
791 bool ThreadSynchronization::IsVSyncThreadRunning()
792 {
793   ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
794   return ! mVSyncThreadStop;
795 }
796
797 ///////////////////////////////////////////////////////////////////////////////////////////////////
798 // Called by Render Thread
799 ///////////////////////////////////////////////////////////////////////////////////////////////////
800
801 bool ThreadSynchronization::IsRenderThreadRunning()
802 {
803   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
804   return ! mRenderThreadStop;
805 }
806
807 bool ThreadSynchronization::IsRenderThreadReplacingSurface()
808 {
809   ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
810   return mRenderThreadReplacingSurface;
811 }
812
813 } // namespace Adaptor
814
815 } // namespace Internal
816
817 } // namespace Dali