@@ -5,9 +5,7 @@ use core::time::Duration;
5
5
use std:: collections:: HashSet ;
6
6
use std:: cell:: RefCell ;
7
7
8
- #[ cfg( not( feature = "backtrace" ) ) ]
9
8
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
10
-
11
9
use std:: sync:: Mutex as StdMutex ;
12
10
use std:: sync:: MutexGuard as StdMutexGuard ;
13
11
use std:: sync:: RwLock as StdRwLock ;
@@ -52,11 +50,10 @@ thread_local! {
52
50
/// We track the set of locks currently held by a reference to their `LockMetadata`
53
51
static LOCKS_HELD : RefCell <HashSet <Arc <LockMetadata >>> = RefCell :: new( HashSet :: new( ) ) ;
54
52
}
55
- #[ cfg( not( feature = "backtrace" ) ) ]
56
53
static LOCK_IDX : AtomicUsize = AtomicUsize :: new ( 0 ) ;
57
54
58
55
#[ cfg( feature = "backtrace" ) ]
59
- static mut LOCKS : Option < StdMutex < HashMap < u64 , Arc < LockMetadata > > > > = None ;
56
+ static mut LOCKS : Option < StdMutex < HashMap < String , Arc < LockMetadata > > > > = None ;
60
57
#[ cfg( feature = "backtrace" ) ]
61
58
static LOCKS_INIT : Once = Once :: new ( ) ;
62
59
@@ -94,40 +91,36 @@ impl std::hash::Hash for LockDep {
94
91
fn hash < H : std:: hash:: Hasher > ( & self , hasher : & mut H ) { hasher. write_u64 ( self . lock . lock_idx ) ; }
95
92
}
96
93
94
+ #[ cfg( feature = "backtrace" ) ]
95
+ fn get_construction_location ( backtrace : & Backtrace ) -> String {
96
+ // Find the first frame which is after `debug_sync` (or which is in our tests) and use
97
+ // that as the mutex construction site. Note that the first few frames may be in
98
+ // `backtrace`, so we have to ignore those.
99
+ let sync_mutex_constr_regex = regex:: Regex :: new ( r"lightning.*debug_sync.*new" ) . unwrap ( ) ;
100
+ let mut found_debug_sync = false ;
101
+ for frame in backtrace. frames ( ) {
102
+ for symbol in frame. symbols ( ) {
103
+ let symbol_name = symbol. name ( ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
104
+ if !sync_mutex_constr_regex. is_match ( symbol_name) {
105
+ if found_debug_sync {
106
+ if let Some ( col) = symbol. colno ( ) {
107
+ return format ! ( "{}:{}:{}" , symbol. filename( ) . unwrap( ) . display( ) , symbol. lineno( ) . unwrap( ) , col) ;
108
+ } else {
109
+ // Windows debug symbols don't support column numbers, so fall back to
110
+ // line numbers only if no `colno` is available
111
+ return format ! ( "{}:{}" , symbol. filename( ) . unwrap( ) . display( ) , symbol. lineno( ) . unwrap( ) ) ;
112
+ }
113
+ }
114
+ } else { found_debug_sync = true ; }
115
+ }
116
+ }
117
+ panic ! ( "Couldn't find mutex construction callsite" ) ;
118
+ }
119
+
97
120
impl LockMetadata {
98
121
fn new ( ) -> Arc < LockMetadata > {
99
- let lock_idx;
100
122
let backtrace = Backtrace :: new ( ) ;
101
-
102
- #[ cfg( not( feature = "backtrace" ) ) ]
103
- { lock_idx = LOCK_IDX . fetch_add ( 1 , Ordering :: Relaxed ) as u64 ; }
104
-
105
- #[ cfg( feature = "backtrace" ) ]
106
- {
107
- let mut ip = None ;
108
- // Find the first frame which is after `debug_sync` (or which is in our tests) and use
109
- // that as the mutex construction site. Note that the first few frames may be in
110
- // `backtrace`, so we have to ignore those.
111
- let sync_mutex_constr_regex = regex:: Regex :: new ( r"lightning.*debug_sync.*new" ) . unwrap ( ) ;
112
- let mut found_debug_sync = false ;
113
- for frame in backtrace. frames ( ) {
114
- // If a constructor was inlined we should take the frame in which it was inlined
115
- // (as its specific to the callsite), thus we look at the last available symbol,
116
- // which the `backtrace` docs say will be the caller.
117
- let symbol_name = frame. symbols ( ) . last ( ) . unwrap ( ) . name ( ) . unwrap ( ) . as_str ( ) . unwrap ( ) ;
118
- if !sync_mutex_constr_regex. is_match ( symbol_name) {
119
- if found_debug_sync {
120
- ip = Some ( frame. ip ( ) as usize as u64 ) ;
121
- break ;
122
- }
123
- } else { found_debug_sync = true ; }
124
- }
125
- lock_idx = ip. unwrap ( ) ;
126
- LOCKS_INIT . call_once ( || { unsafe { LOCKS = Some ( StdMutex :: new ( HashMap :: new ( ) ) ) ; } } ) ;
127
- if let Some ( metadata) = unsafe { LOCKS . as_ref ( ) } . unwrap ( ) . lock ( ) . unwrap ( ) . get ( & lock_idx) {
128
- return Arc :: clone ( & metadata) ;
129
- }
130
- }
123
+ let lock_idx = LOCK_IDX . fetch_add ( 1 , Ordering :: Relaxed ) as u64 ;
131
124
132
125
let res = Arc :: new ( LockMetadata {
133
126
locked_before : StdMutex :: new ( HashSet :: new ( ) ) ,
@@ -137,8 +130,10 @@ impl LockMetadata {
137
130
138
131
#[ cfg( feature = "backtrace" ) ]
139
132
{
133
+ let lock_constr_location = get_construction_location ( & res. _lock_construction_bt ) ;
134
+ LOCKS_INIT . call_once ( || { unsafe { LOCKS = Some ( StdMutex :: new ( HashMap :: new ( ) ) ) ; } } ) ;
140
135
let mut locks = unsafe { LOCKS . as_ref ( ) } . unwrap ( ) . lock ( ) . unwrap ( ) ;
141
- match locks. entry ( lock_idx ) {
136
+ match locks. entry ( lock_constr_location ) {
142
137
hash_map:: Entry :: Occupied ( e) => return Arc :: clone ( e. get ( ) ) ,
143
138
hash_map:: Entry :: Vacant ( e) => { e. insert ( Arc :: clone ( & res) ) ; } ,
144
139
}
@@ -168,7 +163,10 @@ impl LockMetadata {
168
163
for locked_dep in locked. locked_before . lock ( ) . unwrap ( ) . iter ( ) {
169
164
if locked_dep. lock == * this && locked_dep. lock != * locked {
170
165
#[ cfg( feature = "backtrace" ) ]
171
- panic ! ( "Tried to violate existing lockorder.\n Mutex that should be locked after the current lock was created at the following backtrace.\n Note that to get a backtrace for the lockorder violation, you should set RUST_BACKTRACE=1\n Lock constructed at:\n {:?}\n \n Lock dep created at:\n {:?}\n \n " , locked. _lock_construction_bt, locked_dep. lockdep_trace) ;
166
+ panic ! ( "Tried to violate existing lockorder.\n Mutex that should be locked after the current lock was created at the following backtrace.\n Note that to get a backtrace for the lockorder violation, you should set RUST_BACKTRACE=1\n Lock being taken constructed at: {} ({}):\n {:?}\n Lock constructed at: {} ({})\n {:?}\n \n Lock dep created at:\n {:?}\n \n " ,
167
+ get_construction_location( & this. _lock_construction_bt) , this. lock_idx, this. _lock_construction_bt,
168
+ get_construction_location( & locked. _lock_construction_bt) , locked. lock_idx, locked. _lock_construction_bt,
169
+ locked_dep. lockdep_trace) ;
172
170
#[ cfg( not( feature = "backtrace" ) ) ]
173
171
panic ! ( "Tried to violate existing lockorder. Build with the backtrace feature for more info." ) ;
174
172
}
0 commit comments