blob: dec36e3f75c14262b1f0e638d480b3bbdde7ca16 [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
#pragma once
#include <stdint.h>
#include <object/dispatcher.h>
#include <object/excp_port.h>
#include <object/policy_manager.h>
#include <object/process_dispatcher.h>
#include <object/state_tracker.h>
#include <zircon/types.h>
#include <fbl/array.h>
#include <fbl/auto_lock.h>
#include <fbl/canary.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/mutex.h>
#include <fbl/name.h>
#include <fbl/ref_counted.h>
class JobNode;
// Interface for walking a job/process tree.
class JobEnumerator {
public:
// Visits a job. If OnJob returns false, the enumeration stops.
virtual bool OnJob(JobDispatcher* job) { return true; }
// Visits a process. If OnProcess returns false, the enumeration stops.
virtual bool OnProcess(ProcessDispatcher* proc) { return true; }
protected:
virtual ~JobEnumerator() = default;
};
class JobDispatcher final : public Dispatcher {
public:
// Traits to belong to the parent's raw job list.
struct ListTraitsRaw {
static fbl::DoublyLinkedListNodeState<JobDispatcher*>& node_state(
JobDispatcher& obj) {
return obj.dll_job_raw_;
}
};
// Traits to belong to the parent's job list.
struct ListTraits {
static fbl::SinglyLinkedListNodeState<fbl::RefPtr<JobDispatcher>>& node_state(
JobDispatcher& obj) {
return obj.dll_job_;
}
};
static fbl::RefPtr<JobDispatcher> CreateRootJob();
static zx_status_t Create(uint32_t flags,
fbl::RefPtr<JobDispatcher> parent,
fbl::RefPtr<Dispatcher>* dispatcher,
zx_rights_t* rights);
~JobDispatcher() final;
// Dispatcher implementation.
zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_JOB; }
StateTracker* get_state_tracker() final { return &state_tracker_; }
void on_zero_handles() final;
zx_koid_t get_related_koid() const final;
fbl::RefPtr<JobDispatcher> parent() { return fbl::RefPtr<JobDispatcher>(parent_); }
// Job methods.
void get_name(char out_name[ZX_MAX_NAME_LEN]) const final;
zx_status_t set_name(const char* name, size_t len) final;
uint32_t max_height() const { return max_height_; }
// "Importance" is a userspace-settable hint that is used to rank jobs for
// OOM killing. See ZX_PROP_JOB_IMPORTANCE.
// Note: if the importance is set to ZX_JOB_IMPORTANCE_INHERITED (which is
// the default for all jobs except the root job), get_importance() will
// return the inherited value.
zx_status_t get_importance(zx_job_importance_t* out) const;
zx_status_t set_importance(zx_job_importance_t importance);
// TODO(dbort): Consider adding a get_capped_importance() so that userspace
// doesn't need to check all ancestor jobs to find the value (which is the
// minimum importance value of this job and its ancestors). Could also be
// used by the killer thread to avoid jobs whose capped importance is
// IMMORTAL.
bool AddChildProcess(ProcessDispatcher* process);
void RemoveChildProcess(ProcessDispatcher* process);
void Kill();
// Set policy. |mode| is is either ZX_JOB_POL_RELATIVE or ZX_JOB_POL_ABSOLUTE and
// in_policy is an array of |count| elements.
zx_status_t SetPolicy(uint32_t mode, const zx_policy_basic* in_policy, size_t policy_count);
pol_cookie_t GetPolicy();
// Updates a partial ordering between jobs so that this job will be killed
// after |other| in low-resource situations. If |other| is null, then this
// job becomes the least-important job in the system.
zx_status_t MakeMoreImportantThan(fbl::RefPtr<JobDispatcher> other);
// Calls the provided |zx_status_t func(JobDispatcher*)| on every
// JobDispatcher in the system, from least important to most important,
// using the order determined by MakeMoreImportantThan(). Stops if |func|
// returns an error, returning the error value.
template <typename T>
static zx_status_t ForEachJobByImportance(T func) {
fbl::AutoLock lock(&importance_lock_);
for (auto &job : importance_list_) {
zx_status_t s = func(&job);
if (s != ZX_OK)
return s;
}
return ZX_OK;
}
// Walks the job/process tree and invokes |je| methods on each node. If
// |recurse| is false, only visits direct children of this job. Returns
// false if any methods of |je| return false; returns true otherwise.
bool EnumerateChildren(JobEnumerator* je, bool recurse);
fbl::RefPtr<ProcessDispatcher> LookupProcessById(zx_koid_t koid);
fbl::RefPtr<JobDispatcher> LookupJobById(zx_koid_t koid);
// exception handling support
zx_status_t SetExceptionPort(fbl::RefPtr<ExceptionPort> eport);
// Returns true if a port had been set.
bool ResetExceptionPort(bool quietly);
fbl::RefPtr<ExceptionPort> exception_port();
private:
enum class State {
READY,
KILLING,
};
JobDispatcher(uint32_t flags, fbl::RefPtr<JobDispatcher> parent, pol_cookie_t policy);
// Like get_importance(), but does not resolve inheritance; i.e., this
// method may return ZX_JOB_IMPORTANCE_INHERITED.
zx_job_importance_t GetRawImportance() const;
bool AddChildJob(JobDispatcher* job);
void RemoveChildJob(JobDispatcher* job);
void UpdateSignalsIncrementLocked() TA_REQ(lock_);
void UpdateSignalsDecrementLocked() TA_REQ(lock_);
fbl::Canary<fbl::magic("JOBD")> canary_;
const fbl::RefPtr<JobDispatcher> parent_;
const uint32_t max_height_;
fbl::DoublyLinkedListNodeState<JobDispatcher*> dll_job_raw_;
fbl::SinglyLinkedListNodeState<fbl::RefPtr<JobDispatcher>> dll_job_;
// The user-friendly job name. For debug purposes only. That
// is, there is no mechanism to mint a handle to a job via this name.
fbl::Name<ZX_MAX_NAME_LEN> name_;
// The |lock_| protects all members below.
mutable fbl::Mutex lock_;
State state_ TA_GUARDED(lock_);
uint32_t process_count_ TA_GUARDED(lock_);
uint32_t job_count_ TA_GUARDED(lock_);
zx_job_importance_t importance_ TA_GUARDED(lock_);
StateTracker state_tracker_;
using RawJobList =
fbl::DoublyLinkedList<JobDispatcher*, ListTraitsRaw>;
using RawProcessList =
fbl::DoublyLinkedList<ProcessDispatcher*, ProcessDispatcher::JobListTraitsRaw>;
using ProcessList =
fbl::SinglyLinkedList<fbl::RefPtr<ProcessDispatcher>, ProcessDispatcher::JobListTraits>;
using JobList =
fbl::SinglyLinkedList<fbl::RefPtr<JobDispatcher>, ListTraits>;
RawJobList jobs_ TA_GUARDED(lock_);
RawProcessList procs_ TA_GUARDED(lock_);
pol_cookie_t policy_ TA_GUARDED(lock_);
fbl::RefPtr<ExceptionPort> exception_port_ TA_GUARDED(lock_);
// Global list of JobDispatchers, ordered by relative importance. Used to
// find victims in low-resource situations.
fbl::DoublyLinkedListNodeState<JobDispatcher*> dll_importance_;
struct ListTraitsImportance {
static fbl::DoublyLinkedListNodeState<JobDispatcher*>& node_state(
JobDispatcher& obj) {
return obj.dll_importance_;
}
};
using JobImportanceList =
fbl::DoublyLinkedList<JobDispatcher*, ListTraitsImportance>;
static fbl::Mutex importance_lock_;
// Jobs, ordered by importance, with the least-important job at the front.
static JobImportanceList importance_list_ TA_GUARDED(importance_lock_);
};
// Returns the job that is the ancestor of all other tasks.
fbl::RefPtr<JobDispatcher> GetRootJobDispatcher();