summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Ogórek <kamil.ogorek@gmail.com>2022-12-27 00:16:12 +0100
committerGitHub <noreply@github.com>2022-12-27 00:16:12 +0100
commit7ce2b58bcf412924464578f3469c210b34894c8b (patch)
tree571ef978ec8ff59bc2f3c229ea44b0786251e6b9
parenta67fd3e23e6965ce0bf25e19e5467bc5cc538d23 (diff)
feat(unstable): Add "Deno.osUptime()" API (#17179)
This PR adds support for `Deno.osUptime` which reports number of seconds since os was booted. It will allow us to be compatible with Node's `os.uptime` - https://nodejs.org/api/os.html#osuptime Partially based on https://docs.rs/uptime_lib/latest/src/uptime_lib/lib.rs.html
-rw-r--r--cli/tests/unit/os_test.ts12
-rw-r--r--cli/tests/unit/permissions_test.ts1
-rw-r--r--cli/tsc/diagnostics.rs1
-rw-r--r--cli/tsc/dts/lib.deno.ns.d.ts1
-rw-r--r--cli/tsc/dts/lib.deno.unstable.d.ts15
-rw-r--r--runtime/js/30_os.js5
-rw-r--r--runtime/js/90_deno_ns.js1
-rw-r--r--runtime/ops/os/mod.rs11
-rw-r--r--runtime/ops/os/sys_info.rs62
-rw-r--r--runtime/permissions/mod.rs2
10 files changed, 110 insertions, 1 deletions
diff --git a/cli/tests/unit/os_test.ts b/cli/tests/unit/os_test.ts
index 5e88f02c1..ae2bee72e 100644
--- a/cli/tests/unit/os_test.ts
+++ b/cli/tests/unit/os_test.ts
@@ -239,6 +239,18 @@ Deno.test({ permissions: { sys: false } }, function releasePerm() {
}, Deno.errors.PermissionDenied);
});
+Deno.test({ permissions: { sys: ["osUptime"] } }, function osUptime() {
+ const uptime = Deno.osUptime();
+ assert(typeof uptime === "number");
+ assert(uptime > 0);
+});
+
+Deno.test({ permissions: { sys: false } }, function osUptimePerm() {
+ assertThrows(() => {
+ Deno.osUptime();
+ }, Deno.errors.PermissionDenied);
+});
+
Deno.test(
{ permissions: { sys: ["systemMemoryInfo"] } },
function systemMemoryInfo() {
diff --git a/cli/tests/unit/permissions_test.ts b/cli/tests/unit/permissions_test.ts
index 3387913e8..3af2e35ea 100644
--- a/cli/tests/unit/permissions_test.ts
+++ b/cli/tests/unit/permissions_test.ts
@@ -22,6 +22,7 @@ Deno.test(async function permissionNetInvalidHost() {
Deno.test(async function permissionSysValidKind() {
await Deno.permissions.query({ name: "sys", kind: "loadavg" });
await Deno.permissions.query({ name: "sys", kind: "osRelease" });
+ await Deno.permissions.query({ name: "sys", kind: "osUptime" });
await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" });
await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" });
await Deno.permissions.query({ name: "sys", kind: "hostname" });
diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs
index 4413398c2..8323fd7ac 100644
--- a/cli/tsc/diagnostics.rs
+++ b/cli/tsc/diagnostics.rs
@@ -46,6 +46,7 @@ const UNSTABLE_DENO_PROPS: &[&str] = &[
"ServeInit",
"ServeTlsInit",
"Handler",
+ "osUptime",
];
static MSG_MISSING_PROPERTY_DENO: Lazy<Regex> = Lazy::new(|| {
diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts
index fa68dc1bd..4dafd7388 100644
--- a/cli/tsc/dts/lib.deno.ns.d.ts
+++ b/cli/tsc/dts/lib.deno.ns.d.ts
@@ -4120,6 +4120,7 @@ declare namespace Deno {
| "systemMemoryInfo"
| "networkInterfaces"
| "osRelease"
+ | "osUptime"
| "uid"
| "gid";
}
diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts
index f1b8d99e9..77d350503 100644
--- a/cli/tsc/dts/lib.deno.unstable.d.ts
+++ b/cli/tsc/dts/lib.deno.unstable.d.ts
@@ -1691,6 +1691,21 @@ declare namespace Deno {
/** The buffered output from the child process' `stderr`. */
readonly stderr: Uint8Array;
}
+
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
+ * Returns the Operating System uptime in number of seconds.
+ *
+ * ```ts
+ * console.log(Deno.osUptime());
+ * ```
+ *
+ * Requires `allow-sys` permission.
+ *
+ * @tags allow-sys
+ * @category Runtime Environment
+ */
+ export function osUptime(): number;
}
/** **UNSTABLE**: New API, yet to be vetted.
diff --git a/runtime/js/30_os.js b/runtime/js/30_os.js
index 723b52132..3c9768593 100644
--- a/runtime/js/30_os.js
+++ b/runtime/js/30_os.js
@@ -25,6 +25,10 @@
return ops.op_os_release();
}
+ function osUptime() {
+ return ops.op_os_uptime();
+ }
+
function systemMemoryInfo() {
return ops.op_system_memory_info();
}
@@ -106,6 +110,7 @@
loadavg,
networkInterfaces,
osRelease,
+ osUptime,
setExitHandler,
systemMemoryInfo,
uid,
diff --git a/runtime/js/90_deno_ns.js b/runtime/js/90_deno_ns.js
index 94a611456..f49fb5af1 100644
--- a/runtime/js/90_deno_ns.js
+++ b/runtime/js/90_deno_ns.js
@@ -119,6 +119,7 @@
refTimer: __bootstrap.timers.refTimer,
unrefTimer: __bootstrap.timers.unrefTimer,
osRelease: __bootstrap.os.osRelease,
+ osUptime: __bootstrap.os.osUptime,
hostname: __bootstrap.os.hostname,
systemMemoryInfo: __bootstrap.os.systemMemoryInfo,
networkInterfaces: __bootstrap.os.networkInterfaces,
diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs
index 613b4507d..e82afbf7c 100644
--- a/runtime/ops/os/mod.rs
+++ b/runtime/ops/os/mod.rs
@@ -29,6 +29,7 @@ fn init_ops(builder: &mut ExtensionBuilder) -> &mut ExtensionBuilder {
op_loadavg::decl(),
op_network_interfaces::decl(),
op_os_release::decl(),
+ op_os_uptime::decl(),
op_set_env::decl(),
op_set_exit_code::decl(),
op_system_memory_info::decl(),
@@ -423,3 +424,13 @@ fn rss() -> usize {
}
}
}
+
+#[op]
+fn op_os_uptime(state: &mut OpState) -> Result<u64, AnyError> {
+ super::check_unstable(state, "Deno.osUptime");
+ state
+ .borrow_mut::<Permissions>()
+ .sys
+ .check("osUptime", Some("Deno.osUptime()"))?;
+ Ok(sys_info::os_uptime())
+}
diff --git a/runtime/ops/os/sys_info.rs b/runtime/ops/os/sys_info.rs
index 40de7cc4b..ecb40b9a0 100644
--- a/runtime/ops/os/sys_info.rs
+++ b/runtime/ops/os/sys_info.rs
@@ -300,3 +300,65 @@ pub fn mem_info() -> Option<MemInfo> {
Some(mem_info)
}
+
+pub fn os_uptime() -> u64 {
+ #[cfg(target_os = "linux")]
+ {
+ let mut info = std::mem::MaybeUninit::uninit();
+ // SAFETY: `info` is a valid pointer to a `libc::sysinfo` struct.
+ let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
+ if res == 0 {
+ // SAFETY: `sysinfo` initializes the struct.
+ let info = unsafe { info.assume_init() };
+ return info.uptime as u64;
+ }
+ }
+
+ #[cfg(any(
+ target_vendor = "apple",
+ target_os = "freebsd",
+ target_os = "openbsd"
+ ))]
+ {
+ use std::mem;
+ use std::time::Duration;
+ use std::time::SystemTime;
+ let mut request = [libc::CTL_KERN, libc::KERN_BOOTTIME];
+ // SAFETY: `boottime` is only accessed if sysctl() succeeds
+ // and agrees with the `size` set by sysctl().
+ let mut boottime: libc::timeval = unsafe { mem::zeroed() };
+ let mut size: libc::size_t = mem::size_of_val(&boottime) as libc::size_t;
+ // SAFETY: `sysctl` is thread-safe.
+ let res = unsafe {
+ libc::sysctl(
+ &mut request[0],
+ 2,
+ &mut boottime as *mut libc::timeval as *mut libc::c_void,
+ &mut size,
+ std::ptr::null_mut(),
+ 0,
+ )
+ };
+ if res == 0 {
+ return SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .map(|d| {
+ (d - Duration::new(
+ boottime.tv_sec as u64,
+ boottime.tv_usec as u32 * 1000,
+ ))
+ .as_secs()
+ })
+ .unwrap_or_default();
+ }
+ }
+
+ #[cfg(target_family = "windows")]
+ unsafe {
+ // Windows is the only one that returns `uptime` in milisecond precision,
+ // so we need to get the seconds out of it to be in sync with other envs.
+ return unsafe { winapi::um::sysinfoapi::GetTickCount64() as u64 / 1000 };
+ }
+
+ 0
+}
diff --git a/runtime/permissions/mod.rs b/runtime/permissions/mod.rs
index 5b2af0e0f..ce4984ee1 100644
--- a/runtime/permissions/mod.rs
+++ b/runtime/permissions/mod.rs
@@ -309,7 +309,7 @@ pub struct SysDescriptor(pub String);
pub fn parse_sys_kind(kind: &str) -> Result<&str, AnyError> {
match kind {
- "hostname" | "osRelease" | "loadavg" | "networkInterfaces"
+ "hostname" | "osRelease" | "osUptime" | "loadavg" | "networkInterfaces"
| "systemMemoryInfo" | "uid" | "gid" => Ok(kind),
_ => Err(type_error(format!("unknown system info kind \"{}\"", kind))),
}