terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

debounce view refresh and serialize child reaping

+50 -15
+14 -3
jj_tui/bin/global_funcs.ml
··· 38 38 ;; 39 39 40 40 let current_computation = ref (Promise.of_value ()) 41 + let update_debounce_computation = ref (Promise.of_value ()) 42 + let pending_snapshot = ref false 41 43 42 44 (**Updates the status windows; Without snapshotting the working copy by default 43 45 This should be called after any command that performs a change *) ··· 62 64 ;; 63 65 64 66 let update_views_async ?(cause_snapshot = false) () = 65 - Promise.terminate_after ~seconds:0. !current_computation; 66 - let comp = Flock.fork_as_promise (fun () -> update_views ~cause_snapshot ()) in 67 - current_computation := comp 67 + (* Coalesce rapid refresh requests while scrolling/navigation is active. *) 68 + pending_snapshot := !pending_snapshot || cause_snapshot; 69 + Promise.terminate_after ~seconds:0. !update_debounce_computation; 70 + update_debounce_computation 71 + := Flock.fork_as_promise (fun () -> 72 + Control.sleep ~seconds:0.05; 73 + let should_snapshot = !pending_snapshot in 74 + pending_snapshot := false; 75 + Promise.terminate_after ~seconds:0. !current_computation; 76 + current_computation 77 + := Flock.fork_as_promise (fun () -> 78 + update_views ~cause_snapshot:should_snapshot ())) 68 79 ;; 69 80 70 81 (**Updates the status windows; Without snapshotting the working copy by default
+36 -12
jj_tui/bin/jj_process.ml
··· 134 134 let open Picos_io in 135 135 let closed_one_end = ref false in 136 136 let dispose fd = if not !closed_one_end then Unix.close fd in 137 + let reap_lock = Mutex.create () in 138 + let reaped = ref false in 139 + let reap_once ?(flags = []) pid = 140 + (* Ensure there is exactly one waitpid owner for this child process. *) 141 + Mutex.lock reap_lock; 142 + Fun.protect 143 + ~finally:(fun () -> Mutex.unlock reap_lock) 144 + (fun () -> 145 + if !reaped 146 + then None 147 + else ( 148 + reaped := true; 149 + try Some (Unix.waitpid flags pid) with 150 + | Unix.Unix_error (Unix.ECHILD, "waitpid", _) -> 151 + None)) 152 + in 137 153 let@ stdout_o, stdout_i = 138 154 finally 139 155 (fun (o, i) -> ··· 164 180 (* if the process didn't finish we will kill the process and then wait it's pid to release the pid*) 165 181 if not !isDone 166 182 then ( 167 - try 168 - [%log 169 - debug 170 - "pid: %i Cleaning up cancelled command %s" 171 - pid 172 - (args |> String.concat " ")]; 173 - Unix.kill pid Sys.sigkill; 174 - Unix.waitpid [ Unix.WUNTRACED ] pid |> ignore 175 - with 176 - | _ -> 177 - ())) 183 + [%log 184 + debug 185 + "pid: %i Cleaning up cancelled command %s" 186 + pid 187 + (args |> String.concat " ")]; 188 + (try Unix.kill pid Sys.sigkill with 189 + | Unix.Unix_error (Unix.ESRCH, _, _) -> 190 + () 191 + | _ -> 192 + ()); 193 + reap_once ~flags:[ Unix.WUNTRACED ] pid |> ignore)) 178 194 (fun _ -> 179 195 Unix.create_process_env 180 196 cmd ··· 185 201 stderr_i) 186 202 in 187 203 [%log debug "pid: %i started" pid]; 188 - let prom = Flock.fork_as_promise (fun () -> Unix.waitpid [] pid) in 204 + let prom = 205 + Flock.fork_as_promise (fun () -> 206 + match reap_once pid with 207 + | Some waited -> 208 + waited 209 + | None -> 210 + [%log debug "pid: %i already reaped before waitpid" pid]; 211 + pid, Unix.WEXITED 0) 212 + in 189 213 (* Close unused pipe ends in the parent process *) 190 214 Unix.close stdout_i; 191 215 Unix.close stdin_o;