[Common] Implementation for parallel Worker 94/182394/11
authorSzymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
Fri, 22 Jun 2018 11:38:55 +0000 (13:38 +0200)
committerSzymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
Tue, 25 Sep 2018 08:51:49 +0000 (10:51 +0200)
Change-Id: I93a0494cf5c943d2ead9e55957c25468764aebf8
Signed-off-by: Szymon Jastrzebski <s.jastrzebsk@partner.samsung.com>
src/application/application_manager.cc
src/common/task-queue.cpp
src/common/task-queue.h
src/exif/exif_instance.cc
src/package/package_instance.cc
src/sensor/sensor_service.cc
src/utils/utils_extension.cc
src/utils/utils_instance.h

index 23025be5344618dad59ebc8097c993ce68105111..fc6cf28d8ad617efc8697d381246196faae49b54 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "application_manager.h"
 
+#include <glib.h>
 #include <unistd.h>
 #include <type_traits>
 
index 9bafdae45e6be6bfa7a7a21699d7179f89c172f5..fe551a5ec0c0b0aed321886cac9b2f9a5b58ac5f 100644 (file)
@@ -24,44 +24,54 @@ TaskQueue& TaskQueue::GetInstance() {
 }
 
 template <>
-gboolean TaskQueue::AfterWorkCallback<void>(gpointer data) {
+gboolean TaskQueue::WorkCallback<void>(gpointer data) {
   QueueData<void>* d = static_cast<QueueData<void>*>(data);
   if (nullptr != d) {
-    d->after_work_callback_();
+    d->work_callback_();
     delete d;
   }
   return FALSE;
 }
 
-template <>
-void* TaskQueue::WorkCallback<void>(void* data) {
-  QueueData<void>* d = static_cast<QueueData<void>*>(data);
-  if (nullptr != d) {
-    d->work_callback_();
-    if (d->after_work_callback_) {
-      g_idle_add(AfterWorkCallback<void>, d);
-    }
-  }
-  return nullptr;
+void TaskQueue::Queue(const std::function<void()>& work, const std::function<void()>& after_work) {
+  auto do_work = [work, after_work]() {
+    work();
+    after_work();
+  };
+  this->queue_worker_.add_job(do_work);
 }
 
-void TaskQueue::Queue(const std::function<void()>& work, const std::function<void()>& after_work) {
-  QueueData<void>* d = new QueueData<void>();
-  d->work_callback_ = work;
-  d->after_work_callback_ = after_work;
+void TaskQueue::Async(const std::function<void()>& work) {
+  this->async_worker_.add_job(work);
+}
 
-  if (pthread_create(&d->thread_, nullptr, WorkCallback<void>, d) != 0) {
-    LoggerE("Failed to create a background thread.");
-    delete d;
-  } else {
-    pthread_detach(d->thread_);
+void TaskQueue::Async(const std::function<void(const common::AsyncToken& token)>& work,
+                      const common::AsyncToken& token) {
+  auto do_work = [work, token]() { work(token); };
+  Async(do_work);
+}
+
+void TaskQueue::DeleteJobs() {
+  {
+    std::lock_guard<std::mutex> lck{this->queue_worker_.jobs_mtx};
+    this->queue_worker_.jobs.clear();
+  }
+  {
+    std::lock_guard<std::mutex> lck{this->async_worker_.jobs_mtx};
+    this->async_worker_.jobs.clear();
   }
 }
 
-void TaskQueue::Async(const std::function<void()>& work) {
+void TaskQueue::Stop() {
+  LoggerI("Stopping TaskQueue workers");
+  queue_worker_.stop();
+  async_worker_.stop();
+}
+
+void TaskQueue::ScheduleWorkInMainThread(const std::function<void()>& work) {
   QueueData<void>* d = new QueueData<void>();
-  d->after_work_callback_ = work;
-  g_idle_add(AfterWorkCallback<void>, d);
+  d->work_callback_ = work;
+  g_idle_add(WorkCallback<void>, d);
 }
 
 }  // namespace common
index fb3300a3b90ff88d8f9c90e2c8287579ecf0394b..c44cc09c3262a7b65eda80908c61611ab43940dd 100644 (file)
 #include <functional>
 #include <memory>
 
-#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 <class T>
@@ -47,19 +79,17 @@ class TaskQueue {
              const std::shared_ptr<T>& 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<void()>& work,
-             const std::function<void()>& after_work = std::function<void()>());
+  void Queue(const std::function<void()>& work, const std::function<void()>& 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 <class T>
@@ -67,82 +97,98 @@ class TaskQueue {
              const std::shared_ptr<T>& 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<void()>& 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<void(const common::AsyncToken& token)>& 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 <class T>
+  void ScheduleWorkInMainThread(const std::function<void(const std::shared_ptr<T>&)>& work,
+                                const std::shared_ptr<T>& 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<void()>& work);
 
   template <class T>
   struct QueueData {
-    pthread_t thread_;
     std::function<void(const std::shared_ptr<T>&)> work_callback_;
-    std::function<void(const std::shared_ptr<T>&)> after_work_callback_;
     std::shared_ptr<T> data_;
   };
 
   template <class T>
-  static void* WorkCallback(void* data);
+  static gboolean WorkCallback(gpointer data);
 
-  template <class T>
-  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<void> {
-  pthread_t thread_;
   std::function<void()> work_callback_;
-  std::function<void()> after_work_callback_;
 };
 
 template <class T>
-gboolean TaskQueue::AfterWorkCallback(gpointer data) {
+gboolean TaskQueue::WorkCallback(gpointer data) {
   QueueData<T>* d = static_cast<QueueData<T>*>(data);
   if (nullptr != d) {
-    d->after_work_callback_(d->data_);
+    d->work_callback_(d->data_);
     delete d;
   }
   return FALSE;
 }
 
-template <class T>
-void* TaskQueue::WorkCallback(void* data) {
-  QueueData<T>* d = static_cast<QueueData<T>*>(data);
-  if (nullptr != d) {
-    d->work_callback_(d->data_);
-    g_idle_add(AfterWorkCallback<T>, d);
-  }
-  return nullptr;
-}
-
 template <class T>
 void TaskQueue::Queue(const std::function<void(const std::shared_ptr<T>&)>& work,
                       const std::function<void(const std::shared_ptr<T>&)>& after_work,
                       const std::shared_ptr<T>& data) {
-  QueueData<T>* d = new QueueData<T>();
-  d->work_callback_ = work;
-  d->after_work_callback_ = after_work;
-  d->data_ = data;
-
-  if (pthread_create(&d->thread_, nullptr, WorkCallback<T>, 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 <class T>
 void TaskQueue::Async(const std::function<void(const std::shared_ptr<T>&)>& work,
                       const std::shared_ptr<T>& data) {
+  auto do_work = [data, work]() { work(data); };
+  this->async_worker_.add_job(do_work);
+}
+
+template <class T>
+void TaskQueue::ScheduleWorkInMainThread(const std::function<void(const std::shared_ptr<T>&)>& work,
+                                         const std::shared_ptr<T>& data) {
   QueueData<T>* d = new QueueData<T>();
-  d->after_work_callback_ = work;
+  d->work_callback_ = work;
   d->data_ = data;
-  g_idle_add(AfterWorkCallback<T>, d);
+  g_idle_add(WorkCallback<T>, d);
 }
 
 }  // namespace common
index c632916c1f0d0edb9cda331ed9f77bd88a30bb9e..28ae74c156989c90ce4096d4a233c46baf78bd67 100644 (file)
@@ -20,6 +20,7 @@
 #include <libexif/exif-loader.h>
 #include <libexif/exif-utils.h>
 
+#include <glib.h>
 #include <sstream>
 #include <string>
 
index b944775f19596d740d5c7b5f663f35474bab116a..a1ca8888091682b07d04c6b4fd18c7454c9ab141 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "package/package_instance.h"
 
+#include <glib.h>
 #include <functional>
 #include <string>
 
index 1dcc339deb061fe33d6d8e671e918e74baa615a4..217ec36ec76130be35ed62497e34dcb53b4bfa30 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "sensor_service.h"
 
+#include <glib.h>
 #include <memory>
 #include <mutex>
 #include <string>
index 0b9d7a6545f0aa0f198f06f9987be4cf1a9c0700..7cc85d3a2dbc41835e83cafaba34cb8193069548 100644 (file)
@@ -23,6 +23,7 @@ UtilsExtension::UtilsExtension() {
 
 UtilsExtension::~UtilsExtension() {
   ScopeLogger();
+  common::TaskQueue::GetInstance().Stop();
 }
 
 common::Instance* UtilsExtension::CreateInstance() {
index c39a91d47ca9670a248dea78443c96318ad82027..df065d5279ef430bcb35fd274805ab4b1cfe669a 100644 (file)
@@ -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: