10
10
11
11
use prelude:: v1:: * ;
12
12
13
+ use libc;
13
14
use cell:: UnsafeCell ;
14
15
use sys:: sync as ffi;
15
16
@@ -26,7 +27,23 @@ impl RWLock {
26
27
#[ inline]
27
28
pub unsafe fn read ( & self ) {
28
29
let r = ffi:: pthread_rwlock_rdlock ( self . inner . get ( ) ) ;
29
- debug_assert_eq ! ( r, 0 ) ;
30
+
31
+ // According to the pthread_rwlock_rdlock spec, this function **may**
32
+ // fail with EDEADLK if a deadlock is detected. On the other hand
33
+ // pthread mutexes will *never* return EDEADLK if they are initialized
34
+ // as the "fast" kind (which ours always are). As a result, a deadlock
35
+ // situation may actually return from the call to pthread_rwlock_rdlock
36
+ // instead of blocking forever (as mutexes and Windows rwlocks do). Note
37
+ // that not all unix implementations, however, will return EDEADLK for
38
+ // their rwlocks.
39
+ //
40
+ // We roughly maintain the deadlocking behavior by panicking to ensure
41
+ // that this lock acquisition does not succeed.
42
+ if r == libc:: EDEADLK {
43
+ panic ! ( "rwlock read lock would result in deadlock" ) ;
44
+ } else {
45
+ debug_assert_eq ! ( r, 0 ) ;
46
+ }
30
47
}
31
48
#[ inline]
32
49
pub unsafe fn try_read ( & self ) -> bool {
@@ -35,7 +52,12 @@ impl RWLock {
35
52
#[ inline]
36
53
pub unsafe fn write ( & self ) {
37
54
let r = ffi:: pthread_rwlock_wrlock ( self . inner . get ( ) ) ;
38
- debug_assert_eq ! ( r, 0 ) ;
55
+ // see comments above for why we check for EDEADLK
56
+ if r == libc:: EDEADLK {
57
+ panic ! ( "rwlock write lock would result in deadlock" ) ;
58
+ } else {
59
+ debug_assert_eq ! ( r, 0 ) ;
60
+ }
39
61
}
40
62
#[ inline]
41
63
pub unsafe fn try_write ( & self ) -> bool {
0 commit comments