-
Notifications
You must be signed in to change notification settings - Fork 2
Unique lock specs #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
780719b
scoped_lock spec: drop dead code
pgiarrusso-sl b130910
unique_lock spec
pgiarrusso-sl 553f737
refactor post condition of dtor and move operator in unique_lock
dkxb c3fa321
lock/unlock (alt) specs
pgiarrusso-sl d53b445
(try and fail to) derive alt specs from base ones
pgiarrusso-sl afcf05b
ensure_unlock: fix bug
pgiarrusso-sl ba6e935
Add unique_lock tests
pgiarrusso-sl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #include <mutex> | ||
|
|
||
| template class std::lock_guard<std::mutex>; | ||
| template class std::unique_lock<std::mutex>; | ||
| template class std::scoped_lock<std::mutex, std::mutex>; |
This file contains hidden or 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 hidden or 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 hidden or 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,314 @@ | ||
| Require Import skylabs.auto.cpp.prelude.proof. | ||
| Require Import skylabs.brick.libstdcpp.mutex.inc_hpp. | ||
|
|
||
| Require Export skylabs.brick.libstdcpp.runtime.pred. | ||
| Require Import skylabs.brick.libstdcpp.mutex.spec.mutex. | ||
|
|
||
| Module defer_lock_t. | ||
| Section with_cpp. | ||
| Context `{Σ : cpp_logic, σ : genv}. | ||
|
|
||
| Parameter R : forall {σ : genv}, cQp.t -> Rep. | ||
| #[only(cfracsplittable, type_ptr="std::defer_lock_t")] derive R. | ||
|
|
||
| cpp.spec "std::defer_lock_t::defer_lock_t(const std::defer_lock_t&)" as defer_lock_copy_ctor_spec from source with ( | ||
| \this this | ||
| \arg{other} "other" (Vptr other) | ||
| \prepost{q} other |-> R q | ||
| \post this |-> R 1$m | ||
| ). | ||
| cpp.spec "std::defer_lock_t::~defer_lock_t()" as defer_lock_dtor_spec from source with ( | ||
| \this this | ||
| \pre this |-> R 1$m | ||
| \post emp | ||
| ). | ||
| End with_cpp. | ||
| End defer_lock_t. | ||
|
|
||
| Module unique_lock. | ||
| Section with_cpp. | ||
| Context `{Σ : cpp_logic}. | ||
|
|
||
| (* a unique_lock may have an associated mutex, if so it holds | ||
| (Some (b * mutex_state)) where b indicates whether the unique_lock | ||
| has acquired the associated mutex. *) | ||
| Parameter R : forall {HAS_THREADS : HasStdThreads Σ} {σ : genv}, | ||
| cQp.t -> option (bool * (ptr * gname * Qp * mpred)) -> Rep. | ||
|
|
||
| Definition owned (om : option (bool * (ptr * gname * Qp * mpred))) : bool := | ||
| match om with | ||
| | Some (own, _) => own | ||
| | None => false | ||
| end. | ||
|
|
||
| Definition mutex (om : option (bool * (ptr * gname * Qp * mpred))) : ptr := | ||
| match om with | ||
| | Some (_, (mp, g, q, P)) => mp | ||
| | None => nullptr | ||
| end. | ||
|
|
||
| #[only(cfracsplittable,type_ptr="std::unique_lock<std::mutex>")] derive R. | ||
|
|
||
| Section with_threads. | ||
| Context {σ : genv}. | ||
| Context `{HAS_THREADS : !HasStdThreads Σ}. | ||
|
|
||
| #[global] Instance: LearnEqF1 R := ltac:(solve_learnable). | ||
|
|
||
| (* TODO maybe a class / interface Lockable that exposes do_lock, do_unlock | ||
| and the rep predicate R, formalizing the C++ lockable concept | ||
| <https://en.cppreference.com/w/cpp/named_req/Lockable.html>. | ||
|
|
||
| Instantiate with mutex, recursive_mutex, maybe in different styles (AC | ||
| and invariant styles). | ||
| *) | ||
|
|
||
| (* | ||
| TODO: could we write something like this? | ||
| Definition do_unlock_spec_body (thr : thread_idT) (lk : ptr * gname * Qp * mpred) (Q : mpred) : WpSpec_cpp := | ||
| match lk with | ||
| | (mp, g, q, P) => | ||
| \pre mutex.locked g thr q | ||
| \pre ▷P | ||
| \post mutex.token g q | ||
| end. | ||
| *) | ||
|
|
||
| Definition do_unlock (thr : thread_idT) (lk : ptr * gname * Qp * mpred) (Q : mpred) : mpred := | ||
| match lk with | ||
| | (mp, g, q, P) => | ||
| mutex.locked g thr q ** ▷P ** | ||
| (* TODO readd *) | ||
| (* ▷ *) | ||
| (mutex.token g q -* Q) | ||
| end. | ||
|
|
||
| Definition do_lock (thr : thread_idT) (lk : ptr * gname * Qp * mpred) (Q : mpred) : mpred := | ||
| match lk with | ||
| | (mp, g, q, P) => | ||
| mutex.token g q ** | ||
| (* TODO readd *) | ||
| (* ▷ *) | ||
| (mutex.locked g thr q ** ▷P -* Q) | ||
| end. | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unique_lock()" | ||
| as default_ctor_spec from source with ( | ||
| \this this | ||
| \post this |-> R 1$m None | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unique_lock(std::mutex&)" as mutex_ctor_spec_alt from source with ( | ||
| \this this | ||
| \arg{mp} "" (Vptr mp) | ||
| \pre{g q P} mp |-> mutex.R g q$m P | ||
| \persist{thr} current_thread thr | ||
| \pre{K} do_lock thr (mp, g, q, P) K | ||
| \post | ||
| this |-> R 1$m (Some (true, (mp, g, q, P))) ** | ||
| K | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unique_lock(std::mutex&)" as mutex_ctor_spec from source with ( | ||
| \this this | ||
| \arg{mp} "" (Vptr mp) | ||
| \pre{g q P} mp |-> mutex.R g q$m P | ||
| \pre mutex.token g q | ||
| \persist{thr} current_thread thr | ||
| \post | ||
| this |-> R 1$m (Some (true, (mp, g, q, P))) ** | ||
| P ** mutex.locked g thr q | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unique_lock(std::mutex&, std::defer_lock_t)" as mutex_defer_ctor_spec from source with ( | ||
| \this this | ||
| \arg{mp} "" (Vptr mp) | ||
| \pre{g q P} mp |-> mutex.R g q$m P | ||
| \arg{def_p} "" (Vptr def_p) | ||
| \post this |-> R 1$m (Some (false, (mp, g, q, P))) | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unique_lock(std::unique_lock<std::mutex> &&)" as move_ctor_spec from source with ( | ||
| \this this | ||
| \arg{other} "" (Vptr other) | ||
| \pre{om} other |-> R 1$m om | ||
| \post | ||
| this |-> R 1$m om ** | ||
| other |-> R 1$m None | ||
| ). | ||
|
|
||
| (** Ensures the associated mutex is unlocked and released. *) | ||
| Definition ensure_unlock (thr : thread_idT) (om : option (bool * (ptr * gname * Qp * mpred))) (Q : mpred) : mpred := | ||
| match om with | ||
| | Some (true, (mp, g, q, P)) => | ||
| letI* := do_unlock thr (mp, g, q, P) in | ||
| mp |-> mutex.R g q$m P -* Q | ||
| | Some (false, (mp, g, q, P)) => | ||
| ▷ (mp |-> mutex.R g q$m P -* Q) | ||
| | _ => | ||
| (* TODO should this be [bi_later Q]? *) | ||
| Q | ||
| end. | ||
|
|
||
| (* spec for dtor written with do_unlock. | ||
| Should be equivalent to dtor_spec. *) | ||
| cpp.spec "std::unique_lock<std::mutex>::~unique_lock()" as dtor_spec_alt from source with ( | ||
| \this this | ||
| \persist{thr} current_thread thr | ||
| \pre{om} this |-> R 1$m om | ||
| \pre{K} | ||
| ensure_unlock thr om K | ||
| \post K | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::~unique_lock()" as dtor_spec from source with ( | ||
| \this this | ||
| \persist{thr} current_thread thr | ||
| \pre{om} this |-> R 1$m om | ||
| \pre | ||
| match om with | ||
| | Some (true, (mp, g, q, P)) => mutex.locked g thr q ** ▷P | ||
| | _ => emp | ||
| end | ||
| \post | ||
| match om with | ||
| | Some (true, (mp, g, q, P)) => mp |-> mutex.R g q$m P ** mutex.token g q | ||
| | Some (false, (mp, g, q, P)) => mp |-> mutex.R g q$m P | ||
| | None => emp | ||
| end | ||
| ). | ||
|
|
||
| (* unlock the associated mutex, if any, and set input as the associated mutex. | ||
| Should be equivalent to move_assign_spec. *) | ||
| cpp.spec "std::unique_lock<std::mutex>::operator=(std::unique_lock<std::mutex> &&)" as move_assign_spec_alt from source with ( | ||
| \this this | ||
| \arg{other} "" (Vptr other) | ||
| \pre{om1} this |-> R 1$m om1 | ||
| \pre{om2} other |-> R 1$m om2 | ||
| \persist{thr} current_thread thr | ||
| \pre{K} | ||
| ensure_unlock thr om1 K | ||
| \post | ||
| this |-> R 1$m om2 ** | ||
| other |-> R 1$m None ** | ||
| K | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::operator=(std::unique_lock<std::mutex> &&)" as move_assign_spec from source with ( | ||
| \this this | ||
| \arg{other} "" (Vptr other) | ||
| \pre{om1} this |-> R 1$m om1 | ||
| \pre{om2} other |-> R 1$m om2 | ||
| \persist{thr} current_thread thr | ||
| \pre | ||
| match om1 with | ||
| | Some (true, (mp, g, q, P)) => mutex.locked g thr q ** ▷P | ||
| | _ => emp | ||
| end | ||
| \post | ||
| this |-> R 1$m om2 ** | ||
| other |-> R 1$m None ** | ||
| match om1 with | ||
| | Some (true, (mp, g, q, P)) => mp |-> mutex.R g q$m P ** mutex.token g q | ||
| | Some (false, (mp, g, q, P)) => mp |-> mutex.R g q$m P | ||
| | None => emp | ||
| end | ||
| ). | ||
|
|
||
| Notation owns_lock_spec_body := ( | ||
| \this this | ||
| \prepost{om q} this |-> R q om | ||
| \post [Vbool (owned om)] emp) (only parsing). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::owns_lock() const" as owns_lock_spec | ||
| from source with (owns_lock_spec_body). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::operator bool() const" as operator_bool_spec | ||
| from source with (owns_lock_spec_body). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::mutex() const" as mutex_spec from source with ( | ||
| \this this | ||
| \prepost{om q} this |-> R q om | ||
| \post[Vptr (mutex om)] emp | ||
| ). | ||
|
|
||
| (* these preconditions statically rule out cases that throw exceptions, such as: | ||
| - If there is no associated mutex, std::system_error with an error code of std::errc::operation_not_permitted. | ||
| - If the mutex is already locked by this unique_lock (in other words, owns_lock() is true), std::system_error with an error code of std::errc::resource_deadlock_would_occur. *) | ||
| cpp.spec "std::unique_lock<std::mutex>::lock()" as lock_spec from source with ( | ||
| \this this | ||
| \pre{mp g q P} this |-> R 1$m (Some (false, (mp, g, q, P))) | ||
| \pre mutex.token g q | ||
| \persist{thr} current_thread thr | ||
| \post | ||
| this |-> R 1$m (Some (true, (mp, g, q, P))) ** | ||
| P ** mutex.locked g thr q). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::lock()" as lock_spec_alt from source with ( | ||
| \this this | ||
| \pre{mm} this |-> R 1$m (Some (false, mm)) | ||
| \persist{thr} current_thread thr | ||
| \pre{K} do_lock thr mm K | ||
| \post | ||
| this |-> R 1$m (Some (true, mm)) ** | ||
| K). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unlock()" as unlock_spec from source with ( | ||
| \this this | ||
| \pre{mp g q P} this |-> R 1$m (Some (true, (mp, g, q, P))) | ||
| \persist{thr} current_thread thr | ||
| \pre mutex.locked g thr q | ||
| \pre ▷P | ||
| \post | ||
| this |-> R 1$m (Some (false, (mp, g, q, P))) ** | ||
| mutex.token g q | ||
| ). | ||
|
|
||
| cpp.spec "std::unique_lock<std::mutex>::unlock()" as unlock_spec_alt from source with ( | ||
| \this this | ||
| \pre{mm} this |-> R 1$m (Some (true, mm)) | ||
| \persist{thr} current_thread thr | ||
| \pre{K} do_unlock thr mm K | ||
| \post | ||
| this |-> R 1$m (Some (false, mm)) ** | ||
| K | ||
| ). | ||
|
|
||
| Lemma lock_spec_entails_lock_spec_alt : lock_spec |-- lock_spec_alt. | ||
| Proof. | ||
| apply specify_mono. | ||
| rewrite /do_lock. | ||
| go. | ||
| (* XXX needs removing later in do_lock, or a stronger specify_mono offering a later. *) | ||
| repeat case_match; go. | ||
| Qed. | ||
|
|
||
| Lemma unlock_spec_entails_unlock_spec_alt : unlock_spec |-- unlock_spec_alt. | ||
| Proof. | ||
| apply specify_mono. | ||
| rewrite /do_unlock. | ||
| go. | ||
| (* XXX needs removing later in do_unlock, or a stronger specify_mono offering a later. *) | ||
| repeat case_match; go. | ||
| Qed. | ||
|
|
||
| Lemma lock_spec_alt_entails_lock_spec : lock_spec_alt |-- lock_spec. | ||
| Proof. | ||
| apply specify_mono. | ||
| rewrite /do_lock. | ||
| go. | ||
| (* failed goal: ▷ P -∗ P. This might work with a stronger specify_mono offering a later. *) | ||
| admit. | ||
| all: fail. | ||
| Abort. | ||
|
|
||
| Lemma unlock_spec_alt_entails_unlock_spec : unlock_spec_alt |-- unlock_spec. | ||
| Proof. | ||
| apply specify_mono. | ||
| rewrite /do_unlock. | ||
| go. | ||
| Qed. | ||
|
|
||
| End with_threads. | ||
| End with_cpp. | ||
| End unique_lock. | ||
This file contains hidden or 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 hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.