@@ -153,6 +153,15 @@ module Process = struct
153153 ; session : Lev_fiber_csexp.Session .t
154154 }
155155
156+ let waitpid t =
157+ let + status = Lev_fiber. waitpid ~pid: (Pid. to_int t.pid) in
158+ (match status with
159+ | Unix. WEXITED n when n <> 0 ->
160+ Format. eprintf " dune finished with code = %d@.%!" n
161+ | _ -> () );
162+ Lev_fiber.Io. close t.stdin;
163+ Lev_fiber.Io. close t.stdout
164+
156165 let start ~dir =
157166 match Bin. which " dune" with
158167 | None ->
@@ -190,50 +199,64 @@ module Process = struct
190199 { pid; initial_cwd; stdin; stdout; session }
191200end
192201
202+ module Dot_protocol_io =
203+ Merlin_dot_protocol. Make
204+ (Fiber )
205+ (struct
206+ include Lev_fiber_csexp. Session
207+
208+ let write t x = write t (Some [ x ])
209+ end )
210+
193211type db =
194- { running : (string , Process .t ) Table .t
212+ { running : (string , entry ) Table .t
195213 ; pool : Fiber.Pool .t
196214 }
197215
216+ and entry =
217+ { db : db
218+ ; process : Process .t
219+ ; mutable ref_count : int
220+ }
221+
222+ module Entry = struct
223+ type t = entry
224+
225+ let create db process = { db; process; ref_count = 0 }
226+
227+ let equal = ( == )
228+
229+ let incr t = t.ref_count < - t.ref_count + 1
230+
231+ let destroy (t : t ) =
232+ assert (t.ref_count > 0 );
233+ t.ref_count < - t.ref_count - 1 ;
234+ if t.ref_count > 0 then Fiber. return ()
235+ else (
236+ Table. remove t.db.running t.process.initial_cwd;
237+ Dot_protocol_io.Commands. halt t.process.session)
238+ end
239+
198240let get_process t ~dir =
199241 match Table. find t.running dir with
200242 | Some p -> Fiber. return p
201243 | None ->
202- let * p = Process. start ~dir in
203- Table. add_exn t.running dir p;
204- let + () =
205- Fiber.Pool. task t.pool ~f: (fun () ->
206- let + status = Lev_fiber. waitpid ~pid: (Pid. to_int p.pid) in
207- (match status with
208- | Unix. WEXITED n when n <> 0 ->
209- Format. eprintf " dune finished with code = %d@.%!" n
210- | _ -> () );
211- Lev_fiber.Io. close p.stdin;
212- Lev_fiber.Io. close p.stdout;
213- Table. remove t.running dir)
214- in
215- p
244+ let * process = Process. start ~dir in
245+ let entry = Entry. create t process in
246+ Table. add_exn t.running dir entry;
247+ let + () = Fiber.Pool. task t.pool ~f: (fun () -> Process. waitpid process) in
248+ entry
216249
217250type context =
218251 { workdir : string
219252 ; process_dir : string
220253 }
221254
222- module Dot_protocol_io =
223- Merlin_dot_protocol. Make
224- (Fiber )
225- (struct
226- include Lev_fiber_csexp. Session
227-
228- let write t x = write t (Some [ x ])
229- end )
230-
231- let get_config db { workdir; process_dir } path_abs =
255+ let get_config (p : Process.t ) ~workdir path_abs =
232256 let query path (p : Process.t ) =
233257 let * () = Dot_protocol_io.Commands. send_file p.session path in
234258 Dot_protocol_io. read p.session
235259 in
236- let * p = get_process db ~dir: process_dir in
237260 (* Both [p.initial_cwd] and [path_abs] have gone through
238261 [canonicalize_filename] *)
239262 let path_rel =
@@ -315,10 +338,16 @@ type nonrec t =
315338 { path : string
316339 ; directory : string
317340 ; initial : Mconfig .t
341+ ; mutable entry : Entry .t option
318342 ; db : db
319343 }
320344
321- let destroy _ = Fiber. return ()
345+ let destroy t =
346+ match t.entry with
347+ | None -> Fiber. return ()
348+ | Some entry ->
349+ t.entry < - None ;
350+ Entry. destroy entry
322351
323352let create db path =
324353 let path =
@@ -334,14 +363,32 @@ let create db path =
334363 ; query = { init.query with filename; directory }
335364 }
336365 in
337- { path; directory; initial; db }
366+ { path; directory; initial; db; entry = None }
338367
339368let config (t : t ) : Mconfig.t Fiber.t =
369+ let use_entry entry =
370+ Entry. incr entry;
371+ t.entry < - Some entry
372+ in
340373 let * () = Fiber. return () in
341374 match find_project_context t.directory with
342- | None -> Fiber. return t.initial
343- | Some (ctxt , config_path ) ->
344- let + dot, failures = get_config t.db ctxt t.path in
375+ | None ->
376+ let + () = destroy t in
377+ t.initial
378+ | Some (ctx , config_path ) ->
379+ let * entry = get_process t.db ~dir: ctx.process_dir in
380+ let * () =
381+ match t.entry with
382+ | None ->
383+ use_entry entry;
384+ Fiber. return ()
385+ | Some entry' ->
386+ if Entry. equal entry entry' then Fiber. return ()
387+ else
388+ let + () = destroy t in
389+ use_entry entry
390+ in
391+ let + dot, failures = get_config entry.process ~workdir: ctx.workdir t.path in
345392 let merlin = Config. merge dot t.initial.merlin failures config_path in
346393 Mconfig. normalize { t.initial with merlin }
347394
0 commit comments