instead of sleep_{ns,ms} we now have sleep_{for,until}_{ns,ms}. This
makes code cleaner that just wants to sleep until some timestamp
112 lines
2.3 KiB
C++
112 lines
2.3 KiB
C++
#pragma once
|
|
|
|
#include <BAN/UniqPtr.h>
|
|
#include <BAN/Vector.h>
|
|
#include <kernel/Memory/DMARegion.h>
|
|
#include <kernel/Timer/RTC.h>
|
|
|
|
#include <time.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
class Timer
|
|
{
|
|
public:
|
|
virtual ~Timer() {};
|
|
virtual uint64_t ms_since_boot() const = 0;
|
|
virtual uint64_t ns_since_boot() const = 0;
|
|
virtual timespec time_since_boot() const = 0;
|
|
|
|
virtual bool pre_scheduler_sleep_needs_lock() const = 0;
|
|
virtual void pre_scheduler_sleep_ns(uint64_t) = 0;
|
|
|
|
protected:
|
|
bool should_invoke_scheduler() const { return m_should_invoke_scheduler; }
|
|
|
|
private:
|
|
bool m_should_invoke_scheduler { true };
|
|
friend class SystemTimer;
|
|
};
|
|
|
|
class SystemTimer : public Timer
|
|
{
|
|
public:
|
|
struct TSCInfo
|
|
{
|
|
int8_t shift;
|
|
uint32_t mult;
|
|
};
|
|
|
|
public:
|
|
static void initialize();
|
|
static SystemTimer& get();
|
|
static bool is_initialized();
|
|
|
|
void initialize_tsc();
|
|
|
|
virtual uint64_t ms_since_boot() const override;
|
|
virtual uint64_t ns_since_boot() const override;
|
|
virtual timespec time_since_boot() const override;
|
|
|
|
virtual bool pre_scheduler_sleep_needs_lock() const override;
|
|
virtual void pre_scheduler_sleep_ns(uint64_t) override;
|
|
|
|
void sleep_for_ns(uint64_t timeout_ns) const;
|
|
void sleep_until_ns(uint64_t waketime_ns) const;
|
|
|
|
void sleep_for_ms(uint64_t timeout_ms) const
|
|
{
|
|
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(timeout_ms, 1'000'000));
|
|
return sleep_for_ns(timeout_ms * 1'000'000);
|
|
}
|
|
void sleep_until_ms(uint64_t waketime_ms) const
|
|
{
|
|
ASSERT(!BAN::Math::will_multiplication_overflow<uint64_t>(waketime_ms, 1'000'000));
|
|
return sleep_until_ns(waketime_ms * 1'000'000);
|
|
}
|
|
|
|
void dont_invoke_scheduler() { m_timer->m_should_invoke_scheduler = false; }
|
|
|
|
void update_tsc();
|
|
TSCInfo tsc_info() const;
|
|
|
|
uint64_t ns_since_boot_no_tsc() const { return m_timer->ns_since_boot(); }
|
|
|
|
timespec real_time() const;
|
|
|
|
private:
|
|
SystemTimer() = default;
|
|
|
|
void initialize_timers();
|
|
|
|
void initialize_invariant_tsc();
|
|
void initialize_pvclock();
|
|
|
|
private:
|
|
enum class TSCType
|
|
{
|
|
None,
|
|
Invariant,
|
|
PVClock,
|
|
};
|
|
|
|
uint64_t m_boot_time { 0 };
|
|
BAN::UniqPtr<RTC> m_rtc;
|
|
BAN::UniqPtr<Timer> m_timer;
|
|
|
|
TSCType m_tsc_type = TSCType::None;
|
|
|
|
union {
|
|
struct {
|
|
int8_t shift;
|
|
uint32_t mult;
|
|
} invariant;
|
|
} m_tsc_info;
|
|
|
|
BAN::UniqPtr<DMARegion> m_tsc_page;
|
|
uint64_t m_tsc_update_ns { 0 };
|
|
};
|
|
|
|
}
|