Multithreaded wait test case for ConditionalWait 50/43050/2
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Tue, 7 Jul 2015 10:26:31 +0000 (11:26 +0100)
committerKimmo Hoikka <kimmo.hoikka@samsung.com>
Tue, 7 Jul 2015 15:21:29 +0000 (16:21 +0100)
Change-Id: I46ea1fd4baa2fef92aa9271b1e5edadbe63d3c20

adaptors/base/conditional-wait.cpp
adaptors/base/conditional-wait.h
automated-tests/src/dali-adaptor-internal/utc-ConditionalWait.cpp

index cb0b16c67c49a055f6f40af6af93fff4fe58f3f8..3b7e4919a5e910b399a0caaa1a49ee6e8e041ce5 100644 (file)
@@ -38,7 +38,7 @@ struct ConditionalWait::ConditionalWaitImpl
 {
   pthread_mutex_t mutex;
   pthread_cond_t condition;
-  volatile bool wait;
+  volatile unsigned int count;
 };
 
 ConditionalWait::ConditionalWait()
@@ -46,7 +46,7 @@ ConditionalWait::ConditionalWait()
 {
   pthread_mutex_init( &mImpl->mutex, NULL );
   pthread_cond_init( &mImpl->condition, NULL );
-  mImpl->wait = false;
+  mImpl->count = 0;
 }
 
 ConditionalWait::~ConditionalWait()
@@ -60,43 +60,38 @@ void ConditionalWait::Notify()
 {
   // pthread_cond_wait requires a lock to be held
   pthread_mutex_lock( &mImpl->mutex );
-  bool wasWaiting = mImpl->wait;
-  mImpl->wait = false;
-  pthread_mutex_unlock( &mImpl->mutex );
+  volatile unsigned int previousCount = mImpl->count;
+  mImpl->count = 0; // change state before broadcast as that may wake clients immediately
   // broadcast does nothing if the thread is not waiting but still has a system call overhead
   // broadcast all threads to continue
-  if( wasWaiting )
+  if( 0 != previousCount )
   {
     pthread_cond_broadcast( &mImpl->condition );
   }
+  pthread_mutex_unlock( &mImpl->mutex );
 }
 
 void ConditionalWait::Wait()
 {
   // pthread_cond_wait requires a lock to be held
   pthread_mutex_lock( &mImpl->mutex );
-  mImpl->wait = true;
+  ++(mImpl->count);
   // pthread_cond_wait may wake up without anyone calling Notify
-  while( mImpl->wait )
+  do
   {
     // wait while condition changes
     pthread_cond_wait( &mImpl->condition, &mImpl->mutex ); // releases the lock whilst waiting
   }
+  while( 0 != mImpl->count );
   // when condition returns the mutex is locked so release the lock
   pthread_mutex_unlock( &mImpl->mutex );
 }
 
-bool ConditionalWait::IsWaiting() const
+unsigned int ConditionalWait::GetWaitCount() const
 {
-  bool isWaiting( false );
-  pthread_mutex_lock( &mImpl->mutex );
-  isWaiting = mImpl->wait;
-  pthread_mutex_unlock( &mImpl->mutex );
-  return isWaiting;
+  return mImpl->count;
 }
 
-
-
 } // namespace Adaptor
 
 } // namespace Internal
index 3638bfa509da80ef7c5b7391956341a69dc65c89..c6b2b5dd14a05a9da2bcd9c9ae5963fd44fde630 100644 (file)
@@ -60,10 +60,10 @@ public:
   void Wait();
 
   /**
-   * @brief Return true if the wait is locked, i.e. someone is waiting for it
-   * @return true if this object is waiting on a thread
+   * @brief Return the count of threads waiting for this conditional
+   * @return count of waits
    */
-  bool IsWaiting() const;
+  unsigned int GetWaitCount() const;
 
 private:
 
index 85abcf6b7b41364dbcd25e38a29fdec40354b3af..f66562d93fcb2b4786d684e9224338024f2a44d7 100644 (file)
@@ -39,7 +39,8 @@ void* WorkerThreadNotify( void* ptr )
     gWorkerThreadState = RUN;
     usleep( 1 ); // 1 microseconds
   }
-  usleep( 1000 ); // 1000 microseconds to give other thread time to do its thing
+  usleep( 200 ); // give other thread time to get to Wait
+  gGlobalValue = 1;
   gConditionalWait->Notify();
   gWorkerThreadState = TERMINATE;
   return NULL;
