/* * Copyright 2019 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 "os/handler.h" #include #include #include #include "common/bind.h" #include "common/callback.h" #include "os/log.h" #include "os/reactor.h" #include "os/utils.h" #ifndef EFD_SEMAPHORE #define EFD_SEMAPHORE 1 #endif namespace bluetooth { namespace os { using common::OnceClosure; Handler::Handler(Thread* thread) : tasks_(new std::queue()), thread_(thread), fd_(eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) { ASSERT(fd_ != -1); reactable_ = thread_->GetReactor()->Register( fd_, common::Bind(&Handler::handle_next_event, common::Unretained(this)), common::Closure()); } Handler::~Handler() { { std::lock_guard lock(mutex_); ASSERT_LOG(was_cleared(), "Handlers must be cleared before they are destroyed"); } int close_status; RUN_NO_INTR(close_status = close(fd_)); ASSERT(close_status != -1); } void Handler::Post(OnceClosure closure) { { std::lock_guard lock(mutex_); if (was_cleared()) { LOG_WARN("Posting to a handler which has been cleared"); return; } tasks_->emplace(std::move(closure)); } uint64_t val = 1; auto write_result = eventfd_write(fd_, val); ASSERT(write_result != -1); } void Handler::Clear() { std::queue* tmp = nullptr; { std::lock_guard lock(mutex_); ASSERT_LOG(!was_cleared(), "Handlers must only be cleared once"); std::swap(tasks_, tmp); } delete tmp; uint64_t val; while (eventfd_read(fd_, &val) == 0) { } thread_->GetReactor()->Unregister(reactable_); reactable_ = nullptr; } void Handler::WaitUntilStopped(std::chrono::milliseconds timeout) { ASSERT(reactable_ == nullptr); ASSERT(thread_->GetReactor()->WaitForUnregisteredReactable(timeout)); } void Handler::handle_next_event() { common::OnceClosure closure; { std::lock_guard lock(mutex_); uint64_t val = 0; auto read_result = eventfd_read(fd_, &val); if (was_cleared()) { return; } ASSERT_LOG(read_result != -1, "eventfd read error %d %s", errno, strerror(errno)); closure = std::move(tasks_->front()); tasks_->pop(); } std::move(closure).Run(); } } // namespace os } // namespace bluetooth