Make AsyncTask destructor called out of mutex 31/300231/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 19 Oct 2023 04:31:21 +0000 (13:31 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Thu, 19 Oct 2023 06:33:24 +0000 (15:33 +0900)
Some unhappy case may happened when destructor of AsyncTask call
RemoveTask() API if it is canceled before.

It may occure some dead-lock issue. So we need to avoid this case.

Change-Id: I1d51d43a7683b189d91251dd2404d927bc948726
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/system/common/async-task-manager-impl.cpp

index 6a3eaf1..36425fc 100644 (file)
@@ -435,31 +435,36 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
 
 AsyncTaskPtr AsyncTaskManager::PopNextCompletedTask()
 {
-  // Lock while popping task out from the queue
-  Mutex::ScopedLock lock(mCompletedTasksMutex);
+  std::vector<AsyncTaskPtr> ignoredTaskList; ///< To keep asyncTask reference so we can ensure that destructor called out of mutex.
 
   AsyncTaskPtr nextCompletedTask = nullptr;
-
-  while(!mCompletedTasks.empty())
   {
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "PopNextCompletedTask, completed task count : [%zu]\n", mCompletedTasks.size());
+    // Lock while popping task out from the queue
+    Mutex::ScopedLock lock(mCompletedTasksMutex);
+
+    while(!mCompletedTasks.empty())
+    {
+      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "PopNextCompletedTask, completed task count : [%zu]\n", mCompletedTasks.size());
 
-    auto               next      = mCompletedTasks.begin();
-    AsyncTaskPtr       nextTask  = next->first;
-    CompletedTaskState taskState = next->second;
-    CacheImpl::EraseTaskCache(mCacheImpl->mCompletedTasksCache, nextTask, next);
-    mCompletedTasks.erase(next);
+      auto               next      = mCompletedTasks.begin();
+      AsyncTaskPtr       nextTask  = next->first;
+      CompletedTaskState taskState = next->second;
+      CacheImpl::EraseTaskCache(mCacheImpl->mCompletedTasksCache, nextTask, next);
+      mCompletedTasks.erase(next);
 
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Completed task [%p] (callback required? : %d)\n", nextTask.Get(), taskState == CompletedTaskState::REQUIRE_CALLBACK);
+      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Completed task [%p] (callback required? : %d)\n", nextTask.Get(), taskState == CompletedTaskState::REQUIRE_CALLBACK);
 
-    if(taskState == CompletedTaskState::REQUIRE_CALLBACK)
-    {
-      nextCompletedTask = nextTask;
-      break;
+      if(taskState == CompletedTaskState::REQUIRE_CALLBACK)
+      {
+        nextCompletedTask = nextTask;
+        break;
+      }
+
+      ignoredTaskList.push_back(nextTask);
     }
-  }
 
-  DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Pickup completed [%p]\n", nextCompletedTask.Get());
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Pickup completed [%p]\n", nextCompletedTask.Get());
+  }
 
   return nextCompletedTask;
 }