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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// SPDX-License-Identifier: GPL-2.0

//! A kernel read/write mutex.
//!
//! This module allows Rust code to use the kernel's [`struct rw_semaphore`].
//!
//! C header: [`include/linux/rwsem.h`](../../../../include/linux/rwsem.h)

use super::{
    mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, LockIniter, ReadLock,
    WriteLock,
};
use crate::{bindings, str::CStr, Opaque};
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};

/// Safely initialises a [`RwSemaphore`] with the given name, generating a new lock class.
#[macro_export]
macro_rules! rwsemaphore_init {
    ($rwsem:expr, $name:literal) => {
        $crate::init_with_lockdep!($rwsem, $name)
    };
}

/// Exposes the kernel's [`struct rw_semaphore`].
///
/// It's a read/write mutex. That is, it allows multiple readers to acquire it concurrently, but
/// only one writer at a time. On contention, waiters sleep.
///
/// A [`RwSemaphore`] must first be initialised with a call to [`RwSemaphore::init_lock`] before it
/// can be used. The [`rwsemaphore_init`] macro is provided to automatically assign a new lock
/// class to an [`RwSemaphore`] instance.
///
/// Since it may block, [`RwSemaphore`] needs to be used with care in atomic contexts.
///
/// [`struct rw_semaphore`]: ../../../include/linux/rwsem.h
pub struct RwSemaphore<T: ?Sized> {
    /// The kernel `struct rw_semaphore` object.
    rwsem: Opaque<bindings::rw_semaphore>,

    /// An rwsem needs to be pinned because it contains a [`struct list_head`] that is
    /// self-referential, so it cannot be safely moved once it is initialised.
    _pin: PhantomPinned,

    /// The data protected by the rwsem.
    data: UnsafeCell<T>,
}

// SAFETY: `RwSemaphore` can be transferred across thread boundaries iff the data it protects can.
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl<T: ?Sized + Send> Send for RwSemaphore<T> {}

// SAFETY: `RwSemaphore` requires that the protected type be `Sync` for it to be `Sync` as well
// because the read mode allows multiple threads to access the protected data concurrently. It
// requires `Send` because the write lock allows a `&mut T` to be accessible from an arbitrary
// thread.
unsafe impl<T: ?Sized + Send + Sync> Sync for RwSemaphore<T> {}

impl<T> RwSemaphore<T> {
    /// Constructs a new rw semaphore.
    ///
    /// # Safety
    ///
    /// The caller must call [`RwSemaphore::init_lock`] before using the rw semaphore.
    pub unsafe fn new(t: T) -> Self {
        Self {
            rwsem: Opaque::uninit(),
            data: UnsafeCell::new(t),
            _pin: PhantomPinned,
        }
    }
}

impl<T: ?Sized> RwSemaphore<T> {
    /// Locks the rw semaphore in write (exclusive) mode and gives the caller access to the data
    /// protected by it. Only one thread at a time is allowed to access the protected data.
    pub fn write(&self) -> Guard<'_, Self> {
        let ctx = <Self as Lock>::lock_noguard(self);
        // SAFETY: The rw semaphore was just acquired in write mode.
        unsafe { Guard::new(self, ctx) }
    }

    /// Locks the rw semaphore in read (shared) mode and gives the caller access to the data
    /// protected by it. Only one thread at a time is allowed to access the protected data.
    pub fn read(&self) -> Guard<'_, Self, ReadLock> {
        let ctx = <Self as Lock<ReadLock>>::lock_noguard(self);
        // SAFETY: The rw semaphore was just acquired in read mode.
        unsafe { Guard::new(self, ctx) }
    }
}

impl<T> LockFactory for RwSemaphore<T> {
    type LockedType<U> = RwSemaphore<U>;

    unsafe fn new_lock<U>(data: U) -> RwSemaphore<U> {
        // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called.
        unsafe { RwSemaphore::new(data) }
    }
}

impl<T> LockIniter for RwSemaphore<T> {
    fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) {
        unsafe { bindings::__init_rwsem(self.rwsem.get(), name.as_char_ptr(), key.get()) };
    }
}

// SAFETY: The underlying kernel `struct rw_semaphore` object ensures mutual exclusion because it's
// acquired in write mode.
unsafe impl<T: ?Sized> Lock for RwSemaphore<T> {
    type Inner = T;
    type GuardContext = EmptyGuardContext;

    fn lock_noguard(&self) -> EmptyGuardContext {
        // SAFETY: `rwsem` points to valid memory.
        unsafe { bindings::down_write(self.rwsem.get()) };
        EmptyGuardContext
    }

    unsafe fn unlock(&self, _: &mut EmptyGuardContext) {
        // SAFETY: The safety requirements of the function ensure that the rw semaphore is owned by
        // the caller.
        unsafe { bindings::up_write(self.rwsem.get()) };
    }

    fn locked_data(&self) -> &UnsafeCell<T> {
        &self.data
    }
}

// SAFETY: The underlying kernel `struct rw_semaphore` object ensures that only shared references
// are accessible from other threads because it's acquired in read mode.
unsafe impl<T: ?Sized> Lock<ReadLock> for RwSemaphore<T> {
    type Inner = T;
    type GuardContext = EmptyGuardContext;

    fn lock_noguard(&self) -> EmptyGuardContext {
        // SAFETY: `rwsem` points to valid memory.
        unsafe { bindings::down_read(self.rwsem.get()) };
        EmptyGuardContext
    }

    unsafe fn unlock(&self, _: &mut EmptyGuardContext) {
        // SAFETY: The safety requirements of the function ensure that the rw semaphore is owned by
        // the caller.
        unsafe { bindings::up_read(self.rwsem.get()) };
    }

    fn locked_data(&self) -> &UnsafeCell<T> {
        &self.data
    }
}

/// A revocable rw semaphore.
///
/// That is, a read/write semaphore to which access can be revoked at runtime. It is a
/// specialisation of the more generic [`super::revocable::Revocable`].
///
/// # Examples
///
/// ```
/// # use kernel::sync::RevocableRwSemaphore;
/// # use kernel::revocable_init;
/// # use core::pin::Pin;
///
/// struct Example {
///     a: u32,
///     b: u32,
/// }
///
/// fn read_sum(v: &RevocableRwSemaphore<Example>) -> Option<u32> {
///     let guard = v.try_read()?;
///     Some(guard.a + guard.b)
/// }
///
/// fn add_two(v: &RevocableRwSemaphore<Example>) -> Option<u32> {
///     let mut guard = v.try_write()?;
///     guard.a += 2;
///     guard.b += 2;
///     Some(guard.a + guard.b)
/// }
///
/// // SAFETY: We call `revocable_init` immediately below.
/// let mut v = unsafe { RevocableRwSemaphore::new(Example { a: 10, b: 20 }) };
/// // SAFETY: We never move out of `v`.
/// let pinned = unsafe { Pin::new_unchecked(&mut v) };
/// revocable_init!(pinned, "example::v");
/// assert_eq!(read_sum(&v), Some(30));
/// assert_eq!(add_two(&v), Some(34));
/// v.revoke();
/// assert_eq!(read_sum(&v), None);
/// assert_eq!(add_two(&v), None);
/// ```
pub type RevocableRwSemaphore<T> = super::revocable::Revocable<RwSemaphore<()>, T>;

/// A guard for a revocable rw semaphore..
pub type RevocableRwSemaphoreGuard<'a, T, I = WriteLock> =
    super::revocable::RevocableGuard<'a, RwSemaphore<()>, T, I>;