blob: 2334981d3bc4df095433b2e556e8b3cc27c307ce [file] [log] [blame]
// Copyright 2016 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
// This file defines:
// * Initialization code for kernel/object module
// * Singleton instances and global locks
// * Helper functions
#include <inttypes.h>
#include <kernel/cmdline.h>
#include <lk/init.h>
#include <lib/oom.h>
#include <object/diagnostics.h>
#include <object/event_dispatcher.h>
#include <object/excp_port.h>
#include <object/job_dispatcher.h>
#include <object/port_dispatcher.h>
#include <platform/halt_helper.h>
#include <zircon/syscalls/object.h>
#include <zircon/types.h>
// All jobs and processes are rooted at the |root_job|.
static fbl::RefPtr<JobDispatcher> root_job;
fbl::RefPtr<JobDispatcher> GetRootJobDispatcher() {
return root_job;
}
// Kernel-owned event that is signaled before taking action in OOM situation.
static fbl::RefPtr<EventDispatcher> low_mem_event;
fbl::RefPtr<EventDispatcher> GetLowMemEvent() {
return low_mem_event;
}
static void oom_lowmem(size_t shortfall_bytes) {
zx_status_t status;
printf("OOM: oom_lowmem(shortfall_bytes=%zu) called\n", shortfall_bytes);
status = low_mem_event->user_signal_self(0, ZX_EVENT_SIGNALED);
if (status != ZX_OK) {
printf("OOM: signal low mem failed: %d\n", status);
}
#if defined(ENABLE_KERNEL_DEBUGGING_FEATURES)
// See ZX-3637 for the product details on when this path vs. the reboot
// should be used.
bool found = false;
JobDispatcher::ForEachJob([&found](JobDispatcher* job) {
if (job->get_kill_on_oom()) {
// The traversal order of ForEachJob() is going to favor killing newer
// jobs, this helps in case more than one is eligible.
if (job->Kill(ZX_TASK_RETCODE_OOM_KILL)) {
found = true;
char name[ZX_MAX_NAME_LEN];
job->get_name(name);
printf("OOM: killing job %6" PRIu64 " '%s'\n", job->get_koid(), name);
return ZX_ERR_STOP;
}
}
return ZX_OK;
});
if (!found) {
printf("OOM: no alive job has a kill bit\n");
}
#else
const int kSleepSeconds = 8;
printf("OOM: pausing for %ds after low mem signal\n", kSleepSeconds);
status = thread_sleep_relative(ZX_SEC(kSleepSeconds));
if (status != ZX_OK) {
printf("OOM: sleep failed: %d\n", status);
}
printf("OOM: rebooting\n");
platform_graceful_halt_helper(HALT_ACTION_REBOOT);
#endif
}
static void object_glue_init(uint level) TA_NO_THREAD_SAFETY_ANALYSIS {
Handle::Init();
root_job = JobDispatcher::CreateRootJob();
PortDispatcher::Init();
KernelHandle<EventDispatcher> event;
zx_rights_t rights;
zx_status_t status = EventDispatcher::Create(0, &event, &rights);
if (status != ZX_OK) {
panic("low mem event create: %d\n", status);
}
low_mem_event = event.release();
// Be sure to update kernel_cmdline.md if any of these defaults change.
oom_init(cmdline_get_bool("kernel.oom.enable", true),
ZX_SEC(cmdline_get_uint64("kernel.oom.sleep-sec", 1)),
cmdline_get_uint64("kernel.oom.redline-mb", 50) * MB,
oom_lowmem);
}
LK_INIT_HOOK(libobject, object_glue_init, LK_INIT_LEVEL_THREADING)