Open
Description
Problem
Code that heavily depends on synchronous primitives like Mutex
can suffer unnecessary resource contention if the lock is only released at the end of its scope through Drop
but could in fact be released early.
fn example_1() {
let locked = some_sync_resource.lock();
let owned_rslt = locked.do_stuff_with_resource();
// Only `owned_rslt` is needed but `locked` is still held
do_heavy_computation_that_takes_time(owned_rslt);
}
fn example_2() {
let locked = some_sync_resource.lock();
let reference = locked.get_inner_resource_ref();
let _ = reference.do_stuff();
let _ = reference.do_other_things();
// From this point forward, `locked` is not needed anymore
let _ = compute_foo();
let _ = compute_bar();
let _ = compute_baz();
}
Request
A new lint called sync_lock_drop
that asks for an explicit "inline" expression or an explicit drop
call. The above snippets would then be rewritten as follows:
fn example_1() {
let owned_rslt = some_sync_resource.lock().do_stuff_with_resource();
do_heavy_computation_that_takes_time(owned_rslt);
}
fn example_2() {
let locked = some_sync_resource.lock();
let reference = locked.get_inner_resource_ref();
let _ = reference.do_stuff();
let _ = reference.do_other_things();
drop(locked);
let _ = compute_foo();
let _ = compute_bar();
let _ = compute_baz();
}
Implementation
It is trivial to detect synchronous primitives of the standard library but third-party implementations are tricky to detect. What should be done here? Hard code a list of well-known crates or allow users to provide a list of custom types?