Merge "[AT-SPI] Rework intercepting key events" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / common / async-task-manager-impl.cpp
index 74f89be..2f2a2bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -67,6 +67,19 @@ Debug::Filter* gAsyncTasksManagerLogFilter = Debug::Filter::New(Debug::NoLogging
 uint32_t gThreadId = 0u; // Only for debug
 #endif
 
+/**
+ * @brief Get the Task Name.
+ * Note that we can get const char* from std::string_view as data() since it will be const class.
+ *
+ * @param task The task what we want to get the name.
+ * @return The name of task, or (nil) if task is invalid.
+ */
+const char* GetTaskName(AsyncTaskPtr task)
+{
+  // Note
+  return task ? task->GetTaskName().data() : "(nil)";
+}
+
 } // unnamed namespace
 
 // AsyncTaskThread
@@ -150,9 +163,9 @@ void AsyncTaskThread::Run()
     }
     else
     {
-      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Thread[%u] Process task [%p]\n", threadId, task.Get());
+      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Thread[%u] Process task [%p][%s]\n", threadId, task.Get(), GetTaskName(task));
       task->Process();
-      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Thread[%u] Complete task [%p]\n", threadId, task.Get());
+      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Thread[%u] Complete task [%p][%s]\n", threadId, task.Get(), GetTaskName(task));
       if(!mDestroyThread)
       {
         mAsyncTaskManager.CompleteTask(std::move(task));
@@ -200,7 +213,7 @@ public:
    */
   void AppendTaskTrace(Dali::AsyncTaskManager::TasksCompletedId id, AsyncTaskPtr task)
   {
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "AppendTaskTrace id[%u] task[%p]\n", id, task.Get());
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "AppendTaskTrace id[%u] task[%p][%s]\n", id, task.Get(), GetTaskName(task));
 
     // Lock while adding tasks completed callback list to the queue
     Mutex::ScopedLock lock(mTasksCompletedCallbacksMutex);
@@ -238,7 +251,7 @@ public:
     {
       return;
     }
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTaskTrace task[%p] remove count[%u]\n", task.Get(), count);
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTaskTrace task[%p][%s] remove count[%u]\n", task.Get(), GetTaskName(task), count);
 
     // Lock while removing tasks completed callback list to the queue
     Mutex::ScopedLock lock(mTasksCompletedCallbacksMutex);
@@ -252,7 +265,7 @@ public:
 
       if(jter != callbackData.mTasks.end())
       {
-        DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTaskTrace id[%u] task[%p], current refcount[%u]\n", iter->first, task.Get(), (jter->second));
+        DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTaskTrace id[%u] task[%p][%s], current refcount[%u]\n", iter->first, task.Get(), GetTaskName(task), (jter->second));
 
         if(jter->second <= count)
         {
@@ -633,7 +646,7 @@ void AsyncTaskManager::AddTask(AsyncTaskPtr task)
     // Lock while adding task to the queue
     Mutex::ScopedLock lock(mWaitingTasksMutex);
 
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "AddTask [%p]\n", task.Get());
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "AddTask [%p][%s]\n", task.Get(), GetTaskName(task));
 
     // push back into waiting queue.
     auto waitingIter = mWaitingTasks.insert(mWaitingTasks.end(), task);
@@ -680,7 +693,7 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
 {
   if(task)
   {
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTask [%p]\n", task.Get());
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "RemoveTask [%p][%s]\n", task.Get(), GetTaskName(task));
 
     // Check whether we need to unregister processor.
     // If there is some non-empty queue exist, we don't need to unregister processor.
@@ -698,7 +711,7 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
         for(auto& iterator : mapIter->second)
         {
           DALI_ASSERT_DEBUG((*iterator) == task);
-          if((*iterator)->GetPriorityType() == AsyncTask::PriorityType::HIGH)
+          if((*iterator)->GetPriorityType() == AsyncTask::PriorityType::HIGH && mWaitingHighProirityTaskCounts > 0u)
           {
             // Decrease the number of waiting tasks for high priority.
             --mWaitingHighProirityTaskCounts;
@@ -727,8 +740,11 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
           DALI_ASSERT_DEBUG((*iterator).first == task);
           // We cannot erase container. Just mark as canceled.
           // Note : mAvaliableLowPriorityTaskCounts will be increased after process finished.
-          (*iterator).second = RunningTaskState::CANCELED;
-          ++removedCount;
+          if((*iterator).second == RunningTaskState::RUNNING)
+          {
+            (*iterator).second = RunningTaskState::CANCELED;
+            ++removedCount;
+          }
         }
       }
 
@@ -747,9 +763,12 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
       {
         for(auto& iterator : mapIter->second)
         {
-          DALI_ASSERT_DEBUG(iterator->first == task);
+          DALI_ASSERT_DEBUG((*iterator).first == task);
+          if((*iterator).second == CompletedTaskState::REQUIRE_CALLBACK)
+          {
+            ++removedCount;
+          }
           mCompletedTasks.erase(iterator);
-          ++removedCount;
         }
         CacheImpl::EraseAllTaskCache(mCacheImpl->mCompletedTasksCache, task);
       }
@@ -761,7 +780,7 @@ void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
     }
 
     // Remove TasksCompleted callback trace
-    if(mTasksCompletedImpl->IsTasksCompletedCallbackExist() && removedCount > 0u)
+    if(removedCount > 0u && mTasksCompletedImpl->IsTasksCompletedCallbackExist())
     {
       mTasksCompletedImpl->RemoveTaskTrace(task, removedCount);
     }
@@ -807,28 +826,40 @@ Dali::AsyncTaskManager::TasksCompletedId AsyncTaskManager::SetCompletedCallback(
         // Collect all tasks from running tasks
         for(auto& taskPair : mRunningTasks)
         {
-          auto& task      = taskPair.first;
-          auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
-                           (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
-
-          if((checkMask & mask) == checkMask)
+          // Trace only if it is running now.
+          if(taskPair.second == RunningTaskState::RUNNING)
           {
-            taskAdded = true;
-            mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            auto& task      = taskPair.first;
+            auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
+                             (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
+
+            if((checkMask & mask) == checkMask)
+            {
+              taskAdded = true;
+              mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            }
           }
         }
 
         // Collect all tasks from complete tasks
         for(auto& taskPair : mCompletedTasks)
         {
-          auto& task      = taskPair.first;
-          auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
-                           (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
-
-          if((checkMask & mask) == checkMask)
+          // Trace only if it is need callback.
+          // Note : There are two CompletedTaskState::SKIP_CALLBACK cases, worker thread invocation and canceled cases.
+          //        If worker thread invocation, than it already remove trace at completed timing.
+          //        If canceled cases, we don't append trace at running tasks already.
+          //        So, we don't need to trace for SKIP_CALLBACK cases.
+          if(taskPair.second == CompletedTaskState::REQUIRE_CALLBACK)
           {
-            taskAdded = true;
-            mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            auto& task      = taskPair.first;
+            auto  checkMask = (task->GetCallbackInvocationThread() == Dali::AsyncTask::ThreadType::MAIN_THREAD ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_MAIN : Dali::AsyncTaskManager::CompletedCallbackTraceMask::THREAD_MASK_WORKER) |
+                             (task->GetPriorityType() == Dali::AsyncTask::PriorityType::HIGH ? Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_HIGH : Dali::AsyncTaskManager::CompletedCallbackTraceMask::PRIORITY_MASK_LOW);
+
+            if((checkMask & mask) == checkMask)
+            {
+              taskAdded = true;
+              mTasksCompletedImpl->AppendTaskTrace(tasksCompletedId, task);
+            }
           }
         }
       }
@@ -869,7 +900,7 @@ AsyncTaskPtr AsyncTaskManager::PopNextCompletedTask()
       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][%s] (callback required? : %d)\n", nextTask.Get(), GetTaskName(nextTask), taskState == CompletedTaskState::REQUIRE_CALLBACK);
 
       if(taskState == CompletedTaskState::REQUIRE_CALLBACK)
       {
@@ -880,7 +911,7 @@ AsyncTaskPtr AsyncTaskManager::PopNextCompletedTask()
       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][%s]\n", nextCompletedTask.Get(), GetTaskName(nextCompletedTask));
   }
 
   return nextCompletedTask;
@@ -926,7 +957,7 @@ void AsyncTaskManager::TasksCompleted()
   DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "TasksCompleted begin\n");
   while(AsyncTaskPtr task = PopNextCompletedTask())
   {
-    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Execute callback [%p]\n", task.Get());
+    DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Execute callback [%p][%s]\n", task.Get(), GetTaskName(task));
     CallbackBase::Execute(*(task->GetCompletedCallback()), task);
 
     // Remove TasksCompleted callback trace
@@ -985,6 +1016,22 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
         taskAvaliable = (mAvaliableLowPriorityTaskCounts > 0u); // priority is low, but we can use it.
       }
 
+      // Check whether we try to running same task at multiple threads.
+      if(taskAvaliable)
+      {
+        Mutex::ScopedLock lock(mRunningTasksMutex); // We can lock this mutex under mWaitingTasksMutex.
+        auto              mapIter = mCacheImpl->mRunningTasksCache.find((*iter).Get());
+        if(mapIter != mCacheImpl->mRunningTasksCache.end())
+        {
+          if(!mapIter->second.empty())
+          {
+            // Some other thread running this tasks now. Ignore it.
+            DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Some other thread running this task [%p][%s]\n", (*iter).Get(), GetTaskName(*iter));
+            taskAvaliable = false;
+          }
+        }
+      }
+
       if(taskAvaliable)
       {
         nextTask = *iter;
@@ -994,7 +1041,7 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
           // Lock while popping task out from the queue
           Mutex::ScopedLock lock(mRunningTasksMutex); // We can lock this mutex under mWaitingTasksMutex.
 
-          DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Waiting -> Running [%p]\n", nextTask.Get());
+          DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Waiting -> Running [%p][%s]\n", nextTask.Get(), GetTaskName(nextTask));
 
           auto runningIter = mRunningTasks.insert(mRunningTasks.end(), std::make_pair(nextTask, RunningTaskState::RUNNING));
           CacheImpl::InsertTaskCache(mCacheImpl->mRunningTasksCache, nextTask, runningIter);
@@ -1010,7 +1057,7 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
           }
         }
 
