Skip to content

A Mutex wrapper tracking acquisition order

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

quisar/tracing-mutex

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tracing Mutex

Continuous integration Crates.io Documentation

Avoid deadlocks in your mutexes by acquiring them in a consistent order, or else.

Background

In any code that uses mutexes or locks, you quickly run into the possibility of deadlock. With just two mutexes Foo and Bar you can already deadlock, assuming one thread first locks Foo then attempts to get Bar and another first gets Bar then tries to get Foo. Now both threads are waiting for each other to release the lock they already have.

One simple way to get around this is by ensuring that, when you need both Foo and Bar, you should first acquire Foo then you can never deadlock. Of course, with just two mutexes, this is easy to keep track of, but once your code starts to grow you might lose track of all these dependencies. That's where this crate comes in.

This crate tracks the order in which you acquire locks in your code, tries to build a dependency tree out of it, and panics if your dependencies would create a cycle. It provides replacements for existing synchronization primitives with an identical API, and should be a drop-in replacement.

Inspired by this blogpost, which references a similar behaviour implemented by Abseil for their mutexes.

Usage

Add this dependency to your Cargo.lock file like any other:

[dependencies]
tracing-mutex = "0.2"

Then use the locks provided by this library instead of the ones you would use otherwise. Replacements for the synchronization primitives in std::sync can be found in the stdsync module. Support for other synchronization primitives is planned.

use tracing_mutex::stdsync::TracingMutex;

let some_mutex = TracingMutex::new(42);
*some_mutex.lock().unwrap() += 1;
println!("{:?}", some_mutex);

The interdependencies between locks are automatically tracked. If any locking operation would introduce a cyclic dependency between your locks, the operation panics instead. This allows you to immediately notice the cyclic dependency rather than be eventually surprised by it in production.

Mutex tracing is efficient, but it is not completely overhead-free. If you cannot spare the performance penalty in your production environment, this library also offers debug-only tracing. DebugMutex, also found in the stdsync module, is a type alias that evaluates to TracingMutex when debug assertions are enabled, and to Mutex when they are not. Similar helper types are available for other synchronization primitives.

Future improvements

  • Improve performance in lock tracing
  • Optional logging to make debugging easier
  • Better and configurable error handling when detecting cyclic dependencies
  • Support for other locking libraries, such as parking_lot

Note: parking_lot has already began work on its own deadlock detection mechanism, which works in a different way. Both can be complimentary.

License

Licensed under either of

at your option.

Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

A Mutex wrapper tracking acquisition order

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Rust 100.0%