258 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! 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
 | |
| )]
 | |
| 
 | |
| use core::ptr;
 | |
| 
 | |
| 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(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl LinkedListNode {
 | |
|     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,
 | |
|             },
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
 | |
|         interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
 | |
|     }
 | |
| 
 | |
|     /// 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) {
 | |
|         interrupt::free(|_| {
 | |
|             let mut list_head = ptr::read_volatile(p_list_head);
 | |
|             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);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /// 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) {
 | |
|         interrupt::free(|_| {
 | |
|             let mut list_tail = ptr::read_volatile(p_list_tail);
 | |
|             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);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /// Remove `node` from the linked list
 | |
|     pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
 | |
|         interrupt::free(|_| {
 | |
|             // 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);
 | |
| 
 | |
|             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;
 | |
| 
 | |
|                 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);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /// Remove `list_head` and return a pointer to the `node`.
 | |
|     pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
 | |
|         interrupt::free(|_| {
 | |
|             let list_head = ptr::read_volatile(p_list_head);
 | |
| 
 | |
|             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);
 | |
| 
 | |
|                 Some(p_node)
 | |
|             }
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     /// Remove `list_tail` and return a pointer to the `node`.
 | |
|     pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
 | |
|         interrupt::free(|_| {
 | |
|             let list_tail = ptr::read_volatile(p_list_tail);
 | |
| 
 | |
|             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);
 | |
| 
 | |
|                 Some(p_node)
 | |
|             }
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|         });
 | |
| 
 | |
|         todo!("this function has not been converted to volatile semantics");
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|         });
 | |
| 
 | |
|         todo!("this function has not been converted to volatile semantics");
 | |
|     }
 | |
| 
 | |
|     pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
 | |
|         interrupt::free(|_| {
 | |
|             let mut size = 0;
 | |
|             let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
 | |
| 
 | |
|             temp = (*list_head).next;
 | |
|             while temp != list_head {
 | |
|                 size += 1;
 | |
|                 temp = (*temp).next
 | |
|             }
 | |
| 
 | |
|             size
 | |
|         });
 | |
| 
 | |
|         todo!("this function has not been converted to volatile semantics");
 | |
|     }
 | |
| 
 | |
|     pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
 | |
|         interrupt::free(|_| {
 | |
|             let ref_node = ptr::read_volatile(p_ref_node);
 | |
| 
 | |
|             // Allowed because a removed node is not seen by another core
 | |
|             ref_node.next
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
 | |
|         interrupt::free(|_| {
 | |
|             let ref_node = ptr::read_volatile(p_ref_node);
 | |
| 
 | |
|             // Allowed because a removed node is not seen by another core
 | |
|             ref_node.prev
 | |
|         })
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[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;
 | |
|     }
 | |
| }
 |