Skip to content

Commit 4df0160

Browse files
committed
Oh Windows, you're so special and different.
1 parent 7791ae7 commit 4df0160

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

lib/olly_common/launch.ml

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ type exec_config = Attach of string * int | Execute of string list
1414
(* Raised by exec_process to indicate various unrecoverable failures. *)
1515
exception Fail of string
1616

17+
(* List .events files in a directory, returning the set of filenames. *)
18+
let list_events_files dir =
19+
try
20+
Sys.readdir dir
21+
|> Array.to_list
22+
|> List.filter (fun f -> Filename.check_suffix f ".events")
23+
with Sys_error _ -> []
24+
25+
(* Extract the PID from a ring buffer filename like "12345.events". *)
26+
let pid_of_events_file filename =
27+
try Some (int_of_string (Filename.chop_suffix filename ".events"))
28+
with _ -> None
29+
1730
let exec_process (config : runtime_events_config) (argsl : string list) :
1831
subprocess =
1932
if not (List.length argsl > 0) then
@@ -48,7 +61,12 @@ let exec_process (config : runtime_events_config) (argsl : string list) :
4861
|]
4962
(Unix.environment ())
5063
in
51-
let child_pid =
64+
(* Record existing .events files so we can detect the child's new one.
65+
On Windows, Unix.create_process_env returns a process handle, not a PID,
66+
but the .events file is named with the real PID. We find the child's
67+
real PID by detecting which new .events file appeared. *)
68+
let existing_events = list_events_files dir in
69+
let child_handle =
5270
try
5371
Unix.create_process_env executable_filename (Array.of_list argsl) env
5472
Unix.stdin Unix.stdout Unix.stderr
@@ -63,14 +81,29 @@ let exec_process (config : runtime_events_config) (argsl : string list) :
6381
let timeout = 5.0 in
6482
let poll_interval = 0.05 in
6583
let deadline = Unix.gettimeofday () +. timeout in
84+
let child_pid = ref child_handle in
6685
let cursor =
6786
let last_exn = ref None in
6887
let result = ref None in
6988
while !result = None && Unix.gettimeofday () < deadline do
70-
try result := Some (Runtime_events.create_cursor (Some (dir, child_pid)))
71-
with Failure _ as exn ->
72-
last_exn := Some exn;
73-
Unix.sleepf poll_interval
89+
(* Find the child's real PID by detecting the new .events file.
90+
On Unix, child_handle IS the PID so this is a no-op. On Windows,
91+
we need to discover the real PID from the filesystem. *)
92+
if !child_pid = child_handle then begin
93+
let current = list_events_files dir in
94+
let new_files = List.filter (fun f -> not (List.mem f existing_events)) current in
95+
match new_files with
96+
| [f] -> (match pid_of_events_file f with
97+
| Some pid -> child_pid := pid
98+
| None -> ())
99+
| _ -> ()
100+
end;
101+
(try
102+
result :=
103+
Some (Runtime_events.create_cursor (Some (dir, !child_pid)))
104+
with Failure _ as exn ->
105+
last_exn := Some exn;
106+
Unix.sleepf poll_interval)
74107
done;
75108
match !result with
76109
| Some c -> c
@@ -82,19 +115,22 @@ let exec_process (config : runtime_events_config) (argsl : string list) :
82115
in
83116
failwith msg
84117
in
118+
let real_pid = !child_pid in
85119
let alive () =
86-
match Unix.waitpid [ Unix.WNOHANG ] child_pid with
120+
match Unix.waitpid [ Unix.WNOHANG ] child_handle with
87121
| 0, _ -> true
88-
| p, _ when p = child_pid -> false
122+
| p, _ when p = child_handle -> false
89123
| _, _ -> assert false
90124
and close () =
91125
Runtime_events.free_cursor cursor;
92126
(* We need to remove the ring buffers ourselves because we told
93127
the child process not to remove them *)
94-
let ring_file = Filename.concat dir (string_of_int child_pid ^ ".events") in
95-
Unix.unlink ring_file
128+
let ring_file =
129+
Filename.concat dir (string_of_int real_pid ^ ".events")
130+
in
131+
(try Unix.unlink ring_file with Unix.Unix_error _ -> ())
96132
in
97-
{ alive; cursor; close; pid = child_pid }
133+
{ alive; cursor; close; pid = child_handle }
98134

99135
let attach_process (dir : string) (pid : int) : subprocess =
100136
let cursor =

0 commit comments

Comments
 (0)