From 3d3557f9b103ea6b87a612905db63d845d7466a2 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Fri, 2 Apr 2021 19:25:55 +0200
Subject: [PATCH] pool using cs

---
 Cargo.toml  |   1 +
 src/lib.rs  | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main.rs | 134 ---------------------------------------------
 3 files changed, 156 insertions(+), 134 deletions(-)
 create mode 100644 src/lib.rs
 delete mode 100644 src/main.rs

diff --git a/Cargo.toml b/Cargo.toml
index 1396ba4..5e023e0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+cortex-m = "0.7.2"
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..9b7a039
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,155 @@
+#![no_std]
+use core::cell::UnsafeCell;
+use core::ops::{Deref, DerefMut, Drop};
+use cortex_m::interrupt;
+
+/// Internal replacement for `static mut T`
+// TODO: Decide name and location.
+pub struct RacyCell<T>(UnsafeCell<T>);
+
+impl<T> RacyCell<T> {
+    /// Create a RacyCell
+    pub const fn new(value: T) -> Self {
+        RacyCell(UnsafeCell::new(value))
+    }
+
+    /// Get &mut T
+    pub unsafe fn get_mut_unchecked(&self) -> &mut T {
+        &mut *self.0.get()
+    }
+}
+
+// The type wrapped need to be Sync for RacyCell<T> to be Sync
+//unsafe impl<T> Sync for RacyCell<T> where T: Sync {}
+unsafe impl<T> Sync for RacyCell<T> {}
+
+#[inline]
+pub fn interrupt_free<F, R>(f: F) -> R
+where
+    F: FnOnce() -> R,
+{
+    if cfg!(target_arch = "arm") {
+        interrupt::free(|_| f())
+    } else {
+        f()
+    }
+}
+
+#[derive(Debug)]
+pub enum Error {
+    Uninitialized,
+    OutOfMemory,
+    AlreadyInitialized,
+}
+
+pub struct Box<T: 'static + Sized, const S: usize> {
+    index: usize,
+    allocator: &'static PoolMan<T, S>,
+}
+
+impl<T: 'static, const S: usize> Drop for Box<T, S> {
+    fn drop(&mut self) {
+        self.allocator.dealloc(self.index)
+    }
+}
+
+impl<T: 'static, const S: usize> Deref for Box<T, S> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        unsafe {
+            self.allocator
+                .data /* RacyCell */
+                .get_mut_unchecked() /* Array */
+                .get_unchecked(self.index)
+        }
+    }
+}
+
+impl<T: 'static, const S: usize> DerefMut for Box<T, S> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe {
+            self.allocator
+                .data /* RacyCell */
+                .get_mut_unchecked() /* Array */
+                .get_unchecked_mut(self.index)
+        }
+    }
+}
+
+pub struct PoolMan<T: 'static, const S: usize> {
+    data: RacyCell<[T; S]>,
+    free: RacyCell<[usize; S]>,
+    head: RacyCell<usize>,
+    init: RacyCell<bool>,
+}
+
+impl<T, const S: usize> PoolMan<T, S>
+where
+    T: Sized,
+{
+    pub const fn new(v: [T; S]) -> Self
+    where
+        T: Sized,
+    {
+        Self {
+            data: RacyCell::new(v),
+            free: RacyCell::new([0; S]),
+            head: RacyCell::new(0),
+            init: RacyCell::new(false),
+        }
+    }
+
+    #[inline]
+    pub fn init(&self) -> Result<(), Error> {
+        interrupt_free(|| {
+            if *unsafe { self.init.get_mut_unchecked() } {
+                Err(Error::AlreadyInitialized)
+            } else {
+                let free = unsafe { self.free.get_mut_unchecked() };
+                for (index, value) in free.iter_mut().enumerate() {
+                    *value = index + 1;
+                }
+                *unsafe { self.init.get_mut_unchecked() } = true;
+                Ok(())
+            }
+        })
+    }
+
+    // Safety:
+    //  dealloc can only be called by dropping Box
+    //  which can happen only if already initialized
+    //  thus it is safe to assume init == true
+    //
+    // not accissible from user code
+    #[inline]
+    fn dealloc(&self, index: usize) {
+        interrupt_free(|| unsafe {
+            *self.free.get_mut_unchecked().get_unchecked_mut(index) =
+                *self.head.get_mut_unchecked();
+            *self.head.get_mut_unchecked() = index;
+        });
+    }
+
+    #[inline]
+    pub fn alloc(&'static self) -> Result<Box<T, S>, Error> {
+        // this check does not need to be inside of critical section
+        // as initialization is monotonic, cannot be undone
+        if !unsafe { *self.init.get_mut_unchecked() } {
+            Err(Error::Uninitialized)
+        } else {
+            interrupt_free(|| unsafe {
+                let index = *self.head.get_mut_unchecked();
+                *self.head.get_mut_unchecked() =
+                    *self.free.get_mut_unchecked().get_unchecked(index);
+                if *self.head.get_mut_unchecked() > S {
+                    Err(Error::OutOfMemory)
+                } else {
+                    Ok(Box {
+                        index,
+                        allocator: self,
+                    })
+                }
+            })
+        }
+    }
+}
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index fb3a7bd..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-use core::cell::UnsafeCell;
-use core::mem;
-use core::ops::{Deref, DerefMut, Drop};
-
-/// Internal replacement for `static mut T`
-// TODO: Decide name and location.
-pub struct RacyCell<T>(UnsafeCell<T>);
-
-impl<T> RacyCell<T> {
-    /// Create a RacyCell
-    pub const fn new(value: T) -> Self {
-        RacyCell(UnsafeCell::new(value))
-    }
-
-    /// Get &mut T
-    pub unsafe fn get_mut_unchecked(&self) -> &mut T {
-        &mut *self.0.get()
-    }
-}
-
-// The type wrapped need to be Sync for RacyCell<T> to be Sync
-//unsafe impl<T> Sync for RacyCell<T> where T: Sync {}
-unsafe impl<T> Sync for RacyCell<T> {}
-
-struct Box<T: 'static + Sized, const S: usize> {
-    // data: &'static mut T,
-    index: usize,
-    allocator: &'static PoolMan<T, S>,
-}
-
-impl<T: 'static, const S: usize> Drop for Box<T, S> {
-    fn drop(&mut self) {
-        self.allocator.dealloc(self.index)
-    }
-}
-
-impl<T: 'static, const S: usize> Deref for Box<T, S> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        unsafe { &self.allocator.data.get_mut_unchecked()[self.index] }
-    }
-}
-
-impl<T: 'static, const S: usize> DerefMut for Box<T, S> {
-    // type Target = T;
-    fn deref_mut(&mut self) -> &mut T {
-        unsafe { &mut self.allocator.data.get_mut_unchecked()[self.index] }
-    }
-}
-
-struct PoolMan<T: 'static, const S: usize> {
-    data: RacyCell<[T; S]>,
-    free: RacyCell<[usize; S]>,
-    head: RacyCell<usize>,
-    init: RacyCell<bool>,
-}
-
-impl<T, const S: usize> PoolMan<T, S>
-where
-    T: Sized,
-{
-    const fn new(v: [T; S]) -> Self
-    where
-        T: Sized,
-    {
-        Self {
-            data: RacyCell::new(v),
-            free: RacyCell::new([0; S]),
-            head: RacyCell::new(0),
-            init: RacyCell::new(false),
-        }
-    }
-
-    fn init(&self) {
-        let free = unsafe { self.free.get_mut_unchecked() };
-        for (index, value) in free.iter_mut().enumerate() {
-            *value = index + 1;
-        }
-        *unsafe { self.init.get_mut_unchecked() } = true;
-
-        println!("init : free {:?}", unsafe { self.free.get_mut_unchecked() });
-    }
-
-    fn dealloc(&self, index: usize) {
-        unsafe {
-            if !*self.init.get_mut_unchecked() {
-                panic!();
-            }
-            self.free.get_mut_unchecked()[index] = *self.head.get_mut_unchecked();
-            *self.head.get_mut_unchecked() = index;
-        }
-        println!("dealloc index {}", index)
-    }
-
-    fn alloc(&'static self) -> Result<Box<T, S>, ()> {
-        unsafe {
-            if !*self.init.get_mut_unchecked() {
-                panic!();
-            }
-            let index = *self.head.get_mut_unchecked();
-            println!("index {}", self.head.get_mut_unchecked());
-            println!("head {}", self.head.get_mut_unchecked());
-            *self.head.get_mut_unchecked() = self.free.get_mut_unchecked()[index];
-            println!("new head {}", self.head.get_mut_unchecked());
-            if *self.head.get_mut_unchecked() > S {
-                Err(())
-            } else {
-                Ok(Box {
-                    index,
-                    allocator: self,
-                })
-            }
-        }
-    }
-}
-
-static P: PoolMan<u32, 2> = PoolMan::new([0; 2]);
-fn main() {
-    P.init();
-    {
-        let e = P.alloc().unwrap();
-        println!("e {}", *e);
-        mem::drop(e);
-        let mut e1 = P.alloc().unwrap();
-        println!("e1 {}", *e1);
-        *e1 = 2;
-        println!("e1 {}", *e1);
-
-        let e2 = P.alloc().unwrap();
-        println!("e2 {}", *e2);
-    }
-    let e = P.alloc().unwrap();
-    println!("e {}", *e);
-}
-- 
GitLab