Skip to content

Commit

Permalink
[multicore] avoid racing on chdir
Browse files Browse the repository at this point in the history
Summary:
In multicore we can't allow the workers to change the working directory concurrently in `Utils.do_in_dir` as they will eventually execute their functions in the wrong directory.

This diff introduces a mutex for exclusion, and removes redundant uses of the function which can crash due to recursively locking the mutex.

Reviewed By: jvillard

Differential Revision:
D67195918

Privacy Context Container: L1208441

fbshipit-source-id: 6f7c3518fbc9b638e8a5e71fa15bf4ce621ffe22
  • Loading branch information
ngorogiannis authored and facebook-github-bot committed Dec 13, 2024
1 parent 7fb8d07 commit b4aebc8
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 9 deletions.
10 changes: 5 additions & 5 deletions infer/src/base/DBWriter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ module F = Format
module ServerSocket = struct
let socket_name = ResultsDirEntryName.db_writer_socket_name

let socket_path = Config.toplevel_results_dir ^/ socket_name

let socket_addr = Unix.ADDR_UNIX socket_name

let socket_domain = Unix.domain_of_sockaddr socket_addr
Expand All @@ -22,7 +24,7 @@ module ServerSocket = struct
function. *)
let in_results_dir ~f = Utils.do_in_dir ~dir:Config.toplevel_results_dir ~f

let socket_exists () = in_results_dir ~f:(fun () -> Sys.file_exists_exn socket_name)
let socket_exists () = Sys.file_exists_exn socket_path

(* Error recuperation is done by attempting this function at module initialization time, and
not using DbWriter at all in case it fails. See {!can_use_socket} below. *)
Expand All @@ -37,12 +39,10 @@ module ServerSocket = struct
socket


let remove_socket_file () =
in_results_dir ~f:(fun () -> if socket_exists () then Unix.unlink socket_name)

let remove_socket_file () = if socket_exists () then Unix.unlink socket_path

let remove_socket socket =
in_results_dir ~f:(fun () -> Unix.close socket) ;
Unix.close socket ;
remove_socket_file ()


Expand Down
9 changes: 6 additions & 3 deletions infer/src/base/Utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -435,10 +435,13 @@ let timeit ~f =
(ret_val, duration)


let mutex = Error_checking_mutex.create ()

let do_in_dir ~dir ~f =
let cwd = Unix.getcwd () in
Unix.chdir dir ;
Exception.try_finally ~f ~finally:(fun () -> Unix.chdir cwd)
Error_checking_mutex.critical_section mutex ~f:(fun () ->
let cwd = Unix.getcwd () in
Unix.chdir dir ;
Exception.try_finally ~f ~finally:(fun () -> Unix.chdir cwd) )


let get_available_memory_MB () =
Expand Down
3 changes: 2 additions & 1 deletion infer/src/base/Utils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ val timeit : f:(unit -> 'a) -> 'a * Mtime.Span.t
(** Returns the execution time of [f] together with its result *)

val do_in_dir : dir:string -> f:(unit -> 'a) -> 'a
(** executes [f] after cding into [dir] and then restores original cwd *)
(** executes [f] after cding into [dir] and then restores original cwd. Uses a mutex to prevent
races on [chdir] in multicore mode. *)

val get_available_memory_MB : unit -> int option
(** On Linux systems, return [Some x] where [MemAvailable x] is in [/proc/meminfo]. Returns [None]
Expand Down

0 comments on commit b4aebc8

Please sign in to comment.