blob: 5a8359d3c3731596bde6dd928bc3a465bd1367cd [file] [log] [blame]
// Copyright 2022 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 SRC_MEDIA_AUDIO_LIB_CLOCK_SYNTHETIC_TIMER_H_
#define SRC_MEDIA_AUDIO_LIB_CLOCK_SYNTHETIC_TIMER_H_
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/time.h>
#include <memory>
#include <mutex>
#include <optional>
#include "src/media/audio/lib/clock/timer.h"
namespace media_audio {
// An implementation of Timer that is controlled by a SyntheticClockRealm. Once a thread blocks in
// SleepUntil(T), it does not unblock until receiving a call to AdvanceTo(T') where `T' >= T`.
//
// This class is thread safe.
class SyntheticTimer : public Timer {
public:
[[nodiscard]] static std::shared_ptr<SyntheticTimer> Create(zx::time mono_start_time);
// Implementation of Timer.
void SetShutdownBit() override;
void SetEventBit() override;
WakeReason SleepUntil(zx::time deadline) override;
void Stop() override;
// Blocks until stopped or until a thread is blocked in SleepUntil. This is intended to be used
// from SyntheticClockRealm using code like:
//
// ```
// void AdvanceTo(when) {
// while (now_ < when) {
// for (auto& t : timers) {
// t.WaitUntilSleepingOrStopped();
// }
//
// // Use SyntheticTimer::CurrentState to compute the next deadline and check
// // if any events are pending, then advance to the next deadline.
// }
// }
// ```
//
// May be called from any thread.
void WaitUntilSleepingOrStopped();
// Advances to the given system monotonic time. If a thread is currently blocked in
// `SleepUntil(deadline)` with `deadline <= t`, the blocked thread is woken. If called with `t <
// deadline`, the blocked thread will be woken iff there is a pending signal.
//
// May be called from any thread.
//
// REQUIRES: currently sleeping and t >= now.
void AdvanceTo(zx::time t);
struct State {
std::optional<zx::time> deadline; // std::nullopt if not sleeping
bool event_set; // true if the "event" bit is set
bool shutdown_set; // true if the "shutdown" bit is set
bool stopped; // true if stopped
};
// Reports the current state of this timer.
// May be called from any thread, however to ensure the state is not changing
// concurrently, this should not be called unless all threads are blocked. See
// example in the class comments.
State CurrentState();
// The current system monotonic time.
zx::time now();
private:
explicit SyntheticTimer(zx::time mono_start_time);
struct InternalState {
explicit InternalState(zx::time start_time) : now(start_time) {}
zx::time now;
bool event_set = false;
bool shutdown_set = false;
// Notified when any of the following fields change.
std::condition_variable cvar;
std::optional<zx::time> deadline_if_sleeping;
int64_t sleep_count = 0;
int64_t advance_count = 0;
int64_t wake_count = 0;
bool stopped = false;
};
std::mutex mutex_;
InternalState state_ TA_GUARDED(mutex_);
};
} // namespace media_audio
#endif // SRC_MEDIA_AUDIO_LIB_CLOCK_SYNTHETIC_TIMER_H_