-
Notifications
You must be signed in to change notification settings - Fork 1.2k
win32unix: cannot kill and wait for arbitrary processes #11021
Description
Hi! I encountered this issue writing test cases for my PRs on
win32unix.
This issue is closely related to #4034. As a result of pids in
win32unix being so-called "pseudo-pids" (handles casted to integers),
they're local to each process. As @xavierleroy explained there,
if
Unix.waitpidis called for a process that has already
terminated, its processID is invalid (Windows doesn't keep the
process around if its handles are closed) and there is no way to
recover its handle and therefore its exit code.
Adrawback is that with the current API processes can only wait or
kill processes they've created themselves and not arbitrary processes,
since there's currently no way to get a handle to arbitrary
processes. Furthermore, if a "real" pid (regardless of whether the
corresponding process was created in the same "parent" process or
elsewhere) is given to Unix.waitpid or Unix.kill, the functions
will raise Unix.ESRCH.
For instance, the following program fails and cannot be correctly
written with the current API (it is to an extent pseudo-code):
Grand-parent tries to kill grand-child
let parent () =
let null = Unix.openfile Filename.null [Unix.O_RDWR; O_CLOEXEC] 0o0 in
let pin, pout = Unix.pipe ~cloexec:true () in
let child = Unix.create_process Sys.argv.(0) [|Sys.argv.(0); "child"|]
null pout Unix.stderr in
let buf = Bytes.create 8 in
assert (Unix.read pin buf 0 8 = 8);
let sub_child = Bytes.get_int64_ne buf 0 |> Int64.to_int in
begin try
Unix.kill child Sys.sigkill;
print_endline "PARENT: killed child process."
with Unix.Unix_error(Unix.ESRCH, _, _) ->
print_endline "PARENT: couldn't kill child process."
end;
begin try
Unix.kill sub_child Sys.sigkill;
print_endline "PARENT: killed sub_child process."
with Unix.Unix_error(Unix.ESRCH, _, _) ->
print_endline "PARENT: couldn't kill sub_child process."
end
let child () =
let _ = Unix.create_process Sys.argv.(0) [|Sys.argv.(0); "subchild"|]
Unix.stdin Unix.stdout Unix.stderr in
Unix.sleep 2
let sub_child () =
let pid = Unix.getpid () in
let buf = Bytes.create 8 in
Bytes.set_int64_ne buf 0 (Int64.of_int pid);
assert (Unix.write Unix.stdout buf 0 8 = 8);
while true do Unix.sleep 2 done
let () =
match Sys.argv with
| [|_|] -> parent ()
| [|_; "child"|] -> child ()
| [|_; "subchild"|] -> sub_child ()
| _ -> invalid_arg "Sys.argv"
I think that makes a compelling case for the idea @alainfrisch
described:
A related remark only : I think it would seem coherent with the
treatment of file descriptors in the Unix library to represent
process descriptors with a dedicated abstract type which would be
implemented as the integer representing the pid on Unix, and as the
handle on Windows.
which entails adding a new type, new functions to win32unix and a
wrapper for OpenProcess.
Note also that Linux 5.13 has introduced pidfd which share
similarities to Windows process handles.
I hope I got this right! Thanks.