From 21d3dfca4e47c211aa3bac197dda906e6f35fda5 Mon Sep 17 00:00:00 2001 From: Timothy Hutchins Date: Sun, 6 Aug 2023 18:28:46 -0500 Subject: [PATCH] Implemented scheduled_executor --- .../linux/scheduled_executor.cc | 82 ++++++++++++++ .../implementation/linux/scheduled_executor.h | 100 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 internal/platform/implementation/linux/scheduled_executor.cc create mode 100644 internal/platform/implementation/linux/scheduled_executor.h diff --git a/internal/platform/implementation/linux/scheduled_executor.cc b/internal/platform/implementation/linux/scheduled_executor.cc new file mode 100644 index 00000000..ff8b3a1d --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor.cc @@ -0,0 +1,82 @@ +// Copyright 2021 Google LLC +// +// 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 +// +// https://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 "internal/platform/implementation/linux/scheduled_executor.h" + +#include +#include +#include + +#include "absl/time/time.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace linux { + +ScheduledExecutor::ScheduledExecutor() + : executor_(std::make_unique()), + shut_down_(false) {} + +// Cancelable is kept both in the executor context, and in the caller context. +// We want Cancelable to live until both caller and executor are done with it. +// Exclusive ownership model does not work for this case; +// using std:shared_ptr<> instead of std::unique_ptr<>. +std::shared_ptr ScheduledExecutor::Schedule( + Runnable&& runnable, absl::Duration duration) { + if (shut_down_) { + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Schedule on a shut down executor."; + + return nullptr; + } + + // Cleans completed tasks + std::remove_if( + scheduled_tasks_.begin(), scheduled_tasks_.end(), + [](std::shared_ptr& task) { return task->IsDone(); }); + + std::shared_ptr task = + std::make_shared(std::move(runnable), duration); + + scheduled_tasks_.push_back(task); + executor_->Execute([task]() { task->Start(); }); + return task; +} + +void ScheduledExecutor::Execute(Runnable&& runnable) { + if (shut_down_) { + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Execute on a shut down executor."; + return; + } + + executor_->Execute(std::move(runnable)); +} + +void ScheduledExecutor::Shutdown() { + if (!shut_down_) { + shut_down_ = true; + for (auto& task : scheduled_tasks_) { + task->Cancel(); + } + + scheduled_tasks_.clear(); + executor_->Shutdown(); + return; + } + NEARBY_LOGS(ERROR) << __func__ + << ": Attempt to Shutdown on a shut down executor."; +} +} // namespace linux +} // namespace nearby diff --git a/internal/platform/implementation/linux/scheduled_executor.h b/internal/platform/implementation/linux/scheduled_executor.h new file mode 100644 index 00000000..4dffef8b --- /dev/null +++ b/internal/platform/implementation/linux/scheduled_executor.h @@ -0,0 +1,100 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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. + +#ifndef PLATFORM_IMPL_LINUX_SCHEDULED_EXECUTOR_H_ +#define PLATFORM_IMPL_LINUX_SCHEDULED_EXECUTOR_H_ + +#include +#include +#include + +#include "absl/synchronization/notification.h" +#include "absl/time/time.h" +#include "internal/platform/implementation/cancelable.h" +#include "internal/platform/implementation/scheduled_executor.h" +#include "internal/platform/implementation/linux/executor.h" + +namespace nearby { +namespace linux { + +#define TIMER_NAME_BUFFER_SIZE 64 + +// An Executor that can schedule commands to run after a given delay, or to +// execute periodically. +// +// https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html +class ScheduledExecutor : public api::ScheduledExecutor { + public: + ScheduledExecutor(); + + ~ScheduledExecutor() override = default; + + // Cancelable is kept both in the executor context, and in the caller context. + // We want Cancelable to live until both caller and executor are done with it. + // Exclusive ownership model does not work for this case; + // using std:shared_ptr<> instead if std::unique_ptr<>. + std::shared_ptr Schedule(Runnable&& runnable, + absl::Duration duration) override; + + // Executes the runnable task immedately. + void Execute(Runnable&& runnable) override; + + // Shutdowns the executor, all scheduled task will be cancelled. + void Shutdown() override; + + private: + class ScheduledTask : public api::Cancelable { + public: + explicit ScheduledTask(Runnable&& task, absl::Duration duration) + : task_(std::move(task)), duration_(duration) {} + + bool Cancel() override { + if (is_executed_ || is_cancelled_) { + return false; + } + + is_cancelled_ = true; + notification_.Notify(); + return true; + }; + + void Start() { + if (is_executed_ || + notification_.WaitForNotificationWithTimeout(duration_)) { + return; + } + + is_executed_ = true; + task_(); + } + + bool IsDone() const { return is_cancelled_ || is_executed_; } + + private: + Runnable task_; + absl::Duration duration_; + absl::Notification notification_; + bool is_cancelled_ = false; + bool is_executed_ = false; + }; + + std::unique_ptr executor_ = nullptr; + std::vector> scheduled_tasks_; + std::atomic_bool shut_down_ = false; +}; + +} // namespace linux +} // namespace nearby + +#endif // PLATFORM_IMPL_LINUX_SCHEDULED_EXECUTOR_H_