@@ -47,7 +48,7 @@ void* WorkerThreadNotify( void* ptr )
 
 int UtcConditionalWait1P(void)
 {
-  tet_infoline("Testing ConditionalWait - scenario 1:  wait - notify from separate thread");
+  tet_infoline("Testing ConditionalWait - scenario:  wait - notify with 2 threads");
 
   pthread_t thread1;
   // initialize values
@@ -65,6 +66,8 @@ int UtcConditionalWait1P(void)
   // let worker continue and finish
   gWorkerThreadWait = false;
   gConditionalWait->Wait();
+  DALI_TEST_EQUALS( 1, gGlobalValue, TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
 
   // wait till the thread is terminated state
   while( TERMINATE != gWorkerThreadState )
@@ -81,20 +84,20 @@ int UtcConditionalWait1P(void)
 
 int UtcConditionalWait2P(void)
 {
-  tet_infoline("Testing ConditionalWait - scenario 2:  notify without wait");
+  tet_infoline("Testing ConditionalWait - scenario: notify without wait");
 
   ConditionalWait wait;
-  DALI_TEST_EQUALS( false, wait.IsWaiting(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, wait.GetWaitCount(), TEST_LOCATION );
   wait.Notify();
-  DALI_TEST_EQUALS( false, wait.IsWaiting(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, wait.GetWaitCount(), TEST_LOCATION );
 
   END_TEST;
 }
 
-volatile unsigned int gNotifyCount = 0;
+volatile int gNotifyCount = 0;
 void* WorkerThreadNotifyN( void* ptr )
 {
-  while( gNotifyCount )
+  while( gNotifyCount > 0 )
   {
     gConditionalWait->Notify();
     usleep( 10 ); // 10 microseconds between each notify
@@ -104,7 +107,7 @@ void* WorkerThreadNotifyN( void* ptr )
 
 int UtcConditionalWait3P(void)
 {
-  tet_infoline("Testing ConditionalWait - scenario 1:  wait - notify N times");
+  tet_infoline("Testing ConditionalWait - scenario: wait - notify N times 2 threads");
 
   // initialize values
   gConditionalWait = new ConditionalWait();
@@ -113,14 +116,14 @@ int UtcConditionalWait3P(void)
   pthread_t thread1;
   pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
 
-  while( gNotifyCount )
+  while( gNotifyCount > 0 )
   {
     gConditionalWait->Wait();
     --gNotifyCount;
-    DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+    DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
     usleep( 10 ); // 10 microseconds between each notify
   }
-  DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
 
   void* exitValue;
   pthread_join( thread1, &exitValue );
@@ -131,7 +134,7 @@ int UtcConditionalWait3P(void)
 
 int UtcConditionalWait4P(void)
 {
-  tet_infoline("Testing ConditionalWait - scenario 1:  wait - notify N times from multiple threads");
+  tet_infoline("Testing ConditionalWait - scenario:  wait - notify N times from 3 threads");
 
   // initialize values
   gConditionalWait = new ConditionalWait();
@@ -139,18 +142,16 @@ int UtcConditionalWait4P(void)
 
   pthread_t thread1;
   pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
-
   pthread_t thread2;
   pthread_create( &thread2, NULL, &WorkerThreadNotifyN, NULL );
-
   pthread_t thread3;
   pthread_create( &thread3, NULL, &WorkerThreadNotifyN, NULL );
 
-  while( gNotifyCount )
+  while( gNotifyCount > 0 )
   {
     gConditionalWait->Wait();
     --gNotifyCount;
-    DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+    DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
     usleep( 10 ); // 10 microseconds between each notify
   }
 
@@ -163,6 +164,47 @@ int UtcConditionalWait4P(void)
   END_TEST;
 }
 
+void* WorkerThreadWaitN( void* ptr )
+{
+  gConditionalWait->Wait();
+
+  return NULL;
+}
+
+int UtcConditionalWait5P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario:  4 threads wait - notify once from 1 thread");
+
+  // initialize values
+  gConditionalWait = new ConditionalWait();
+
+  pthread_t thread1;
+  pthread_create( &thread1, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread2;
+  pthread_create( &thread2, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread3;
+  pthread_create( &thread3, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread4;
+  pthread_create( &thread4, NULL, &WorkerThreadWaitN, NULL );
+
+  // wait till all child threads are waiting
+  while( gConditionalWait->GetWaitCount() < 4 )
+  { }
+
+  // notify once, it will resume all threads
+  gConditionalWait->Notify();
+
+  void* exitValue;
+  pthread_join( thread1, &exitValue );
+  pthread_join( thread2, &exitValue );
+  pthread_join( thread3, &exitValue );
+  pthread_join( thread4, &exitValue );
+
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+
+  delete gConditionalWait;
+  END_TEST;
+}
 
 int UtcConditionalWaitNonCopyable(void)
 {