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
144
use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::sys::cvt_nz;

pub struct Mutex {
    inner: UnsafeCell<libc::pthread_mutex_t>,
}

pub type MovableMutex = Box<Mutex>;

#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
    m.inner.get()
}

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

#[allow(dead_code)] // sys 尚未导出
impl Mutex {
    pub const fn new() -> Mutex {
        // 可能将其移动到其他地址,因此最好避免在登陆之前可能不透明的 OS 数据进行初始化。
        //
        // 使用此新构造的 `Mutex` 时要格外小心,在调用 `init` 之前,可重入锁定是未定义的行为!
        //
        Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
    }
    #[inline]
    pub unsafe fn init(&mut self) {
        // Issue #33770
        //
        // 使用 PTHREAD_MUTEX_INITIALIZER 初始化的 pthread 互斥锁将具有 PTHREAD_MUTEX_DEFAULT 类型,如果您在已经持有锁 (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html) 的情况下尝试从同一线程重新锁定它,则该类型的行为不确定。
        // 即使 PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) 也是这种情况 - 在这种情况下,`pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` 当然与将其设置为 `PTHREAD_MUTEX_NORMAL` 相同,但是不设置任何模式都会导致互锁锁,其中重新锁定为 UB。
        //
        //
        // 实际上,glibc 利用这种未定义的行为来实现硬件锁清除,该操作使用硬件事务性内存来避免获取锁。在进行事务时,锁似乎已解锁。
        // 对于其他线程而言,这不是问题,因为如果检测到冲突,事务内存将终止,但是从同一线程重新锁定时,不会生成终止。
        //
        // 由于两次锁定相同的互斥锁将导致两个别名 &mut references,因此,我们创建类型为 PTHREAD_MUTEX_NORMAL 的互斥锁,如果尝试从同一线程重新锁定它,则可以确保死锁,从而避免了未定义的行为。
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //
        //
        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
        let attr = PthreadMutexAttr(&mut attr);
        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL))
            .unwrap();
        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
    }
    #[inline]
    pub unsafe fn lock(&self) {
        let r = libc::pthread_mutex_lock(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    pub unsafe fn unlock(&self) {
        let r = libc::pthread_mutex_unlock(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        libc::pthread_mutex_trylock(self.inner.get()) == 0
    }
    #[inline]
    #[cfg(not(target_os = "dragonfly"))]
    pub unsafe fn destroy(&self) {
        let r = libc::pthread_mutex_destroy(self.inner.get());
        debug_assert_eq!(r, 0);
    }
    #[inline]
    #[cfg(target_os = "dragonfly")]
    pub unsafe fn destroy(&self) {
        let r = libc::pthread_mutex_destroy(self.inner.get());
        // 在 DragonFly 上,如果在刚刚用 libc::PTHREAD_MUTEX_INITIALIZER 初始化的互斥锁上调用 pthread_mutex_destroy(),则返回 EINVAL。
        //
        // 一旦使用了 (locked/unlocked) 或 pthread_mutex_init(),将不再发生此行为。
        //
        debug_assert!(r == 0 || r == libc::EINVAL);
    }
}

pub struct ReentrantMutex {
    inner: UnsafeCell<libc::pthread_mutex_t>,
}

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
    }

    pub unsafe fn init(&self) {
        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
        let attr = PthreadMutexAttr(&mut attr);
        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE))
            .unwrap();
        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
    }

    pub unsafe fn lock(&self) {
        let result = libc::pthread_mutex_lock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        libc::pthread_mutex_trylock(self.inner.get()) == 0
    }

    pub unsafe fn unlock(&self) {
        let result = libc::pthread_mutex_unlock(self.inner.get());
        debug_assert_eq!(result, 0);
    }

    pub unsafe fn destroy(&self) {
        let result = libc::pthread_mutex_destroy(self.inner.get());
        debug_assert_eq!(result, 0);
    }
}

struct PthreadMutexAttr<'a>(&'a mut MaybeUninit<libc::pthread_mutexattr_t>);

impl Drop for PthreadMutexAttr<'_> {
    fn drop(&mut self) {
        unsafe {
            let result = libc::pthread_mutexattr_destroy(self.0.as_mut_ptr());
            debug_assert_eq!(result, 0);
        }
    }
}