| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/lib/debug_ipc/helper/message_loop.h" |
| |
| #include "garnet/public/lib/fxl/logging.h" |
| |
| namespace debug_ipc { |
| |
| namespace { |
| |
| thread_local MessageLoop* current_message_loop = nullptr; |
| |
| } // namespace |
| |
| MessageLoop::MessageLoop() = default; |
| |
| MessageLoop::~MessageLoop() { |
| FXL_DCHECK(Current() != this); // Cleanup() should have been called. |
| } |
| |
| void MessageLoop::Init() { |
| FXL_DCHECK(!current_message_loop); |
| current_message_loop = this; |
| } |
| |
| void MessageLoop::Cleanup() { |
| FXL_DCHECK(current_message_loop == this); |
| current_message_loop = nullptr; |
| } |
| |
| // static |
| MessageLoop* MessageLoop::Current() { return current_message_loop; } |
| |
| void MessageLoop::Run() { |
| should_quit_ = false; |
| RunImpl(); |
| } |
| |
| void MessageLoop::PostTask(FileLineFunction file_line, |
| std::function<void()> fn) { |
| bool needs_awaken; |
| { |
| std::lock_guard<std::mutex> guard(mutex_); |
| needs_awaken = task_queue_.empty(); |
| task_queue_.push_back({std::move(file_line), std::move(fn)}); |
| } |
| if (needs_awaken) |
| SetHasTasks(); |
| } |
| |
| void MessageLoop::QuitNow() { should_quit_ = true; } |
| |
| bool MessageLoop::ProcessPendingTask() { |
| // This function will be called with the mutex held. |
| if (task_queue_.empty()) |
| return false; |
| |
| Task task = std::move(task_queue_.front()); |
| task_queue_.pop_front(); |
| { |
| mutex_.unlock(); |
| if (debug_mode()) { |
| FXL_LOG(INFO) << "Running task from [" << task.file_line.ToString() |
| << "]"; |
| } |
| task.task_fn(); |
| mutex_.lock(); |
| } |
| return true; |
| } |
| |
| MessageLoop::WatchHandle::WatchHandle() = default; |
| MessageLoop::WatchHandle::WatchHandle(MessageLoop* msg_loop, int id) |
| : msg_loop_(msg_loop), id_(id) {} |
| |
| MessageLoop::WatchHandle::WatchHandle(WatchHandle&& other) |
| : msg_loop_(other.msg_loop_), id_(other.id_) { |
| other.msg_loop_ = nullptr; |
| other.id_ = 0; |
| } |
| |
| MessageLoop::WatchHandle::~WatchHandle() { |
| StopWatching(); |
| } |
| |
| void MessageLoop::WatchHandle::StopWatching() { |
| if (watching()) |
| msg_loop_->StopWatching(id_); |
| msg_loop_ = nullptr; |
| id_ = 0; |
| } |
| |
| MessageLoop::WatchHandle& MessageLoop::WatchHandle::operator=( |
| WatchHandle&& other) { |
| // Should never get into a self-assignment situation since this is not |
| // copyable and every ID should be unique. Do allow self-assignment of |
| // null ones though. |
| FXL_DCHECK(!watching() || (msg_loop_ != other.msg_loop_ || id_ != other.id_)); |
| if (watching()) |
| msg_loop_->StopWatching(id_); |
| msg_loop_ = other.msg_loop_; |
| id_ = other.id_; |
| |
| other.msg_loop_ = nullptr; |
| other.id_ = 0; |
| return *this; |
| } |
| |
| } // namespace debug_ipc |