-
Notifications
You must be signed in to change notification settings - Fork 413
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10534 from gridbugs/stop-treating-toolchains-as-p…
…ackages-in-pkg-rules Stop treating toolchains as packages in pkg rules
- Loading branch information
Showing
7 changed files
with
347 additions
and
242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
open! Stdune | ||
module Flock = Dune_util.Flock | ||
module Scheduler = Dune_engine.Scheduler | ||
|
||
type t = | ||
{ flock : Flock.t | ||
; lock_path : Path.t | ||
} | ||
|
||
(* Global mutable set of names, used to prevent printing "waiting for | ||
lock" messages multiple times when multiple concurrent fibers try | ||
to take a lock at the same time. *) | ||
module Global_waiting_names = struct | ||
let state = lazy (String.Table.create 1) | ||
|
||
(* add a name to the set, returning [true] iff the name wasn't | ||
already in the set *) | ||
let add name = | ||
let state = Lazy.force state in | ||
String.Table.add state name () |> Result.is_ok | ||
;; | ||
|
||
let remove name = | ||
let state = Lazy.force state in | ||
String.Table.remove state name | ||
;; | ||
end | ||
|
||
let attempt_to_lock { flock; lock_path } ~name_for_messages ~timeout_s = | ||
let open Fiber.O in | ||
let current_dune_pid = Unix.getpid () in | ||
let rec loop timeout_s = | ||
match Flock.lock_non_block flock Flock.Exclusive with | ||
| Error e -> Fiber.return @@ Error e | ||
| Ok `Success -> | ||
Global_waiting_names.remove name_for_messages; | ||
Fiber.return (Ok `Success) | ||
| Ok `Failure -> handle_failure timeout_s | ||
and handle_failure timeout_s = | ||
let locked_by_pid = int_of_string (Io.read_file lock_path) in | ||
let sleep_duration_s = 0.1 in | ||
let remaining_duration_s = timeout_s -. sleep_duration_s in | ||
if remaining_duration_s <= 0.0 | ||
then Fiber.return (Ok `Timeout) | ||
else ( | ||
if locked_by_pid <> current_dune_pid && Global_waiting_names.add name_for_messages | ||
then | ||
(* Only print this message if the dune process that holds the | ||
lock isn't the current process and this is the first time | ||
that the current process has failed to take the lock since | ||
the last time it successfully took the lock. This prevents | ||
the situation where multiple fibers all attempt to take the | ||
lock concurrently while it's held by another process from | ||
causing the following message from being printed multiple | ||
times. *) | ||
User_message.print | ||
(User_message.make | ||
[ Pp.textf | ||
"Waiting for another instance of dune (pid %d) to release the lock for \ | ||
the resource %S..." | ||
locked_by_pid | ||
name_for_messages | ||
]); | ||
let* () = Scheduler.sleep sleep_duration_s in | ||
loop remaining_duration_s) | ||
in | ||
loop timeout_s | ||
;; | ||
|
||
let with_flock lock_path ~name_for_messages ~timeout_s ~f = | ||
let open Fiber.O in | ||
let parent = Path.parent_exn lock_path in | ||
Path.mkdir_p parent; | ||
let fd = | ||
Unix.openfile | ||
(Path.to_string lock_path) | ||
[ Unix.O_CREAT; O_WRONLY; O_SHARE_DELETE; O_CLOEXEC ] | ||
0o600 | ||
in | ||
let out = Unix.out_channel_of_descr fd in | ||
let flock = Flock.create fd in | ||
let current_dune_pid = Unix.getpid () in | ||
Fiber.finalize | ||
~finally:(fun () -> | ||
let+ () = Fiber.return () in | ||
close_out out) | ||
(fun () -> | ||
attempt_to_lock { flock; lock_path } ~name_for_messages ~timeout_s | ||
>>= function | ||
| Ok `Success -> | ||
Fiber.finalize | ||
(fun () -> | ||
Printf.fprintf out "%d%!" current_dune_pid; | ||
f ()) | ||
~finally:(fun () -> | ||
let+ () = Fiber.return () in | ||
match Flock.unlock flock with | ||
| Ok () -> | ||
(* Note that after the lock has been released, we | ||
deliberately don't delete the lock file to avoid a race | ||
condition where other processes or fibers still need to | ||
read the file to determine the process that held the | ||
lock. Even though the lock has been released, other | ||
parties may be in between timing out waiting for the | ||
lock and reading the lock file to get the pid to | ||
include in their error message. *) | ||
() | ||
| Error ue -> | ||
Unix_error.Detailed.create ue ~syscall:"flock" ~arg:"unlock" | ||
|> Unix_error.Detailed.raise) | ||
| Ok `Timeout -> | ||
let locked_by_pid = int_of_string (Io.read_file lock_path) in | ||
if locked_by_pid == current_dune_pid | ||
then | ||
Code_error.raise | ||
"timeout while waiting for flock, but flock was currently held by the \ | ||
current process" | ||
[ "name_for_messages", Dyn.string name_for_messages ] | ||
else | ||
User_error.raise | ||
~hints: | ||
[ Pp.textf | ||
"Another instance of dune (pid %d) currently holds the lock for the \ | ||
resource %S. If this is unexpected, terminate that process and re-run \ | ||
the command." | ||
locked_by_pid | ||
name_for_messages | ||
; Pp.textf | ||
"As a last resort, if the other instance of dune (pid %d) is no longer \ | ||
running, manually delete the lock file %s." | ||
locked_by_pid | ||
(Path.to_string_maybe_quoted lock_path) | ||
] | ||
[ Pp.textf | ||
"Timed out after %.2f seconds while waiting for another instance of dune \ | ||
(pid %d) to release the lock on the resource %S." | ||
timeout_s | ||
locked_by_pid | ||
name_for_messages | ||
] | ||
| Error error -> | ||
User_error.raise | ||
[ Pp.textf | ||
"Failed to get a lock for the resource %S with lock file %s: %s" | ||
name_for_messages | ||
(Path.to_string_maybe_quoted lock_path) | ||
(Unix.error_message error) | ||
]) | ||
;; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
open! Stdune | ||
|
||
(** [with_flock path ~name_for_messages ~timeout_s ~f] ensures mutual | ||
exclusion for the function [f] across multiple concurrent | ||
instances of dune, using the lock file at [path] to coordinate | ||
between different dune instances. If the lock is not acquired | ||
after [timeout_s] seconds then a [User_error] is raised. Pass | ||
[infinity] to keep trying to take the lock | ||
forever. [name_for_messages] is the name used to refer to this | ||
lock in error messages. | ||
Within the a dune process, this function also ensures mutual | ||
exclusion between fibers. Note that if this function times out | ||
waiting for the lock while the lock is held by a different fiber | ||
of the same dune process, a [Code_error] is raised rather than a | ||
[User_error]. If a timeout is possible, avoid allowing multiple | ||
fibers to concurrently attempt to take a flock. *) | ||
val with_flock | ||
: Path.t | ||
-> name_for_messages:string | ||
-> timeout_s:float | ||
-> f:(unit -> 'a Fiber.t) | ||
-> 'a Fiber.t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.