blob: 3dae82d188c5ff1193c704bd13827de5410223fd [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_MEMORY_WATCHDOG_H_
#define ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_MEMORY_WATCHDOG_H_
#include <inttypes.h>
#include <lib/cmdline.h>
#include <lib/crashlog.h>
#include <zircon/boot/crash-reason.h>
#include <zircon/syscalls/object.h>
#include <zircon/types.h>
#include <object/diagnostics.h>
#include <object/event_dispatcher.h>
#include <object/job_dispatcher.h>
#include <object/port_dispatcher.h>
#include <platform/crashlog.h>
class Executor;
class MemoryWatchdog {
public:
enum PressureLevel : uint8_t {
kOutOfMemory = 0,
kCritical,
kWarning,
kNormal,
kNumLevels,
};
void Init(Executor* executor);
fbl::RefPtr<EventDispatcher> GetMemPressureEvent(uint32_t kind);
private:
// The callback provided to |pmm_init_reclamation|.
static void AvailableStateUpdatedCallback(void* context, uint8_t idx);
void AvailableStateUpdate(uint8_t idx);
// The callback provided to the |eviction_trigger_| timer.
static void EvictionTriggerCallback(Timer* timer, zx_time_t now, void* arg);
void EvictionTrigger();
void WorkerThread() __NO_RETURN;
// Helper called by the WorkerThread when OOM conditions are hit.
void OnOom();
// Called by the WorkerThread to determine if a kernel event needs to be signaled corresponding to
// pressure change to level |idx|.
inline bool IsSignalDue(PressureLevel idx, zx_time_t time_now) const;
// Called by the WorkerThread to determine if kernel eviction (asynchronous) needs to be triggered
// in response to pressure change to level |idx|.
inline bool IsEvictionRequired(PressureLevel idx) const;
// Kernel-owned events used to signal userspace at different levels of memory pressure.
ktl::array<fbl::RefPtr<EventDispatcher>, PressureLevel::kNumLevels> mem_pressure_events_;
// Event used for communicating memory state between the mem_avail_state_updated_cb callback and
// the WorkerThread.
AutounsignalEvent mem_state_signal_;
ktl::atomic<PressureLevel> mem_event_idx_ = PressureLevel::kNormal;
PressureLevel prev_mem_event_idx_ = mem_event_idx_;
// Used to delay signaling memory level transitions in the case of rapid changes.
zx_time_t hysteresis_seconds_ = ZX_SEC(10);
// Tracks last time the memory state was evaluated (and signaled if required).
zx_time_t prev_mem_state_eval_time_ = ZX_TIME_INFINITE_PAST;
// The highest pressure level we trigger eviction at, OOM being the lowest pressure level (0).
PressureLevel max_eviction_level_ = PressureLevel::kCritical;
// The free memory target to aim for when we trigger eviction.
uint64_t free_mem_target_ = 0;
// Current minimum amount of memory we want the triggered eviction to reclaim.
uint64_t min_free_target_ = 0;
// A timer is used to trigger eviction so that user space is given a chance to act upon a memory
// pressure signal first.
Timer eviction_trigger_;
Executor* executor_;
};
#endif // ZIRCON_KERNEL_OBJECT_INCLUDE_OBJECT_MEMORY_WATCHDOG_H_