From: Szymon Jastrzebski Date: Fri, 22 Jun 2018 11:38:55 +0000 (+0200) Subject: [Common] Implementation for parallel Worker X-Git-Tag: submit/tizen/20181126.112620~4^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5bb0709d231f8cdff9595f94205baa41e92a429a;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Common] Implementation for parallel Worker Change-Id: I93a0494cf5c943d2ead9e55957c25468764aebf8 Signed-off-by: Szymon Jastrzebski --- diff --git a/src/application/application_manager.cc b/src/application/application_manager.cc index 23025be5..fc6cf28d 100644 --- a/src/application/application_manager.cc +++ b/src/application/application_manager.cc @@ -16,6 +16,7 @@ #include "application_manager.h" +#include #include #include diff --git a/src/common/task-queue.cpp b/src/common/task-queue.cpp index 9bafdae4..fe551a5e 100644 --- a/src/common/task-queue.cpp +++ b/src/common/task-queue.cpp @@ -24,44 +24,54 @@ TaskQueue& TaskQueue::GetInstance() { } template <> -gboolean TaskQueue::AfterWorkCallback(gpointer data) { +gboolean TaskQueue::WorkCallback(gpointer data) { QueueData* d = static_cast*>(data); if (nullptr != d) { - d->after_work_callback_(); + d->work_callback_(); delete d; } return FALSE; } -template <> -void* TaskQueue::WorkCallback(void* data) { - QueueData* d = static_cast*>(data); - if (nullptr != d) { - d->work_callback_(); - if (d->after_work_callback_) { - g_idle_add(AfterWorkCallback, d); - } - } - return nullptr; +void TaskQueue::Queue(const std::function& work, const std::function& after_work) { + auto do_work = [work, after_work]() { + work(); + after_work(); + }; + this->queue_worker_.add_job(do_work); } -void TaskQueue::Queue(const std::function& work, const std::function& after_work) { - QueueData* d = new QueueData(); - d->work_callback_ = work; - d->after_work_callback_ = after_work; +void TaskQueue::Async(const std::function& work) { + this->async_worker_.add_job(work); +} - if (pthread_create(&d->thread_, nullptr, WorkCallback, d) != 0) { - LoggerE("Failed to create a background thread."); - delete d; - } else { - pthread_detach(d->thread_); +void TaskQueue::Async(const std::function& work, + const common::AsyncToken& token) { + auto do_work = [work, token]() { work(token); }; + Async(do_work); +} + +void TaskQueue::DeleteJobs() { + { + std::lock_guard lck{this->queue_worker_.jobs_mtx}; + this->queue_worker_.jobs.clear(); + } + { + std::lock_guard lck{this->async_worker_.jobs_mtx}; + this->async_worker_.jobs.clear(); } } -void TaskQueue::Async(const std::function& work) { +void TaskQueue::Stop() { + LoggerI("Stopping TaskQueue workers"); + queue_worker_.stop(); + async_worker_.stop(); +} + +void TaskQueue::ScheduleWorkInMainThread(const std::function& work) { QueueData* d = new QueueData(); - d->after_work_callback_ = work; - g_idle_add(AfterWorkCallback, d); + d->work_callback_ = work; + g_idle_add(WorkCallback, d); } } // namespace common diff --git a/src/common/task-queue.h b/src/common/task-queue.h index fb3300a3..c44cc09c 100644 --- a/src/common/task-queue.h +++ b/src/common/task-queue.h @@ -22,23 +22,55 @@ #include #include -#include "logger.h" +#include "tizen_instance.h" +#include "worker.h" namespace common { +/** + * TaskQueue is a class, which aggregates two instances of Worker class. + * The class contains two workers to prevent from blocking jobs, which should execute and return + * results after a few seconds. + */ class TaskQueue { - public: - TaskQueue(const TaskQueue&) = delete; - TaskQueue& operator=(const TaskQueue&) = delete; + private: + TaskQueue() { + } + /** + * Worker for asynchronous 'quick' jobs. + * This queue is supposed to hold jobs, which are expected to take 'a little' time. + */ + Worker async_worker_; + /** + * Worker for asynchronous 'long' jobs. + * This queue is supposed to hold jobs, which are expected to take 'long' time. + */ + Worker queue_worker_; + + public: static TaskQueue& GetInstance(); + ~TaskQueue() { + } + + /** + * Method used to clear all delegated jobs during lifetime of UtilsInstance class. + * The UtilsInstance class is the first constructed and the last destructed instance of Instance + * class, which determines the lifetime of frame in the page. + */ + void DeleteJobs(); + + /** + * Stops the workers. This method should be called only once, before shutting down the process. + * After that time, no more messages will be sent to Crosswalk. + */ + void Stop(); /** - * @brief Schedules work to be executed in a separate thread, after_work is going - * to be called in main glib loop. + * @brief Schedule a 'long' job * - * @param[in] work - callback is going to be called in a separate thread - * @param[in] after_work - callback is going to be called in main glib loop + * @param[in] work - callback is going to be called in a worker's thread + * @param[in] after_work - callback is going to be called after work * @param[in] data - data passed to both callbacks */ template @@ -47,19 +79,17 @@ class TaskQueue { const std::shared_ptr& data); /** - * @brief Schedules work to be executed in a separate thread, after_work is going - * to be called in main glib loop. + * @brief Schedule a 'long' job * - * @param[in] work - callback is going to be called in a separate thread - * @param[in] after_work - callback is going to be called in main glib loop + * @param[in] work - callback is going to be called in a worker's thread + * @param[in] after_work - callback is going to be called after work function */ - void Queue(const std::function& work, - const std::function& after_work = std::function()); + void Queue(const std::function& work, const std::function& after_work = [] {}); /** - * @brief Schedules work to be executed in main glib loop. + * @brief Schedule a 'quick' job * - * @param[in] work - callback is going to be called in main glib loop + * @param[in] work - callback is going to be called in a worker's thread * @param[in] data - data passed to callback */ template @@ -67,82 +97,98 @@ class TaskQueue { const std::shared_ptr& data); /** - * @brief Schedules work to be executed in main glib loop. + * @brief Schedule a 'quick' job * - * @param[in] work - callback is going to be called in main glib loop + * @param[in] work - callback is going to be called in a worker's thread */ void Async(const std::function& work); - private: - TaskQueue() { - } + /** + * @brief Schedule a 'quick' job requiring AsyncToken + * + * @param[in] work - callback is going to be called in a worker's thread + * @param[in] token - token passed to the work function + */ + void Async(const std::function& work, + const common::AsyncToken& token); + + /** + * @brief Schedules work to be executed in main glib loop + * + * This method should be used only for jobs, which HAVE to be executed in main loop of the + * process. + * + * @param[in] work - callback is going to be called in main glib loop + * @param[in] data - data passed to callback + */ + template + void ScheduleWorkInMainThread(const std::function&)>& work, + const std::shared_ptr& data); + /** + * @brief Schedules work to be executed in main glib loop + * + * This method should be used only for jobs, which HAVE to be executed in main loop of the + * process. + * + * @param[in] work - callback is going to be called in main glib loop + */ + void ScheduleWorkInMainThread(const std::function& work); template struct QueueData { - pthread_t thread_; std::function&)> work_callback_; - std::function&)> after_work_callback_; std::shared_ptr data_; }; template - static void* WorkCallback(void* data); + static gboolean WorkCallback(gpointer data); - template - static gboolean AfterWorkCallback(gpointer data); + TaskQueue(const TaskQueue&) = delete; + TaskQueue& operator=(const TaskQueue&) = delete; + TaskQueue(TaskQueue&&) = delete; + TaskQueue& operator=(TaskQueue&&) = delete; }; template <> struct TaskQueue::QueueData { - pthread_t thread_; std::function work_callback_; - std::function after_work_callback_; }; template -gboolean TaskQueue::AfterWorkCallback(gpointer data) { +gboolean TaskQueue::WorkCallback(gpointer data) { QueueData* d = static_cast*>(data); if (nullptr != d) { - d->after_work_callback_(d->data_); + d->work_callback_(d->data_); delete d; } return FALSE; } -template -void* TaskQueue::WorkCallback(void* data) { - QueueData* d = static_cast*>(data); - if (nullptr != d) { - d->work_callback_(d->data_); - g_idle_add(AfterWorkCallback, d); - } - return nullptr; -} - template void TaskQueue::Queue(const std::function&)>& work, const std::function&)>& after_work, const std::shared_ptr& data) { - QueueData* d = new QueueData(); - d->work_callback_ = work; - d->after_work_callback_ = after_work; - d->data_ = data; - - if (pthread_create(&d->thread_, nullptr, WorkCallback, d) != 0) { - LoggerE("Failed to create a background thread."); - delete d; - } else { - pthread_detach(d->thread_); - } + auto do_work = [data, work, after_work]() { + work(data); + after_work(data); + }; + this->queue_worker_.add_job(do_work); } template void TaskQueue::Async(const std::function&)>& work, const std::shared_ptr& data) { + auto do_work = [data, work]() { work(data); }; + this->async_worker_.add_job(do_work); +} + +template +void TaskQueue::ScheduleWorkInMainThread(const std::function&)>& work, + const std::shared_ptr& data) { QueueData* d = new QueueData(); - d->after_work_callback_ = work; + d->work_callback_ = work; d->data_ = data; - g_idle_add(AfterWorkCallback, d); + g_idle_add(WorkCallback, d); } } // namespace common diff --git a/src/exif/exif_instance.cc b/src/exif/exif_instance.cc index c632916c..28ae74c1 100644 --- a/src/exif/exif_instance.cc +++ b/src/exif/exif_instance.cc @@ -20,6 +20,7 @@ #include #include +#include #include #include diff --git a/src/package/package_instance.cc b/src/package/package_instance.cc index b944775f..a1ca8888 100644 --- a/src/package/package_instance.cc +++ b/src/package/package_instance.cc @@ -16,6 +16,7 @@ #include "package/package_instance.h" +#include #include #include diff --git a/src/sensor/sensor_service.cc b/src/sensor/sensor_service.cc index 1dcc339d..217ec36e 100644 --- a/src/sensor/sensor_service.cc +++ b/src/sensor/sensor_service.cc @@ -16,6 +16,7 @@ #include "sensor_service.h" +#include #include #include #include diff --git a/src/utils/utils_extension.cc b/src/utils/utils_extension.cc index 0b9d7a65..7cc85d3a 100644 --- a/src/utils/utils_extension.cc +++ b/src/utils/utils_extension.cc @@ -23,6 +23,7 @@ UtilsExtension::UtilsExtension() { UtilsExtension::~UtilsExtension() { ScopeLogger(); + common::TaskQueue::GetInstance().Stop(); } common::Instance* UtilsExtension::CreateInstance() { diff --git a/src/utils/utils_instance.h b/src/utils/utils_instance.h index c39a91d4..df065d52 100644 --- a/src/utils/utils_instance.h +++ b/src/utils/utils_instance.h @@ -7,6 +7,7 @@ #define UTILS_UTILS_INSTANCE_H_ #include "common/extension.h" +#include "common/task-queue.h" namespace extension { namespace utils { @@ -15,6 +16,9 @@ class UtilsInstance : public common::ParsedInstance { public: UtilsInstance(); virtual ~UtilsInstance() { + // At this point, frame of the page is destroyed or reloaded, so all the jobs have to be + // removed. + common::TaskQueue::GetInstance().DeleteJobs(); } private: