/*
- * 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.
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
}
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));
*/
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);
{
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);
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)
{
// 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);
{
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.
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;
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;
+ }
}
}
{
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);
}
}
// Remove TasksCompleted callback trace
- if(mTasksCompletedImpl->IsTasksCompletedCallbackExist() && removedCount > 0u)
+ if(removedCount > 0u && mTasksCompletedImpl->IsTasksCompletedCallbackExist())
{
mTasksCompletedImpl->RemoveTaskTrace(task, removedCount);
}
// 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);
+ }
}
}
}
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)
{
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;
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
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;
// 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);
}
}
- if(priorityType == AsyncTask::PriorityType::HIGH)
+ if(priorityType == AsyncTask::PriorityType::HIGH && mWaitingHighProirityTaskCounts > 0u)
{
// Decrease the number of waiting tasks for high priority.
--mWaitingHighProirityTaskCounts;
}
}
- 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;
}
/// 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());
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)
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);