+struct LockDep {
+ lock: Arc<LockMetadata>,
+ lockdep_trace: Option<Backtrace>,
+}
+impl LockDep {
+ /// Note that `Backtrace::new()` is rather expensive so we rely on the caller to fill in the
+ /// `lockdep_backtrace` field after ensuring we need it.
+ fn new_without_bt(lock: &Arc<LockMetadata>) -> Self {
+ Self { lock: Arc::clone(lock), lockdep_trace: None }
+ }
+}
+impl PartialEq for LockDep {
+ fn eq(&self, o: &LockDep) -> bool { self.lock.lock_idx == o.lock.lock_idx }
+}
+impl Eq for LockDep {}
+impl std::hash::Hash for LockDep {
+ fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) { hasher.write_u64(self.lock.lock_idx); }
+}
+
+#[cfg(feature = "backtrace")]
+fn get_construction_location(backtrace: &Backtrace) -> String {
+ // Find the first frame that is after `debug_sync` (or that is in our tests) and use
+ // that as the mutex construction site. Note that the first few frames may be in
+ // the `backtrace` crate, so we have to ignore those.
+ let sync_mutex_constr_regex = regex::Regex::new(r"lightning.*debug_sync.*new").unwrap();
+ let mut found_debug_sync = false;
+ for frame in backtrace.frames() {
+ for symbol in frame.symbols() {
+ let symbol_name = symbol.name().unwrap().as_str().unwrap();
+ if !sync_mutex_constr_regex.is_match(symbol_name) {
+ if found_debug_sync {
+ if let Some(col) = symbol.colno() {
+ return format!("{}:{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap(), col);
+ } else {
+ // Windows debug symbols don't support column numbers, so fall back to
+ // line numbers only if no `colno` is available
+ return format!("{}:{}", symbol.filename().unwrap().display(), symbol.lineno().unwrap());
+ }
+ }
+ } else { found_debug_sync = true; }
+ }
+ }
+ panic!("Couldn't find mutex construction callsite");
+}
+