131 lines
3.2 KiB
C++
131 lines
3.2 KiB
C++
//
|
|
// Copyright (C) 2020 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "host/commands/modem_simulator/thread_looper.h"
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
namespace cuttlefish {
|
|
|
|
ThreadLooper::ThreadLooper()
|
|
: stopped_(false), next_serial_(1) {
|
|
looper_thread_ = std::thread([this]() { ThreadLoop(); });
|
|
}
|
|
|
|
ThreadLooper::~ThreadLooper() { Stop(); }
|
|
|
|
bool ThreadLooper::Event::operator<=(const Event &other) const {
|
|
return when <= other.when;
|
|
}
|
|
|
|
ThreadLooper::Serial ThreadLooper::Post(Callback cb) {
|
|
CHECK(cb != nullptr);
|
|
|
|
auto serial = next_serial_++;
|
|
// If it's the time to process event with delay exactly when posting
|
|
// a event without delay. Looper would process the event without delay firstly
|
|
// if when set to be std::nullptr. so set when_ to be now.
|
|
Insert({ std::chrono::steady_clock::now(), cb, serial });
|
|
|
|
return serial;
|
|
}
|
|
|
|
ThreadLooper::Serial ThreadLooper::Post(
|
|
Callback cb, std::chrono::steady_clock::duration delay) {
|
|
CHECK(cb != nullptr);
|
|
|
|
auto serial = next_serial_++;
|
|
Insert({ std::chrono::steady_clock::now() + delay, cb, serial });
|
|
|
|
return serial;
|
|
}
|
|
|
|
bool ThreadLooper::CancelSerial(Serial serial) {
|
|
std::lock_guard<std::mutex> autolock(lock_);
|
|
|
|
bool found = false;
|
|
for (auto iter = queue_.begin(); iter != queue_.end(); ++iter) {
|
|
if (iter->serial == serial) {
|
|
queue_.erase(iter);
|
|
cond_.notify_all();
|
|
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void ThreadLooper::Insert(const Event &event) {
|
|
std::lock_guard<std::mutex> autolock(lock_);
|
|
|
|
auto iter = queue_.begin();
|
|
while (iter != queue_.end() && *iter <= event) {
|
|
++iter;
|
|
}
|
|
|
|
queue_.insert(iter, event);
|
|
cond_.notify_all();
|
|
}
|
|
|
|
void ThreadLooper::ThreadLoop() {
|
|
for(;;) {
|
|
Callback cb;
|
|
{
|
|
std::unique_lock<std::mutex> lock(lock_);
|
|
|
|
if (stopped_) {
|
|
break;
|
|
}
|
|
|
|
if (queue_.empty()) {
|
|
cond_.wait(lock);
|
|
continue;
|
|
}
|
|
|
|
auto time_to_wait = queue_.front().when - std::chrono::steady_clock::now();
|
|
if (time_to_wait.count() > 0) {
|
|
// wait with timeout
|
|
auto durationMs =
|
|
std::chrono::duration_cast<std::chrono::milliseconds>(time_to_wait);
|
|
cond_.wait_for(lock, durationMs);
|
|
continue;
|
|
}
|
|
cb = queue_.front().cb; // callback at front of queue
|
|
queue_.pop_front();
|
|
}
|
|
cb();
|
|
}
|
|
}
|
|
|
|
void ThreadLooper::Stop() {
|
|
if (stopped_) {
|
|
return;
|
|
}
|
|
CHECK(looper_thread_.get_id() != std::this_thread::get_id())
|
|
<< "Destructor called from looper thread";
|
|
{
|
|
std::lock_guard<std::mutex> autolock(lock_);
|
|
stopped_ = true;
|
|
}
|
|
cond_.notify_all();
|
|
if (looper_thread_.joinable()) {
|
|
looper_thread_.join();
|
|
}
|
|
}
|
|
|
|
} // namespace cuttlefish
|