• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <broadcastradio-utils/WorkerThread.h>
18 
19 namespace android {
20 
21 using std::function;
22 using std::lock_guard;
23 using std::mutex;
24 using std::unique_lock;
25 using std::chrono::milliseconds;
26 using std::chrono::steady_clock;
27 using std::this_thread::sleep_for;
28 
operator <(const WorkerThread::Task & lhs,const WorkerThread::Task & rhs)29 bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) {
30     return lhs.when > rhs.when;
31 }
32 
WorkerThread()33 WorkerThread::WorkerThread() : mIsTerminating(false) {
34     // putting mThread in constructor instead of initializer list
35     // to ensure all class members are init before mThread starts
36     mThread = std::thread(&WorkerThread::threadLoop, this);
37 }
38 
~WorkerThread()39 WorkerThread::~WorkerThread() {
40     {
41         lock_guard<mutex> lk(mMut);
42         mIsTerminating = true;
43         mCond.notify_one();
44     }
45     mThread.join();
46 }
47 
schedule(function<void ()> task,milliseconds delay)48 void WorkerThread::schedule(function<void()> task, milliseconds delay) {
49     auto cancelTask = []() {};
50     schedule(std::move(task), cancelTask, delay);
51 }
52 
schedule(function<void ()> task,function<void ()> cancelTask,milliseconds delay)53 void WorkerThread::schedule(function<void()> task, function<void()> cancelTask,
54                             milliseconds delay) {
55     auto when = steady_clock::now() + delay;
56 
57     lock_guard<mutex> lk(mMut);
58     mTasks.push(Task({when, std::move(task), std::move(cancelTask)}));
59     mCond.notify_one();
60 }
61 
cancelAll()62 void WorkerThread::cancelAll() {
63     lock_guard<mutex> lk(mMut);
64     while (!mTasks.empty()) {
65         auto task = mTasks.top();
66         task.onCanceled();
67         mTasks.pop();
68     }
69 }
70 
threadLoop()71 void WorkerThread::threadLoop() {
72     while (true) {
73         unique_lock<mutex> lk(mMut);
74         if (mIsTerminating) {
75             return;
76         }
77         if (mTasks.empty()) {
78             mCond.wait(lk);
79             continue;
80         }
81 
82         auto task = mTasks.top();
83         if (task.when > steady_clock::now()) {
84             mCond.wait_until(lk, task.when);
85             continue;
86         }
87 
88         mTasks.pop();
89         lk.unlock();  // what() might need to schedule another task
90         task.what();
91     }
92 }
93 
94 }  // namespace android
95