blob: 71f04d41ad5df29243cb0923be2c50e500443b6b [file] [log] [blame]
// Copyright 2017 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.
//! Type-safe bindings for Zircon jobs.
use crate::ok;
use crate::{object_get_info, ObjectQuery, Topic};
use crate::{AsHandleRef, Handle, HandleBased, HandleRef, Process, Status, Task, Vmar};
use fuchsia_zircon_sys as sys;
/// An object representing a Zircon job.
///
/// As essentially a subtype of `Handle`, it can be freely interconverted.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Job(Handle);
impl_handle_based!(Job);
sys::zx_info_job_t!(JobInfo);
impl From<sys::zx_info_job_t> for JobInfo {
fn from(info: sys::zx_info_job_t) -> JobInfo {
let sys::zx_info_job_t { return_code, exited, kill_on_oom, debugger_attached } = info;
JobInfo { return_code, exited, kill_on_oom, debugger_attached }
}
}
// JobInfo is able to be safely replaced with a byte representation and is a PoD type.
unsafe impl ObjectQuery for JobInfo {
const TOPIC: Topic = Topic::JOB;
type InfoTy = JobInfo;
}
impl Job {
/// Create a new job as a child of the current job.
///
/// Wraps the
/// [zx_job_create](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/job_create.md)
/// syscall.
pub fn create_child_job(&self) -> Result<Job, Status> {
let parent_job_raw = self.raw_handle();
let mut out = 0;
let options = 0;
let status = unsafe { sys::zx_job_create(parent_job_raw, options, &mut out) };
ok(status)?;
unsafe { Ok(Job::from(Handle::from_raw(out))) }
}
/// Create a new process as a child of the current job.
///
/// On success, returns a handle to the new process and a handle to the
/// root of the new process's address space.
///
/// Wraps the
/// [zx_process_create](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/process_create.md)
/// syscall.
pub fn create_child_process(&self, name: &[u8]) -> Result<(Process, Vmar), Status> {
let parent_job_raw = self.raw_handle();
let name_ptr = name.as_ptr();
let name_len = name.len();
let options = 0;
let mut process_out = 0;
let mut vmar_out = 0;
let status = unsafe {
sys::zx_process_create(
parent_job_raw,
name_ptr,
name_len,
options,
&mut process_out,
&mut vmar_out,
)
};
ok(status)?;
unsafe {
Ok((
Process::from(Handle::from_raw(process_out)),
Vmar::from(Handle::from_raw(vmar_out)),
))
}
}
/// Wraps the
/// [zx_object_get_info](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/object_get_info.md)
/// syscall for the ZX_INFO_JOB topic.
pub fn info(&self) -> Result<JobInfo, Status> {
let mut info = JobInfo::default();
object_get_info::<JobInfo>(self.as_handle_ref(), std::slice::from_mut(&mut info))
.map(|_| info)
}
}
impl Task for Job {}
#[cfg(test)]
mod tests {
// The unit tests are built with a different crate name, but fuchsia_runtime returns a "real"
// fuchsia_zircon::Job that we need to use.
use fuchsia_zircon::{sys, AsHandleRef, JobInfo, Signals, Task, Time};
#[test]
fn info_default() {
let job = fuchsia_runtime::job_default();
let info = job.info().unwrap();
assert_eq!(
info,
JobInfo { return_code: 0, exited: false, kill_on_oom: false, debugger_attached: false }
);
}
#[test]
fn kill_and_info() {
let default_job = fuchsia_runtime::job_default();
let job = default_job.create_child_job().expect("Failed to create child job");
let info = job.info().unwrap();
assert_eq!(
info,
JobInfo { return_code: 0, exited: false, kill_on_oom: false, debugger_attached: false }
);
job.kill().expect("Failed to kill job");
job.wait_handle(Signals::TASK_TERMINATED, Time::INFINITE).unwrap();
let info = job.info().unwrap();
assert_eq!(
info,
JobInfo {
return_code: sys::ZX_TASK_RETCODE_SYSCALL_KILL,
exited: true,
kill_on_oom: false,
debugger_attached: false
}
);
}
}