@@ -153,6 +153,15 @@ module Process = struct
153
153
; session : Lev_fiber_csexp.Session .t
154
154
}
155
155
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
+
156
165
let start ~dir =
157
166
match Bin. which " dune" with
158
167
| None ->
@@ -190,50 +199,64 @@ module Process = struct
190
199
{ pid; initial_cwd; stdin; stdout; session }
191
200
end
192
201
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
+
193
211
type db =
194
- { running : (string , Process .t ) Table .t
212
+ { running : (string , entry ) Table .t
195
213
; pool : Fiber.Pool .t
196
214
}
197
215
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
+
198
240
let get_process t ~dir =
199
241
match Table. find t.running dir with
200
242
| Some p -> Fiber. return p
201
243
| 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
216
249
217
250
type context =
218
251
{ workdir : string
219
252
; process_dir : string
220
253
}
221
254
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 =
232
256
let query path (p : Process.t ) =
233
257
let * () = Dot_protocol_io.Commands. send_file p.session path in
234
258
Dot_protocol_io. read p.session
235
259
in
236
- let * p = get_process db ~dir: process_dir in
237
260
(* Both [p.initial_cwd] and [path_abs] have gone through
238
261
[canonicalize_filename] *)
239
262
let path_rel =
@@ -315,10 +338,16 @@ type nonrec t =
315
338
{ path : string
316
339
; directory : string
317
340
; initial : Mconfig .t
341
+ ; mutable entry : Entry .t option
318
342
; db : db
319
343
}
320
344
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
322
351
323
352
let create db path =
324
353
let path =
@@ -334,14 +363,32 @@ let create db path =
334
363
; query = { init.query with filename; directory }
335
364
}
336
365
in
337
- { path; directory; initial; db }
366
+ { path; directory; initial; db; entry = None }
338
367
339
368
let config (t : t ) : Mconfig.t Fiber.t =
369
+ let use_entry entry =
370
+ Entry. incr entry;
371
+ t.entry < - Some entry
372
+ in
340
373
let * () = Fiber. return () in
341
374
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
345
392
let merlin = Config. merge dot t.initial.merlin failures config_path in
346
393
Mconfig. normalize { t.initial with merlin }
347
394
0 commit comments