summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authoruki00a <uki00a@gmail.com>2020-07-08 23:35:45 +0900
committerGitHub <noreply@github.com>2020-07-08 10:35:45 -0400
commita2bf61d1ae3ba2ff746a98ad2f0a96b6fc7782d0 (patch)
treed7d074acd7de7ecdc3094c5f6b0c5ded696f3e39 /cli
parent231899695d410d8d8c14c0936682a90e98bc6fd3 (diff)
feat(unstable): Deno.ppid (#6539)
Diffstat (limited to 'cli')
-rw-r--r--cli/Cargo.toml2
-rw-r--r--cli/js/lib.deno.unstable.d.ts5
-rw-r--r--cli/js/ops/runtime.ts1
-rw-r--r--cli/js/runtime_main.ts3
-rw-r--r--cli/ops/runtime.rs60
-rw-r--r--cli/tests/unit/os_test.ts22
6 files changed, 91 insertions, 2 deletions
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 11665023d..64688d5d0 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -64,7 +64,7 @@ swc_ecma_visit = "0.7.0"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.8", features = ["knownfolders", "objbase", "shlobj",
-"winbase", "winerror"] }
+"winbase", "winerror", "tlhelp32"] }
fwdansi = "1.1.0"
[target.'cfg(unix)'.dependencies]
diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts
index 20096cb28..cec4f7f46 100644
--- a/cli/js/lib.deno.unstable.d.ts
+++ b/cli/js/lib.deno.unstable.d.ts
@@ -1194,4 +1194,9 @@ declare namespace Deno {
* ```
*/
export function fstat(rid: number): Promise<FileInfo>;
+
+ /** **UNSTABLE**: New API, yet to be vetted.
+ * The pid of the current process's parent.
+ */
+ export const ppid: number;
}
diff --git a/cli/js/ops/runtime.ts b/cli/js/ops/runtime.ts
index 70addf469..09208df6d 100644
--- a/cli/js/ops/runtime.ts
+++ b/cli/js/ops/runtime.ts
@@ -9,6 +9,7 @@ export interface Start {
denoVersion: string;
noColor: boolean;
pid: number;
+ ppid: number;
repl: boolean;
target: string;
tsVersion: string;
diff --git a/cli/js/runtime_main.ts b/cli/js/runtime_main.ts
index 25a6b0f93..0c579626b 100644
--- a/cli/js/runtime_main.ts
+++ b/cli/js/runtime_main.ts
@@ -96,10 +96,11 @@ export function bootstrapMainRuntime(): void {
}
});
- const { args, cwd, noColor, pid, repl, unstableFlag } = runtime.start();
+ const { args, cwd, noColor, pid, ppid, repl, unstableFlag } = runtime.start();
Object.defineProperties(denoNs, {
pid: readOnly(pid),
+ ppid: readOnly(ppid),
noColor: readOnly(noColor),
args: readOnly(Object.freeze(args)),
});
diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs
index e47b40792..1e426ad8a 100644
--- a/cli/ops/runtime.rs
+++ b/cli/ops/runtime.rs
@@ -32,6 +32,7 @@ fn op_start(
"denoVersion": version::DENO,
"noColor": !colors::use_color(),
"pid": std::process::id(),
+ "ppid": ppid(),
"repl": gs.flags.subcommand == DenoSubcommand::Repl,
"target": env!("TARGET"),
"tsVersion": version::TYPESCRIPT,
@@ -78,3 +79,62 @@ fn op_metrics(
"bytesReceived": m.bytes_received
})))
}
+
+fn ppid() -> Value {
+ #[cfg(windows)]
+ {
+ // Adopted from rustup:
+ // https://github.com/rust-lang/rustup/blob/1.21.1/src/cli/self_update.rs#L1036
+ // Copyright Diggory Blake, the Mozilla Corporation, and rustup contributors.
+ // Licensed under either of
+ // - Apache License, Version 2.0
+ // - MIT license
+ use std::mem;
+ use winapi::shared::minwindef::DWORD;
+ use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
+ use winapi::um::processthreadsapi::GetCurrentProcessId;
+ use winapi::um::tlhelp32::{
+ CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32,
+ TH32CS_SNAPPROCESS,
+ };
+ unsafe {
+ // Take a snapshot of system processes, one of which is ours
+ // and contains our parent's pid
+ let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if snapshot == INVALID_HANDLE_VALUE {
+ return serde_json::to_value(-1).unwrap();
+ }
+
+ let mut entry: PROCESSENTRY32 = mem::zeroed();
+ entry.dwSize = mem::size_of::<PROCESSENTRY32>() as DWORD;
+
+ // Iterate over system processes looking for ours
+ let success = Process32First(snapshot, &mut entry);
+ if success == 0 {
+ CloseHandle(snapshot);
+ return serde_json::to_value(-1).unwrap();
+ }
+
+ let this_pid = GetCurrentProcessId();
+ while entry.th32ProcessID != this_pid {
+ let success = Process32Next(snapshot, &mut entry);
+ if success == 0 {
+ CloseHandle(snapshot);
+ return serde_json::to_value(-1).unwrap();
+ }
+ }
+ CloseHandle(snapshot);
+
+ // FIXME: Using the process ID exposes a race condition
+ // wherein the parent process already exited and the OS
+ // reassigned its ID.
+ let parent_id = entry.th32ParentProcessID;
+ serde_json::to_value(parent_id).unwrap()
+ }
+ }
+ #[cfg(not(windows))]
+ {
+ use std::os::unix::process::parent_id;
+ serde_json::to_value(parent_id()).unwrap()
+ }
+}
diff --git a/cli/tests/unit/os_test.ts b/cli/tests/unit/os_test.ts
index b737d939a..e969464e5 100644
--- a/cli/tests/unit/os_test.ts
+++ b/cli/tests/unit/os_test.ts
@@ -111,6 +111,28 @@ unitTest(function osPid(): void {
assert(Deno.pid > 0);
});
+unitTest(function osPpid(): void {
+ assert(Deno.ppid > 0);
+});
+
+unitTest(
+ { perms: { run: true, read: true } },
+ async function osPpidIsEqualToPidOfParentProcess(): Promise<void> {
+ const decoder = new TextDecoder();
+ const process = Deno.run({
+ cmd: [Deno.execPath(), "eval", "-p", "--unstable", "Deno.ppid"],
+ stdout: "piped",
+ env: { NO_COLOR: "true" },
+ });
+ const output = await process.output();
+ process.close();
+
+ const expected = Deno.pid;
+ const actual = parseInt(decoder.decode(output));
+ assertEquals(actual, expected);
+ }
+);
+
unitTest({ perms: { read: true } }, function execPath(): void {
assertNotEquals(Deno.execPath(), "");
});