1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::cell::UnsafeCell;
use crate::sync::atomic::{AtomicUsize, Ordering};

pub struct RWLock {
    inner: UnsafeCell<libc::pthread_rwlock_t>,
    write_locked: UnsafeCell<bool>, // 由 `inner` RwLock 保护
    num_readers: AtomicUsize,
}

pub type MovableRWLock = Box<RWLock>;

unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}

impl RWLock {
    pub const fn new() -> RWLock {
        RWLock {
            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
            write_locked: UnsafeCell::new(false),
            num_readers: AtomicUsize::new(0),
        }
    }
    #[inline]
    pub unsafe fn read(&self) {
        let r = libc::pthread_rwlock_rdlock(self.inner.get());

        // 根据 POSIX,当一个线程在它已经持有写锁的情况下试图获取这个读锁时 (反之亦然,或者试图获取写锁两次),这个调用要么死锁,要么返回 [EDEADLK]
        //
        // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html,
        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html).
        // 因此,原则上,我们要做的就是检查 `r == 0`,以确保我们正确地获得了锁。
        //
        // 但是,(至少) 版本 2.25 之前的 glibc 不符合该规范,并且即使该线程已持有写锁,它也可以返回 `r == 0`。
        // 因此,当我们检测到线程多次获得写锁定,或者获得读和写锁定时,我们自己和 panic 都检查了这种情况。
        //
        //
        //
        //
        //
        if r == libc::EAGAIN {
            panic!("rwlock maximum reader count exceeded");
        } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) {
            // 上面,我们确保仅在 `r == 0` 时访问 `write_locked`,以避免数据竞争。
            //
            if r == 0 {
                // `pthread_rwlock_rdlock` 在它不应该成功的时候成功了。
                self.raw_unlock();
            }
            panic!("rwlock read lock would result in deadlock");
        } else {
            // 根据 POSIX,对于正确初始化的 rwlock,它只能返回 EAGAIN 或 EDEADLK 或 0。
            // 我们依靠这一点。
            debug_assert_eq!(r, 0);
            self.num_readers.fetch_add(1, Ordering::Relaxed);
        }
    }
    #[inline]
    pub unsafe fn try_read(&self) -> bool {
        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() {
                // `pthread_rwlock_tryrdlock` 在它不应该成功的时候成功了。
                self.raw_unlock();
                false
            } else {
                self.num_readers.fetch_add(1, Ordering::Relaxed);
                true
            }
        } else {
            false
        }
    }
    #[inline]
    pub unsafe fn write(&self) {
        let r = libc::pthread_rwlock_wrlock(self.inner.get());
        // 有关我们为什么检查 EDEADLK 和 write_locked 的信息,请参见上面的评论。
        // 出于同样的原因,我们还需要检查是否没有 readers (在 `num_readers` 中跟踪)。
        if r == libc::EDEADLK
            || (r == 0 && *self.write_locked.get())
            || self.num_readers.load(Ordering::Relaxed) != 0
        {
            // 上面,我们确保仅在 `r == 0` 时访问 `write_locked`,以避免数据竞争。
            //
            if r == 0 {
                // `pthread_rwlock_wrlock` 在它不应该成功的时候成功了。
                self.raw_unlock();
            }
            panic!("rwlock write lock would result in deadlock");
        } else {
            // 根据 POSIX,对于正确初始化的 rwlock,此操作只能返回 EDEADLK 或 0。
            // 我们依靠这一点。
            debug_assert_eq!(r, 0);
        }
        *self.write_locked.get() = true;
    }
    #[inline]
    pub unsafe fn try_write(&self) -> bool {
        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
        if r == 0 {
            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
                // `pthread_rwlock_trywrlock` 在它不应该成功的时候成功了。
                self.raw_unlock();
                false
            } else {
                *self.write_locked.get() = true;
                true
            }
        } else {
            false
        }
    }
    #[inline]
    unsafe fn raw_unlock(&self) {
        let r = libc::pthread_rwlock_unlock(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    pub unsafe fn read_unlock(&self) {
        debug_assert!(!*self.write_locked.get());
        self.num_readers.fetch_sub(1, Ordering::Relaxed);
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn write_unlock(&self) {
        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
        debug_assert!(*self.write_locked.get());
        *self.write_locked.get() = false;
        self.raw_unlock();
    }
    #[inline]
    pub unsafe fn destroy(&self) {
        let r = libc::pthread_rwlock_destroy(self.inner.get());
        // 在 DragonFly 上,如果在刚刚用 libc::PTHREAD_RWLOCK_INITIALIZER 初始化的 rwlock 上调用,则 pthread_rwlock_destroy() 返回 EINVAL。
        // 一旦使用了 (locked/unlocked) 或 pthread_rwlock_init(),将不再发生此行为。
        //
        //
        if cfg!(target_os = "dragonfly") {
            debug_assert!(r == 0 || r == libc::EINVAL);
        } else {
            debug_assert_eq!(r, 0);
        }
    }
}