-        if(priorityType == AsyncTask::PriorityType::HIGH)
+        if(priorityType == AsyncTask::PriorityType::HIGH && mWaitingHighProirityTaskCounts > 0u)
         {
           // Decrease the number of waiting tasks for high priority.
           --mWaitingHighProirityTaskCounts;
@@ -1020,7 +1067,7 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
     }
   }
 
-  DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Pickup process [%p]\n", nextTask.Get());
+  DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::General, "Pickup process [%p][%s]\n", nextTask.Get(), GetTaskName(nextTask));
 
   return nextTask;
 }
@@ -1028,55 +1075,61 @@ AsyncTaskPtr AsyncTaskManager::PopNextTaskToProcess()
 /// Worker thread called
 void AsyncTaskManager::CompleteTask(AsyncTaskPtr&& task)
 {
-  bool notify = false;
-
   if(task)
   {
     bool needTrigger = false;
 
-    // Lock while check validation of task.
+    // Check now whether we need to execute callback or not, for worker thread cases.
+    if(task->GetCallbackInvocationThread() == AsyncTask::ThreadType::WORKER_THREAD)
     {
-      Mutex::ScopedLock lock(mRunningTasksMutex);
+      bool notify = false;
 
-      auto mapIter = mCacheImpl->mRunningTasksCache.find(task.Get());
-      if(mapIter != mCacheImpl->mRunningTasksCache.end())
+      // Lock while check validation of task.
       {
-        const auto cacheIter = mapIter->second.begin();
-        DALI_ASSERT_ALWAYS(cacheIter != mapIter->second.end());
+        Mutex::ScopedLock lock(mRunningTasksMutex);
 
-        const auto iter = *cacheIter;
-        DALI_ASSERT_DEBUG(iter->first == task);
-        if(iter->second == RunningTaskState::RUNNING)
+        auto mapIter = mCacheImpl->mRunningTasksCache.find(task.Get());
+        if(mapIter != mCacheImpl->mRunningTasksCache.end())
         {
-          // This task is valid.
-          notify = true;
-        }
-      }
+          const auto cacheIter = mapIter->second.begin();
+          DALI_ASSERT_ALWAYS(cacheIter != mapIter->second.end());
 
-      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "CompleteTask [%p] (is notify? : %d)\n", task.Get(), notify);
-    }
+          const auto iter = *cacheIter;
+          DALI_ASSERT_DEBUG(iter->first == task);
+          if(iter->second == RunningTaskState::RUNNING)
+          {
+            // This task is valid.
+            notify = true;
+          }
+        }
 
