*/
// CLASS HEADER
-#include "async-task-manager-impl.h"
+#include <dali/internal/system/common/async-task-manager-impl.h>
// EXTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/environment-variable.h>
constexpr auto DEFAULT_NUMBER_OF_ASYNC_THREADS = size_t{8u};
constexpr auto NUMBER_OF_ASYNC_THREADS_ENV = "DALI_ASYNC_MANAGER_THREAD_POOL_SIZE";
+// The number of threads for low priority task.
+constexpr auto DEFAULT_NUMBER_OF_LOW_PRIORITY_THREADS = size_t{6u};
+constexpr auto NUMBER_OF_LOW_PRIORITY_THREADS_ENV = "DALI_ASYNC_MANAGER_LOW_PRIORITY_THREAD_POOL_SIZE";
+
size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
{
auto numberString = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
return (numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS) ? numberOfThreads : defaultValue;
}
+size_t GetNumberOfLowPriorityThreads(const char* environmentVariable, size_t defaultValue, size_t maxValue)
+{
+ auto numberString = EnvironmentVariable::GetEnvironmentVariable(environmentVariable);
+ auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
+ DALI_ASSERT_DEBUG(numberOfThreads <= maxValue);
+ return (numberOfThreads > 0 && numberOfThreads <= maxValue) ? numberOfThreads : std::min(defaultValue, maxValue);
+}
+
#if defined(DEBUG_ENABLED)
Debug::Filter* gAsyncTasksManagerLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ASYNC_TASK_MANAGER");
#endif
AsyncTaskManager::AsyncTaskManager()
: mTasks(GetNumberOfThreads(NUMBER_OF_ASYNC_THREADS_ENV, DEFAULT_NUMBER_OF_ASYNC_THREADS), [&]() { return TaskHelper(*this); }),
+ mAvaliableLowPriorityTaskCounts(GetNumberOfLowPriorityThreads(NUMBER_OF_LOW_PRIORITY_THREADS_ENV, DEFAULT_NUMBER_OF_LOW_PRIORITY_THREADS, mTasks.GetElementCount())),
mTrigger(new EventThreadCallback(MakeCallback(this, &AsyncTaskManager::TasksCompleted))),
mProcessorRegistered(false)
{
void AsyncTaskManager::AddTask(AsyncTaskPtr task)
{
+ if(task)
{
// Lock while adding task to the queue
Mutex::ScopedLock lock(mMutex);
+
mWaitingTasks.push_back(task);
// Finish all Running threads are working
void AsyncTaskManager::RemoveTask(AsyncTaskPtr task)
{
+ if(task)
{
// Lock while remove task from the queue
Mutex::ScopedLock lock(mMutex);
+
if(!mWaitingTasks.empty())
{
for(std::vector<AsyncTaskPtr>::iterator it = mWaitingTasks.begin(); it != mWaitingTasks.end();)
{
if((*iter)->IsReady())
{
- nextTask = *iter;
+ const auto priorityType = (*iter)->GetPriorityType();
+ const bool taskAvaliable = (priorityType == AsyncTask::PriorityType::HIGH) || // Task always valid if it's priority is high
+ (mAvaliableLowPriorityTaskCounts > 0u); // or priority is low, but we can use it.
- // Add Running queue
- mRunningTasks.push_back(std::make_pair(nextTask, false));
- mWaitingTasks.erase(iter);
- break;
+ if(taskAvaliable)
+ {
+ nextTask = *iter;
+
+ // Add Running queue
+ mRunningTasks.push_back(std::make_pair(nextTask, false));
+ mWaitingTasks.erase(iter);
+
+ // Decrease avaliable task counts if it is low priority
+ if(priorityType == AsyncTask::PriorityType::LOW)
+ {
+ --mAvaliableLowPriorityTaskCounts;
+ }
+ break;
+ }
}
}
// Lock while adding task to the queue
{
Mutex::ScopedLock lock(mMutex);
+
for(auto iter = mRunningTasks.begin(), endIter = mRunningTasks.end(); iter != endIter; ++iter)
{
if((*iter).first == task)
// Delete this task in running queue
mRunningTasks.erase(iter);
+
+ // Increase avaliable task counts if it is low priority
+ const auto priorityType = task->GetPriorityType();
+ if(priorityType == AsyncTask::PriorityType::LOW)
+ {
+ ++mAvaliableLowPriorityTaskCounts;
+ }
break;
}
}
};
/**
+ * @brief The priority of this task what user think.
+ * To avoid long term tasks (like remote image download) block whole threads,
+ * Let user set the priority type of this task.
+ *
+ * Low priority task means it doesn't need to process by FIFO logic.
+ * So we make that Low priority don't take whole threads.
+ *
+ * Task selection algorithm defined internally.
+ *
+ * @note Task cannot change the priority type after create.
+ *
+ * @SINCE_2_2.17
+ */
+ enum class PriorityType
+ {
+ HIGH = 0, ///< Highest priority to process task. @SINCE_2_2.17
+ LOW = 1, ///< Lowest priority to process task. @SINCE_2_2.17
+
+ PRIORITY_COUNT, ///< The number of priority type. @SINCE_2_2.17
+
+ DEFAULT = HIGH, ///< Default priority value if nothing defined. @SINCE_2_2.17
+ };
+
+ /**
* Constructor
* @SINCE_2_2.3
* @param[in] callback The callback to invoke on task completion, either on the main thread on the worker thread. The ownership of callback is taken by this class.
+ * @param[in] priority The proirity type of this task.
* @param[in] threadType The thread type of invocation callback.
*/
- AsyncTask(CallbackBase* callback, ThreadType threadType = AsyncTask::ThreadType::MAIN_THREAD);
+ AsyncTask(CallbackBase* callback, PriorityType priority = PriorityType::DEFAULT, ThreadType threadType = AsyncTask::ThreadType::MAIN_THREAD);
/**
* Get the complated callback
ThreadType GetCallbackInvocationThread();
/**
+ * Get the priority of this task
+ * @SINCE_2_2.17
+ * @return the type of priority.
+ */
+ PriorityType GetPriorityType() const;
+
+ /**
* Destructor.
* @SINCE_2_2.3
*/
private:
std::unique_ptr<CallbackBase> mCompletedCallback;
+ const PriorityType mPriorityType;
ThreadType mThreadType;
// Undefined