Coverage Report

Created: 2026-07-26 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gbmcweb/tlbmc/scheduler/scheduler.h
Line
Count
Source
1
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SCHEDULER_SCHEDULER_H_
2
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SCHEDULER_SCHEDULER_H_
3
4
#include <stdbool.h>
5
6
#include <atomic>
7
#include <cstddef>
8
#include <cstdint>
9
#include <memory>
10
#include <optional>
11
#include <thread>
12
13
#include "absl/base/thread_annotations.h"
14
#include "absl/container/flat_hash_map.h"
15
#include "absl/functional/any_invocable.h"
16
#include "absl/synchronization/mutex.h"
17
#include "absl/time/time.h"
18
#include "boost/asio/steady_timer.hpp"
19
#include <boost/asio/executor_work_guard.hpp>
20
#include "boost/circular_buffer.hpp"  //NOLINT: boost is commonly used in BMC
21
#include "time/clock.h"
22
#include "nlohmann/json.hpp"
23
24
namespace milotic_tlbmc {
25
26
// Represents the time information of a task.
27
struct TimeInfo {
28
  absl::Time last_scheduled_time = absl::InfiniteFuture();
29
  absl::Time last_run_time = absl::InfiniteFuture();
30
  boost::circular_buffer<absl::Duration> wait_times =
31
      boost::circular_buffer<absl::Duration>(1000);
32
33
  nlohmann::json ToJson() const;
34
};
35
36
// Represents the mode of a task.
37
//
38
// kPeriodic: The task will be scheduled periodically.
39
// kOnce: The task will be cancelled after it is executed once.
40
enum class TaskMode : uint8_t {
41
  kPeriodic = 0,
42
  kOnce,
43
};
44
45
// Represents a single task to be scheduled and run.
46
class Task : public std::enable_shared_from_this<Task> {
47
 public:
48
  Task(int task_id,
49
       absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task_fn,
50
       absl::Duration period, boost::asio::io_context* io,
51
       absl::Duration task_timeout, TaskMode task_mode = TaskMode::kPeriodic,
52
       ecclesia::Clock* clock = ecclesia::Clock::RealClock());
53
54
  void Run() ABSL_LOCKS_EXCLUDED(task_mutex_, time_info_mutex_);
55
  void ScheduleNextRun() ABSL_LOCKS_EXCLUDED(timer_mutex_);
56
  absl::Duration GetPeriod() const;
57
  void SetPeriod(absl::Duration period);
58
  void Cancel() ABSL_LOCKS_EXCLUDED(timer_mutex_);
59
  void OnDone() ABSL_LOCKS_EXCLUDED(timer_mutex_, time_info_mutex_);
60
0
  bool IsCancelled() const { return cancelled_.load(); }
61
0
  int GetExecutionCount() const { return execution_count_.load(); }
62
  absl::Time GetLastRunTime() const ABSL_LOCKS_EXCLUDED(time_info_mutex_);
63
  absl::Duration GetAverageWaitTime() const
64
      ABSL_LOCKS_EXCLUDED(time_info_mutex_);
65
0
  absl::Duration GetTaskTimeout() const { return task_timeout_; }
66
  nlohmann::json ToJson() const;
67
68
 private:
69
  const int task_id_;
70
  const TaskMode task_mode_;
71
  // Ecclesia clock is thread safe.
72
  ecclesia::Clock* clock_ = nullptr;
73
  std::atomic<absl::Duration> period_ = absl::InfiniteDuration();
74
  std::atomic<bool> cancelled_ = false;
75
  std::atomic<int> execution_count_ = 0;
76
  std::atomic<absl::Duration> last_execution_duration_ = absl::ZeroDuration();
77
78
  // Task function to be executed.
79
  // task_fn_with_ack_: This is used for async tasks i.e tasks with
80
  // TaskMode kPeriodic that have an ack callback.
81
  absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task_fn_with_ack_
82
      ABSL_GUARDED_BY(task_mutex_) = nullptr;
83
  mutable absl::Mutex task_mutex_;
84
85
  // TimeInfo to capture the last, next and average wait time.
86
  TimeInfo time_info_ ABSL_GUARDED_BY(time_info_mutex_);
87
  mutable absl::Mutex time_info_mutex_;
88
89
  // Timer to schedule the task.
90
  // Mainly used for async tasks.
91
  std::unique_ptr<boost::asio::steady_timer> timer_
92
      ABSL_GUARDED_BY(timer_mutex_) = nullptr;
93
  absl::Mutex timer_mutex_;
94
  const absl::Duration task_timeout_;
95
};
96
97
// Schedules tasks with a given periodicity.
98
//
99
// The scheduler is responsible for creating a thread for each period and
100
// scheduling the tasks to run on the corresponding thread based on the period.
101
// The scheduler also provides a way to reschedule a task with a new period and
102
// cancel a task.
103
//
104
// The scheduler is thread safe.
105
class TaskScheduler {
106
 public:
107
  // Options to configure the scheduler.
108
  struct Options {
109
    // Default options for the scheduler.
110
    //
111
    // Cleanup tasks period is set to 10 seconds arbitrarily, not shorter to
112
    // prevent overloading scheduler for cleanup tasks.
113
    //
114
    // Default task timeout is set to 60 seconds to allow for long running
115
    // tasks to complete which today aligns with the default timeout for
116
    // Redfish requests on client side.
117
    Options()
118
2.04k
        : cleanup_tasks_period(absl::Seconds(10)),
119
2.04k
          default_task_timeout(absl::Seconds(60)) {}
120
121
    absl::Duration cleanup_tasks_period;
122
    absl::Duration default_task_timeout;
123
  };
124
125
  explicit TaskScheduler(ecclesia::Clock* clock = ecclesia::Clock::RealClock(),
126
                         const Options& options = Options());
127
  virtual ~TaskScheduler();
128
  // Schedules the `task` for async invocation with the given `period`.
129
  //
130
  // The `task` will be invoked with a `on_done` callback as a parameter.
131
  // The `on_done` callback will be invoked when the task is done.
132
  // The `timeout` parameter is the timeout for the task to complete. If not
133
  // specified, the infinite timeout is used. If a task is not completed within
134
  // the timeout, the task will be cancelled.
135
  int RunAndScheduleAsync(
136
      absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task,
137
      absl::Duration period,
138
      std::optional<absl::Duration> timeout = absl::InfiniteDuration());
139
140
  // Same as RunAndScheduleAsync but does not run the task immediately before
141
  // scheduling it.
142
  int ScheduleAsync(
143
      absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task,
144
      absl::Duration period,
145
      std::optional<absl::Duration> timeout = absl::InfiniteDuration());
146
147
  // Schedule a oneshot task that is async.
148
  int ScheduleOneShotAsync(
149
      absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task,
150
      absl::Duration period,
151
      std::optional<absl::Duration> timeout = std::nullopt);
152
153
  void UpdateTaskPeriod(int task_id, absl::Duration period)
154
      ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
155
  void Cancel(int task_id) ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
156
  void CancelAll() ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
157
  void Stop() ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
158
  size_t GetSchedulingAccuracyPercentage() const;
159
  nlohmann::json ToJson() const;
160
161
  // This only counts the number of user scheduled async tasks.
162
  size_t GetAllUserTaskCount() const ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
163
  // This counts the number of all tasks including the internal scheduler tasks.
164
  size_t GetAllTaskCount() const ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
165
166
 protected:
167
  virtual absl::flat_hash_map<int, std::shared_ptr<Task>> GetSnapshot() const
168
      ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
169
170
  void CleanupInactiveTasks() ABSL_LOCKS_EXCLUDED(async_tasks_mutex_);
171
172
 private:
173
  enum class ExecutionMode : uint8_t {
174
    kRunImmediately = 0,
175
    kRunAfterScheduling,
176
  };
177
178
  int ScheduleAsyncInternal(
179
      absl::AnyInvocable<void(absl::AnyInvocable<void()>)> task,
180
      absl::Duration period, std::optional<absl::Duration> timeout,
181
      ExecutionMode execution_mode);
182
183
  std::atomic<int> next_task_id_;
184
  mutable absl::Mutex async_tasks_mutex_;
185
  absl::flat_hash_map<int, std::shared_ptr<Task>> id_to_async_tasks_
186
      ABSL_GUARDED_BY(async_tasks_mutex_);
187
  ecclesia::Clock* clock_;
188
  std::unique_ptr<boost::asio::io_context> io_;
189
  boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
190
      work_guard_;
191
  std::thread async_executor_thread_;
192
  std::atomic<bool> stop_ = false;
193
  std::atomic<int> cleanup_task_id_ = -1;
194
  absl::Duration default_task_timeout_;
195
};
196
197
}  // namespace milotic_tlbmc
198
199
#endif  // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_SCHEDULER_SCHEDULER_H_