blob: acbff625817dd8948c3e586d2b6f22136aea5c9b [file] [log] [blame]
// 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.
#ifndef GARNET_BIN_COBALT_APP_TIMER_MANAGER_H_
#define GARNET_BIN_COBALT_APP_TIMER_MANAGER_H_
#include <stdlib.h>
#include <chrono>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <unordered_map>
#include <fuchsia/cobalt/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/fxl/logging.h>
#include <lib/zx/time.h>
#include "garnet/lib/wlan/mlme/include/wlan/mlme/clock.h"
using fuchsia::cobalt::Status;
namespace cobalt {
// Used to store all necessary values for a Timer to be able to create an
// Observation.
struct TimerVal {
// The metric_id of the observation we will create.
uint32_t metric_id;
// The encoding_id used in the observation we will create.
uint32_t encoding_id;
// When the timer starts.
int64_t start_timestamp;
// When the timer ends.
int64_t end_timestamp;
// The time at which the timer is expired.
zx::time expiry_time;
// Task which will delete the timer once it is expired.
async::TaskClosure expiry_task;
// The name of the timer field/part if it is a multipart obervation.
std::string part_name;
// The remaining fields of a multipart obervation.
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> observation;
// Stores the start-related arguments in the given TimerVal.
void AddStart(uint32_t metric_id, uint32_t encoding_id, int64_t timestamp);
// Stores the end-related arguments in the given TimerVal.
void AddEnd(int64_t timestamp, const std::string& part_name,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> observation);
};
// Stores partial timer values as they are encountered. Once both the start and
// end value of the timer have been encountered the timer's values are returned
// as a TimerVal.
class TimerManager {
public:
// Constructs a TimerManager Object. Uses the given dispatcher to
// schedule tasks which delete timer data once it has expired.
TimerManager(async_dispatcher_t* dispatcher);
~TimerManager();
// Checks if the given TimerVal contains all the information it needs to send
// an observation. That means it was populated by both StartTimer and EndTimer
// calls.
static bool isReady(const std::unique_ptr<TimerVal>& timer_val_ptr);
// Checks if the given TimerVal contains a multipart observation.
static bool isMultipart(const std::unique_ptr<TimerVal>& timer_val_ptr);
// Checks that the arguments are valid timer arguments.
static bool isValidTimerArguments(fidl::StringPtr timer_id, int64_t timestamp,
uint32_t timeout_s);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the start data and resets the TimerVal ptr. If a timer with the
// same timer_id and different start timestamp exists it returns
// FAILED_PRECONDITION. If timer_ID or timeout_s is invalid, returns
// INVALID_ARGUMENTS.
Status GetTimerValWithStart(uint32_t metric_id, uint32_t encoding_id,
const std::string& timer_id, int64_t timestamp,
uint32_t timeout_s,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the end data and resets the TimerVal ptr. If a timer with the
// same timer_id and different end timestamp exists it returns an error.
Status GetTimerValWithEnd(const std::string& timer_id, int64_t timestamp,
uint32_t timeout_s,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Populates the TimerVal parameter with the timer's values if there is a
// valid timer with the timer_id. If no valid timer exists it creates a new
// timer with the end data and resets the TimerVal ptr. If a timer with the
// same timer_id and different end timestamp exists it returns an error.
Status GetTimerValWithEnd(
const std::string& timer_id, int64_t timestamp, uint32_t timeout_s,
const std::string& part_name,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> observation,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Tests can use private methods for setup.
friend class TimerManagerTests;
private:
// Used for testing.
void SetClockForTesting(std::shared_ptr<wlan::Clock> clock) {
clock_ = clock;
}
// Schedules a task which will delete the timer entries associated with
// timer_id when it expires.
// timeout_s : the timer timer_id will be deleted after timeout_s seconds.
// timer_val_ptr : the task will be stored in the given object until it is
// executed or cancelled. Deleting the TimerVal will cancel
// the task.
void ScheduleExpiryTask(const std::string& timer_id, uint32_t timeout_s,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Copies the data found in the iterator entry to the TimerVal pointer
// provided. It then deletes the data associated with it from the map, which
// includes cancelling the pending expiry task.
void MoveTimerToTimerVal(
std::unordered_map<std::string, std::unique_ptr<TimerVal>>::iterator*
timer_val_iter,
std::unique_ptr<TimerVal>* timer_val_ptr);
// Map from timer_id to the TimerVal values associated with it.
std::unordered_map<std::string, std::unique_ptr<TimerVal>> timer_values_;
// The clock is abstracted so that friend tests can set a non-system clock.
std::shared_ptr<wlan::Clock> clock_;
// Async dispatcher used for deleting expired timer entries.
async_dispatcher_t* const dispatcher_; // not owned.
};
} // namespace cobalt
#endif // GARNET_BIN_COBALT_APP_TIMER_MANAGER_H_