-    // We should execute this tasks complete callback out of mutex
-    if(notify && task->GetCallbackInvocationThread() == AsyncTask::ThreadType::WORKER_THREAD)
-    {
-      DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Execute callback on worker thread [%p]\n", task.Get());
-      CallbackBase::Execute(*(task->GetCompletedCallback()), task);
+        DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "CompleteTask [%p][%s] (is notify? : %d)\n", task.Get(), GetTaskName(task), notify);
+      }
 
-      // We need to remove task trace now.
-      if(mTasksCompletedImpl->IsTasksCompletedCallbackExist())
+      // We should execute this tasks complete callback out of mutex
+      if(notify)
       {
-        mTasksCompletedImpl->RemoveTaskTrace(task);
+        DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Execute callback on worker thread [%p][%s]\n", task.Get(), GetTaskName(task));
+        CallbackBase::Execute(*(task->GetCompletedCallback()), task);
 
-        if(mTasksCompletedImpl->IsExecuteCallbackExist())
+        // We need to remove task trace now.
+        if(mTasksCompletedImpl->IsTasksCompletedCallbackExist())
         {
-          // We need to call EmitCompletedTasks(). Trigger main thread.
-          needTrigger = true;
+          mTasksCompletedImpl->RemoveTaskTrace(task);
+
+          if(mTasksCompletedImpl->IsExecuteCallbackExist())
+          {
+            // We need to call EmitCompletedTasks(). Trigger main thread.
+            needTrigger = true;
+          }
         }
       }
     }
 
     // Lock while adding task to the queue
     {
+      bool notify = false;
+
       Mutex::ScopedLock lock(mRunningTasksMutex);
 
       auto mapIter = mCacheImpl->mRunningTasksCache.find(task.Get());
@@ -1085,7 +1138,15 @@ void AsyncTaskManager::CompleteTask(AsyncTaskPtr&& task)
         const auto cacheIter = mapIter->second.begin();
         DALI_ASSERT_ALWAYS(cacheIter != mapIter->second.end());
 
-        const auto iter         = *cacheIter;
+        const auto iter = *cacheIter;
+
+        DALI_ASSERT_DEBUG(iter->first == task);
+        if(iter->second == RunningTaskState::RUNNING)
+        {
+          // This task is valid.
+          notify = true;
+        }
+
         const auto priorityType = iter->first->GetPriorityType();
         // Increase avaliable task counts if it is low priority
         if(priorityType == AsyncTask::PriorityType::LOW)
@@ -1102,7 +1163,7 @@ void AsyncTaskManager::CompleteTask(AsyncTaskPtr&& task)
 
           needTrigger |= callbackRequired;
 
-          DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Running -> Completed [%p] (callback required? : %d)\n", task.Get(), callbackRequired);
+          DALI_LOG_INFO(gAsyncTasksManagerLogFilter, Debug::Verbose, "Running -> Completed [%p][%s] (callback required? : %d)\n", task.Get(), GetTaskName(task), callbackRequired);
 
           auto completedIter = mCompletedTasks.insert(mCompletedTasks.end(), std::make_pair(task, callbackRequired ? CompletedTaskState::REQUIRE_CALLBACK : CompletedTaskState::SKIP_CALLBACK));
           CacheImpl::InsertTaskCache(mCacheImpl->mCompletedTasksCache, task, completedIter);