2023-05-02 13:16:48 +02:00
|
|
|
//! Unsafe linked list.
|
|
|
|
//! Translated from ST's C by `c2rust` tool.
|
|
|
|
|
|
|
|
#![allow(
|
|
|
|
dead_code,
|
|
|
|
mutable_transmutes,
|
|
|
|
non_camel_case_types,
|
|
|
|
non_snake_case,
|
|
|
|
non_upper_case_globals,
|
|
|
|
unused_assignments,
|
|
|
|
unused_mut
|
|
|
|
)]
|
|
|
|
|
2023-06-14 00:12:34 +02:00
|
|
|
use core::ptr;
|
|
|
|
|
2023-05-02 13:16:48 +02:00
|
|
|
use cortex_m::interrupt;
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
#[repr(C, packed(4))]
|
|
|
|
pub struct LinkedListNode {
|
|
|
|
pub next: *mut LinkedListNode,
|
|
|
|
pub prev: *mut LinkedListNode,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for LinkedListNode {
|
|
|
|
fn default() -> Self {
|
|
|
|
LinkedListNode {
|
|
|
|
next: core::ptr::null_mut(),
|
|
|
|
prev: core::ptr::null_mut(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-20 17:11:29 +02:00
|
|
|
impl LinkedListNode {
|
2023-06-14 00:12:34 +02:00
|
|
|
pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) {
|
|
|
|
ptr::write_volatile(
|
|
|
|
p_list_head,
|
|
|
|
LinkedListNode {
|
|
|
|
next: p_list_head,
|
|
|
|
prev: p_list_head,
|
|
|
|
},
|
|
|
|
);
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 00:12:34 +02:00
|
|
|
pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
|
|
|
|
interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 00:12:34 +02:00
|
|
|
/// Insert `node` after `list_head` and before the next node
|
|
|
|
pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 00:12:34 +02:00
|
|
|
let mut list_head = ptr::read_volatile(p_list_head);
|
2023-06-14 04:10:42 +02:00
|
|
|
if p_list_head != list_head.next {
|
|
|
|
let mut node_next = ptr::read_volatile(list_head.next);
|
|
|
|
let node = LinkedListNode {
|
|
|
|
next: list_head.next,
|
|
|
|
prev: p_list_head,
|
|
|
|
};
|
|
|
|
|
|
|
|
list_head.next = p_node;
|
|
|
|
node_next.prev = p_node;
|
|
|
|
|
|
|
|
// All nodes must be written because they will all be seen by another core
|
|
|
|
ptr::write_volatile(p_node, node);
|
|
|
|
ptr::write_volatile(node.next, node_next);
|
|
|
|
ptr::write_volatile(p_list_head, list_head);
|
|
|
|
} else {
|
|
|
|
let node = LinkedListNode {
|
|
|
|
next: list_head.next,
|
|
|
|
prev: p_list_head,
|
|
|
|
};
|
|
|
|
|
|
|
|
list_head.next = p_node;
|
|
|
|
list_head.prev = p_node;
|
|
|
|
|
|
|
|
// All nodes must be written because they will all be seen by another core
|
|
|
|
ptr::write_volatile(p_node, node);
|
|
|
|
ptr::write_volatile(p_list_head, list_head);
|
|
|
|
}
|
2023-05-20 17:11:29 +02:00
|
|
|
});
|
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 00:12:34 +02:00
|
|
|
/// Insert `node` before `list_tail` and after the second-to-last node
|
|
|
|
pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 00:12:34 +02:00
|
|
|
let mut list_tail = ptr::read_volatile(p_list_tail);
|
2023-06-14 04:10:42 +02:00
|
|
|
if p_list_tail != list_tail.prev {
|
|
|
|
let mut node_prev = ptr::read_volatile(list_tail.prev);
|
|
|
|
let node = LinkedListNode {
|
|
|
|
next: p_list_tail,
|
|
|
|
prev: list_tail.prev,
|
|
|
|
};
|
|
|
|
|
|
|
|
list_tail.prev = p_node;
|
|
|
|
node_prev.next = p_node;
|
|
|
|
|
|
|
|
// All nodes must be written because they will all be seen by another core
|
|
|
|
ptr::write_volatile(p_node, node);
|
|
|
|
ptr::write_volatile(node.prev, node_prev);
|
|
|
|
ptr::write_volatile(p_list_tail, list_tail);
|
|
|
|
} else {
|
|
|
|
let node = LinkedListNode {
|
|
|
|
next: p_list_tail,
|
|
|
|
prev: list_tail.prev,
|
|
|
|
};
|
|
|
|
|
|
|
|
list_tail.prev = p_node;
|
|
|
|
list_tail.next = p_node;
|
|
|
|
|
|
|
|
// All nodes must be written because they will all be seen by another core
|
|
|
|
ptr::write_volatile(p_node, node);
|
|
|
|
ptr::write_volatile(p_list_tail, list_tail);
|
|
|
|
}
|
2023-05-20 17:11:29 +02:00
|
|
|
});
|
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 00:12:34 +02:00
|
|
|
/// Remove `node` from the linked list
|
|
|
|
pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-17 19:00:33 +02:00
|
|
|
// trace!("remove node: {:x}", p_node);
|
|
|
|
// apparently linked list nodes are not always aligned.
|
|
|
|
// if more hardfaults occur, more of these may need to be converted to unaligned.
|
|
|
|
let node = ptr::read_unaligned(p_node);
|
|
|
|
// trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
|
2023-06-17 18:02:31 +02:00
|
|
|
|
2023-06-14 04:10:42 +02:00
|
|
|
if node.next != node.prev {
|
|
|
|
let mut node_next = ptr::read_volatile(node.next);
|
|
|
|
let mut node_prev = ptr::read_volatile(node.prev);
|
|
|
|
|
|
|
|
node_prev.next = node.next;
|
|
|
|
node_next.prev = node.prev;
|
2023-06-14 01:04:05 +02:00
|
|
|
|
2023-06-14 04:10:42 +02:00
|
|
|
ptr::write_volatile(node.next, node_next);
|
|
|
|
ptr::write_volatile(node.prev, node_prev);
|
|
|
|
} else {
|
|
|
|
let mut node_next = ptr::read_volatile(node.next);
|
|
|
|
|
|
|
|
node_next.next = node.next;
|
|
|
|
node_next.prev = node.prev;
|
|
|
|
|
|
|
|
ptr::write_volatile(node.next, node_next);
|
|
|
|
}
|
2023-05-20 17:11:29 +02:00
|
|
|
});
|
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 04:10:42 +02:00
|
|
|
/// Remove `list_head` and return a pointer to the `node`.
|
2023-06-17 03:15:03 +02:00
|
|
|
pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 00:12:34 +02:00
|
|
|
let list_head = ptr::read_volatile(p_list_head);
|
|
|
|
|
2023-06-17 03:15:03 +02:00
|
|
|
if list_head.next == p_list_head {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
// Allowed because a removed node is not seen by another core
|
|
|
|
let p_node = list_head.next;
|
|
|
|
Self::remove_node(p_node);
|
2023-06-14 04:10:42 +02:00
|
|
|
|
2023-06-17 03:15:03 +02:00
|
|
|
Some(p_node)
|
|
|
|
}
|
2023-06-14 04:10:42 +02:00
|
|
|
})
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 04:10:42 +02:00
|
|
|
/// Remove `list_tail` and return a pointer to the `node`.
|
2023-06-17 03:15:03 +02:00
|
|
|
pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 00:12:34 +02:00
|
|
|
let list_tail = ptr::read_volatile(p_list_tail);
|
|
|
|
|
2023-06-17 03:15:03 +02:00
|
|
|
if list_tail.prev == p_list_tail {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
// Allowed because a removed node is not seen by another core
|
|
|
|
let p_node = list_tail.prev;
|
|
|
|
Self::remove_node(p_node);
|
2023-06-14 04:10:42 +02:00
|
|
|
|
2023-06-17 03:15:03 +02:00
|
|
|
Some(p_node)
|
|
|
|
}
|
2023-06-14 04:10:42 +02:00
|
|
|
})
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-05-20 17:11:29 +02:00
|
|
|
pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
|
|
|
interrupt::free(|_| {
|
|
|
|
(*node).next = (*ref_node).next;
|
|
|
|
(*node).prev = ref_node;
|
|
|
|
(*ref_node).next = node;
|
|
|
|
(*(*node).next).prev = node;
|
|
|
|
});
|
2023-06-14 04:10:42 +02:00
|
|
|
|
|
|
|
todo!("this function has not been converted to volatile semantics");
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-05-20 17:11:29 +02:00
|
|
|
pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
|
|
|
interrupt::free(|_| {
|
|
|
|
(*node).next = ref_node;
|
|
|
|
(*node).prev = (*ref_node).prev;
|
|
|
|
(*ref_node).prev = node;
|
|
|
|
(*(*node).prev).next = node;
|
|
|
|
});
|
2023-06-14 04:10:42 +02:00
|
|
|
|
|
|
|
todo!("this function has not been converted to volatile semantics");
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-05-20 17:20:35 +02:00
|
|
|
pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
|
|
|
let mut size = 0;
|
|
|
|
let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-05-20 17:20:35 +02:00
|
|
|
temp = (*list_head).next;
|
|
|
|
while temp != list_head {
|
2023-05-20 17:11:29 +02:00
|
|
|
size += 1;
|
|
|
|
temp = (*temp).next
|
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-05-20 17:11:29 +02:00
|
|
|
size
|
2023-06-14 04:10:42 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
todo!("this function has not been converted to volatile semantics");
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 04:15:01 +02:00
|
|
|
pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 00:12:34 +02:00
|
|
|
let ref_node = ptr::read_volatile(p_ref_node);
|
|
|
|
|
|
|
|
// Allowed because a removed node is not seen by another core
|
2023-06-14 04:15:01 +02:00
|
|
|
ref_node.next
|
|
|
|
})
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
|
2023-06-14 04:15:01 +02:00
|
|
|
pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
|
2023-05-20 17:11:29 +02:00
|
|
|
interrupt::free(|_| {
|
2023-06-14 04:10:42 +02:00
|
|
|
let ref_node = ptr::read_volatile(p_ref_node);
|
|
|
|
|
|
|
|
// Allowed because a removed node is not seen by another core
|
2023-06-14 04:15:01 +02:00
|
|
|
ref_node.prev
|
|
|
|
})
|
2023-05-20 17:11:29 +02:00
|
|
|
}
|
2023-05-02 13:16:48 +02:00
|
|
|
}
|
2023-06-14 01:04:05 +02:00
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) {
|
|
|
|
info!("iterating list from node: {:x}", p_node);
|
|
|
|
let mut p_current_node = p_node;
|
|
|
|
let mut i = 0;
|
|
|
|
loop {
|
|
|
|
let current_node = ptr::read_volatile(p_current_node);
|
|
|
|
info!(
|
|
|
|
"node (prev, current, next): {:x}, {:x}, {:x}",
|
|
|
|
current_node.prev, p_current_node, current_node.next
|
|
|
|
);
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
if i > 10 || current_node.next == p_node {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_current_node = current_node.next;
|
|
|
|
}
|
|
|
|
}
|