nginx_sys/
queue.rs

1use core::ptr;
2
3use crate::bindings::ngx_queue_t;
4
5/// Get a reference to the beginning of a queue node data structure,
6/// considering the queue field offset in it.
7///
8/// # Safety
9///
10/// `$q` must be a valid pointer to the field `$link` in the struct `$type`
11#[macro_export]
12macro_rules! ngx_queue_data {
13    ($q:expr, $type:path, $link:ident) => {
14        $q.byte_sub(::core::mem::offset_of!($type, $link))
15            .cast::<$type>()
16    };
17}
18
19/// Initializes the queue head before use.
20///
21/// # Safety
22///
23/// `q` must be a valid pointer to [ngx_queue_t].
24#[inline]
25pub unsafe fn ngx_queue_init(q: *mut ngx_queue_t) {
26    (*q).prev = q;
27    (*q).next = q;
28}
29
30/// Returns `true` if the queue contains no elements.
31///
32/// # Safety
33///
34/// `q` must be a valid pointer to [ngx_queue_t], initialized with [ngx_queue_init].
35#[inline]
36pub unsafe fn ngx_queue_empty(q: *const ngx_queue_t) -> bool {
37    ptr::eq(q, (*q).prev)
38}
39
40/// Inserts a new node after the current.
41///
42/// # Safety
43///
44/// Both `q` and `x` must be valid pointers to [ngx_queue_t]
45#[inline]
46pub unsafe fn ngx_queue_insert_after(q: *mut ngx_queue_t, x: *mut ngx_queue_t) {
47    (*x).next = (*q).next;
48    (*(*x).next).prev = x;
49    (*x).prev = q;
50    (*q).next = x;
51}
52
53/// Inserts a new node before the current.
54///
55/// # Safety
56///
57/// Both `q` and `x` must be valid pointers to [ngx_queue_t].
58#[inline]
59pub unsafe fn ngx_queue_insert_before(q: *mut ngx_queue_t, x: *mut ngx_queue_t) {
60    (*x).prev = (*q).prev;
61    (*(*x).prev).next = x;
62    (*x).next = q;
63    (*q).prev = x;
64}
65
66/// Removes a node from the queue.
67///
68/// # Safety
69///
70/// `q` must be a valid pointer to an [ngx_queue_t] node.
71#[inline]
72pub unsafe fn ngx_queue_remove(q: *mut ngx_queue_t) {
73    (*(*q).next).prev = (*q).prev;
74    (*(*q).prev).next = (*q).next;
75    (*q).prev = ptr::null_mut();
76    (*q).next = ptr::null_mut();
77}
78
79/// Splits a queue at a node, returning the queue tail in a separate queue.
80///
81/// # Safety
82///
83/// `h` must be a valid pointer to a head queue node.
84/// `q` must be a node in the queue `h`.
85/// `n` must be a valid pointer to [ngx_queue_t].
86#[inline]
87pub unsafe fn ngx_queue_split(h: *mut ngx_queue_t, q: *mut ngx_queue_t, n: *mut ngx_queue_t) {
88    (*n).prev = (*h).prev;
89    (*(*n).prev).next = n;
90    (*n).next = q;
91    (*h).prev = (*q).prev;
92    (*(*h).prev).next = h;
93    (*q).prev = n;
94}
95
96/// Adds a second queue to the first queue.
97///
98/// # Safety
99///
100/// Both `h` and `n` must be valid pointers to queue heads, initialized with [ngx_queue_init].
101/// `n` will be left in invalid state, pointing to the subrange of `h` without back references.
102#[inline]
103pub unsafe fn ngx_queue_add(h: *mut ngx_queue_t, n: *mut ngx_queue_t) {
104    (*(*h).prev).next = (*n).next;
105    (*(*n).next).prev = (*h).prev;
106    (*h).prev = (*n).prev;
107    (*(*h).prev).next = h;
108}
109
110impl ngx_queue_t {
111    /// Returns `true` if the queue contains no elements.
112    pub fn is_empty(&self) -> bool {
113        unsafe { ngx_queue_empty(self) }
114    }
115}
116
117impl Default for ngx_queue_t {
118    fn default() -> ngx_queue_t {
119        ngx_queue_t {
120            prev: ptr::null_mut(),
121            next: ptr::null_mut(),
122        }
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    extern crate alloc;
129    use alloc::boxed::Box;
130
131    use super::*;
132
133    struct TestData {
134        value: usize,
135        queue: ngx_queue_t,
136    }
137
138    impl TestData {
139        pub fn new(value: usize) -> *mut Self {
140            // We should be using `ngx_pool_t` here, but that is not possible without linking to
141            // the nginx
142            let mut x = Box::new(Self {
143                value,
144                queue: Default::default(),
145            });
146            unsafe { ngx_queue_init(ptr::addr_of_mut!(x.queue)) };
147            Box::into_raw(x)
148        }
149
150        pub unsafe fn free(x: *mut Self) {
151            let _ = Box::from_raw(x);
152        }
153    }
154
155    impl Drop for TestData {
156        fn drop(&mut self) {
157            if !self.queue.next.is_null() && !self.queue.is_empty() {
158                unsafe { ngx_queue_remove(ptr::addr_of_mut!(self.queue)) };
159            }
160        }
161    }
162
163    struct Iter {
164        h: *mut ngx_queue_t,
165        q: *mut ngx_queue_t,
166        next: fn(*mut ngx_queue_t) -> *mut ngx_queue_t,
167    }
168
169    impl Iter {
170        pub fn new(h: *mut ngx_queue_t) -> Self {
171            let next = |x: *mut ngx_queue_t| unsafe { (*x).next };
172            Self {
173                h,
174                q: next(h),
175                next,
176            }
177        }
178
179        pub fn new_reverse(h: *mut ngx_queue_t) -> Self {
180            let next = |x: *mut ngx_queue_t| unsafe { (*x).prev };
181            Self {
182                h,
183                q: next(h),
184                next,
185            }
186        }
187    }
188
189    impl Iterator for Iter {
190        type Item = *mut ngx_queue_t;
191
192        fn next(&mut self) -> Option<Self::Item> {
193            if ptr::eq(self.h, self.q) {
194                return None;
195            }
196
197            let item = self.q;
198            self.q = (self.next)(self.q);
199            Some(item)
200        }
201    }
202
203    #[test]
204    fn test_queue() {
205        fn value(q: *mut ngx_queue_t) -> usize {
206            unsafe { (*ngx_queue_data!(q, TestData, queue)).value }
207        }
208
209        // Check forward and reverse iteration
210        fn cmp(h: *mut ngx_queue_t, other: &[usize]) -> bool {
211            Iter::new(h).map(value).eq(other.iter().cloned())
212                && Iter::new_reverse(h)
213                    .map(value)
214                    .eq(other.iter().rev().cloned())
215        }
216
217        // Note how this test does not use references or borrows to avoid triggering UBs
218        // detectable by Miri. This does not mean that the code is safe or sound.
219        unsafe {
220            // Initialize and fill the queue
221
222            let mut h1 = ngx_queue_t::default();
223            ngx_queue_init(ptr::addr_of_mut!(h1));
224
225            let mut h2 = ngx_queue_t::default();
226            ngx_queue_init(ptr::addr_of_mut!(h2));
227
228            for i in 1..=5 {
229                let elem = TestData::new(i);
230                ngx_queue_insert_before(ptr::addr_of_mut!(h1), ptr::addr_of_mut!((*elem).queue));
231
232                let elem = TestData::new(i);
233                ngx_queue_insert_after(ptr::addr_of_mut!(h2), ptr::addr_of_mut!((*elem).queue));
234            }
235
236            // Iterate and test the values
237
238            assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5]));
239            assert!(cmp(ptr::addr_of_mut!(h2), &[5, 4, 3, 2, 1]));
240
241            // Move nodes from h2 to h1
242
243            // h2 still points to the subrange of h1 after this operation
244            ngx_queue_add(ptr::addr_of_mut!(h1), ptr::addr_of_mut!(h2));
245
246            assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5, 5, 4, 3, 2, 1]));
247
248            ngx_queue_split(
249                ptr::addr_of_mut!(h1),
250                (*h2.next).next,
251                ptr::addr_of_mut!(h2),
252            );
253
254            assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5, 5]));
255            assert!(cmp(ptr::addr_of_mut!(h2), &[4, 3, 2, 1]));
256
257            // Cleanup
258
259            for q in Iter::new(ptr::addr_of_mut!(h1)) {
260                let td = ngx_queue_data!(q, TestData, queue);
261                TestData::free(td);
262            }
263            assert!(h1.is_empty());
264
265            for q in Iter::new(ptr::addr_of_mut!(h2)) {
266                let td = ngx_queue_data!(q, TestData, queue);
267                TestData::free(td);
268            }
269            assert!(h2.is_empty());
270        };
271    }
272}