Tokio deadlock detection?

How do people find deadlocks in their Tokio code? Are there any static tools/lints? I stupidly just wrote:

// value calculation is idempotent, so fine if another thread nips in and populates the cache before us
match cache.lock().await.get(k) {
  Some(v) => v.clone(),
  None => {
    let result = calculate_value(k);
    cache.lock().await.insert(k,v)
  }
}

It obviously deadlocks on the second lock because locks (to my surprise!) aren't reentrant.

But surely a lint or tool could find this sort of thing?

I don't use async locks. Per here: "an asynchronous mutex is more expensive than an ordinary mutex, and it is typically better to use one of the two other approaches".

I would be interested to know why you would be using them, as I cannot really imagine a situation where it would be a good idea. So just avoid would be my recommendation.

1 Like

Thanks @geebee22. Elsewhere I need to hold them across awaits, which require an async mutex, but the above code would still lock with sync mutex AFAIK.

1 Like

I don't think this is possible.

parking_lot has deadlock detection and Send guards, but they can't be used together.

Tokio loom is another way to do deadlock detection, but it works only with sync mutexes and doesn't have a Send guard.

1 Like

There's not really any tool for this.

You can tell that the locks aren't reentrant because they give mutable access to the contents. A reentrant lock can only give immutable access (but the contents may be Send + !Sync so they can contain a Cell or RefCell)

3 Likes

It's probably worth pointing out that deadlock detection of async locks is fundamentally impossible because locking the mutex in both branches of a tokio::join! is indistinguishable from your code, but if they are in separate branches of a tokio::join!, then its not necessarily a deadlock.

1 Like

Maybe you could use GitHub - tokio-rs/console: a debugger for async rust! to see which task is stuck?

2 Likes

thanks @alice , @kornel, @SkiFire13 for your comments :-). Tokio console looks fantastic, but I'm still struggling to figure out how to combine tracing with the rest of the log eco system (e.g. log4rs).