Merge changes from topic 'taskrunner_details'
am: f11ca98fa0

Change-Id: I8a9173faa1426e15a73bd794e5e328b360bdab45
diff --git a/base/TaskRunner.cpp b/base/TaskRunner.cpp
index 2f7d89c..33117e7 100644
--- a/base/TaskRunner.cpp
+++ b/base/TaskRunner.cpp
@@ -19,30 +19,31 @@
 
 namespace android {
 namespace hardware {
+namespace details {
 
 TaskRunner::TaskRunner() {
-    bool *running = mRunning = new bool();
-    SynchronizedQueue<std::function<void(void)>> *q
-            = mQueue = new SynchronizedQueue<std::function<void(void)>>();
-    mThread = new std::thread([running, q] {
-        *running = true;
-        while (*running) {
-            (q->wait_pop())();
-        }
-        delete q;
-        delete running;
-    });
-}
-TaskRunner::~TaskRunner() {
-    bool *running = mRunning;
-    std::thread *t = mThread;
-    mThread->detach();
-    mQueue->push([running, t] {
-        *running = false;
-        delete t;
-    });
 }
 
+void TaskRunner::start(size_t limit) {
+    mQueue = std::make_shared<SynchronizedQueue<Task>>(limit);
+
+    // Allow the thread to continue running in background;
+    // TaskRunner do not care about the std::thread object.
+    std::thread{[q = mQueue] {
+        Task nextTask;
+        while (!!(nextTask = q->wait_pop())) {
+            nextTask();
+        }
+    }}.detach();
+}
+
+TaskRunner::~TaskRunner() {
+    if (mQueue) {
+        mQueue->push(nullptr);
+    }
+}
+
+} // namespace details
 } // namespace hardware
 } // namespace android
 
diff --git a/base/include/hidl/SynchronizedQueue.h b/base/include/hidl/SynchronizedQueue.h
index 80123ba..efb04e0 100644
--- a/base/include/hidl/SynchronizedQueue.h
+++ b/base/include/hidl/SynchronizedQueue.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SYNCHRONIZED_QUEUE_H
-#define ANDROID_SYNCHRONIZED_QUEUE_H
+#ifndef ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
+#define ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
 
 #include <condition_variable>
 #include <mutex>
@@ -24,10 +24,12 @@
 
 namespace android {
 namespace hardware {
+namespace details {
 /* Threadsafe queue.
  */
 template <typename T>
 struct SynchronizedQueue {
+    SynchronizedQueue(size_t limit);
 
     /* Gets an item from the front of the queue.
      *
@@ -43,19 +45,18 @@
      */
     size_t size();
 
-    /* Sets the limit to the queue. Will fail
-     * the push operation if the limit is reached.
-     */
-    void setLimit(size_t limit);
-
 private:
     std::condition_variable mCondition;
     std::mutex mMutex;
     std::queue<T> mQueue;
-    size_t mQueueLimit = SIZE_MAX;
+    const size_t mQueueLimit;
 };
 
 template <typename T>
+SynchronizedQueue<T>::SynchronizedQueue(size_t limit) : mQueueLimit(limit) {
+}
+
+template <typename T>
 T SynchronizedQueue<T>::wait_pop() {
     std::unique_lock<std::mutex> lock(mMutex);
 
@@ -93,14 +94,8 @@
     return mQueue.size();
 }
 
-template <typename T>
-void SynchronizedQueue<T>::setLimit(size_t limit) {
-    std::unique_lock<std::mutex> lock(mMutex);
-
-    mQueueLimit = limit;
-}
-
+} // namespace details
 } // namespace hardware
 } // namespace android
 
-#endif
+#endif // ANDROID_HIDL_SYNCHRONIZED_QUEUE_H
diff --git a/base/include/hidl/TaskRunner.h b/base/include/hidl/TaskRunner.h
index bc9087f..8ecceca 100644
--- a/base/include/hidl/TaskRunner.h
+++ b/base/include/hidl/TaskRunner.h
@@ -13,56 +13,55 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef ANDROID_TASK_RUNNER_H
-#define ANDROID_TASK_RUNNER_H
+#ifndef ANDROID_HIDL_TASK_RUNNER_H
+#define ANDROID_HIDL_TASK_RUNNER_H
 
 #include "SynchronizedQueue.h"
+#include <memory>
 #include <thread>
 
 namespace android {
 namespace hardware {
+namespace details {
 
 /*
  * A background infinite loop that runs the Tasks push()'ed.
- * Just a simple single-threaded thread pool.
+ * Equivalent to a simple single-threaded Looper.
  */
 class TaskRunner {
 public:
+    using Task = std::function<void(void)>;
 
-    /* Kicks off the loop immediately. */
+    /* Create an empty task runner. Nothing will be done until start() is called. */
     TaskRunner();
 
     /*
-     * Detaches the background thread and return immediately.
-     * Tasks in the queue will continue to be done sequentially, and _after_
-     * all tasks are done, the background thread releases the resources
-     * (the queue, the std::thread object, etc.)
+     * Notify the background thread to terminate and return immediately.
+     * Tasks in the queue will continue to be done sequentially in background
+     * until all tasks are finished.
      */
     ~TaskRunner();
 
     /*
-     * Add a task. Return true if successful, false if
-     * the queue's size exceeds limit.
+     * Sets the queue limit. Fails the push operation once the limit is reached.
+     * Then kicks off the loop.
      */
-    inline bool push(const std::function<void(void)> &t) {
-        return this->mQueue->push(t);
-    }
+    void start(size_t limit);
 
     /*
-     * Sets the queue limit. Fails the push operation once the limit is reached.
+     * Add a task. Return true if successful, false if
+     * the queue's size exceeds limit or t doesn't contain a callable target.
      */
-    inline void setLimit(size_t limit) {
-        this->mQueue->setLimit(limit);
+    inline bool push(const Task &t) {
+        return (mQueue != nullptr) && (!!t) && this->mQueue->push(t);
     }
-private:
 
-    // resources managed by the background thread.
-    bool *mRunning;
-    SynchronizedQueue<std::function<void(void)>> *mQueue;
-    std::thread *mThread;
+private:
+    std::shared_ptr<SynchronizedQueue<Task>> mQueue;
 };
 
+} // namespace details
 } // namespace hardware
 } // namespace android
 
-#endif // ANDROID_TASK_RUNNER_H
+#endif // ANDROID_HIDL_TASK_RUNNER_H
diff --git a/test_main.cpp b/test_main.cpp
index 7ff8ae3..7859156 100644
--- a/test_main.cpp
+++ b/test_main.cpp
@@ -255,8 +255,9 @@
 }
 
 TEST_F(LibHidlTest, TaskRunnerTest) {
-    using android::hardware::TaskRunner;
+    using android::hardware::details::TaskRunner;
     TaskRunner tr;
+    tr.start(1 /* limit */);
     bool flag = false;
     tr.push([&] {
         usleep(1000);