diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/kernel.rs | 1 | ||||
| -rw-r--r-- | src/mem/alloc.rs | 174 | ||||
| -rw-r--r-- | src/util.rs | 5 | ||||
| -rw-r--r-- | src/util/fifo_queue.rs | 183 | 
4 files changed, 191 insertions, 172 deletions
| diff --git a/src/kernel.rs b/src/kernel.rs index a848ce5..6ec67ae 100644 --- a/src/kernel.rs +++ b/src/kernel.rs @@ -29,6 +29,7 @@ mod panic_wait;  mod print;  mod sync;  mod uart; +mod util;  use crate::console::console;  use crate::mem::alloc::alloc; diff --git a/src/mem/alloc.rs b/src/mem/alloc.rs index e665f41..1c32a38 100644 --- a/src/mem/alloc.rs +++ b/src/mem/alloc.rs @@ -6,179 +6,9 @@ use alloc::alloc::{GlobalAlloc,Layout};  use crate::sync::NullLock;  use crate::sync::interface::Mutex;  use crate::vprintln; -use core::fmt; -use core::fmt::{Debug,Formatter};  use super::types::*; - -/// # Initialize Queue -/// - Name: Symbol name -/// - Size: Number of elements -/// - Default: Default value -/// - Type: Data Type -macro_rules! init_queue { -	($name:tt,$size:tt,$default:tt,$type:ty) => { -		init_queue!{@gen [$name,$size,$default,$type,concat!("# ", stringify!($type), " Queue Allocator")]} -	}; -	(@gen [$name:tt,$size:tt,$default:tt,$type:ty,$doc:expr]) => { -		#[doc = $doc] -		#[link_section = ".data.alloc"] -		pub static $name: QueueAllocator<'static, $type, {$size+2}> = QueueAllocator::<$type, {$size+2}>{inner: NullLock::new([QueueItem{data: $default, next: None}; {$size+2}])}; -	}; -} - -#[derive(Copy,Clone)] -/// # Queue Item -/// -/// Encapsulates a data element and a pointer to -/// the next `Queue` item -pub struct QueueItem<'a, T: Sized> { -	/// # Data -	/// -	/// The encapsulated data -	data: T, -	/// # Pointer to the next item -	/// -	/// Stores either `None` or points -	/// to the next item. -	next: Option<*mut QueueItem<'a, T>>, -} - -impl<T> QueueItem<'_,T> { -	/// # Get the inner data -	/// -	/// Returns a borrow of the underlying data. -	pub fn inner(&mut self) -> &mut T { -		&mut self.data -	} -	/// # Get pointer to inner data -	pub fn ptr(&mut self) -> *mut u8 { -		self.inner() as *mut T as *mut u8 -	} -} - -/// # Sharing Thread Safety for QueueItem -unsafe impl<T> Send for QueueItem<'_,T> {} - -impl<T: Debug> Debug for QueueItem<'_,T> { -	/// # Debug formatter for `QueueItem` -	/// -	/// Output the encapsulated data -	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { -		#[cfg(feature="verbose")] -		return write!(f, "{:?} {:x} {:?}", self.data, self as *const QueueItem<'_,T> as usize, self.next); - -		#[cfg(not(feature="verbose"))] -		return write!(f, "{:?}", self.data); -	} -} - -/// # Queue Allocator -/// -/// Structure to store a pool of allocated data structures. -pub struct QueueAllocator<'a, T: Sized, const COUNT: usize> { -	/// # Synchronized Pool of items -	/// -	/// Stores synchronization wrapper around the data pool -	pub inner: NullLock<[QueueItem<'a, T>;COUNT]>, -} - -/// # Sharing Thread Safety for QueueAllocator -unsafe impl<T,const COUNT: usize> Send for QueueAllocator<'_,T,COUNT> {} - -impl<'a, T: Sized,const COUNT: usize> QueueAllocator<'a, T, COUNT> { -	/// # Initialization of Fixed-Size Pool -	///  -	/// Establishes the header and footer of the queue -	/// as the first and second elements respectively. -	/// All of the internal elements point to the next -	/// one and the final element points to `None` -	pub fn init(&self) { -		vprintln!("QA: Initializing Queue Allocator!"); -		self.inner.lock(|queue| { -			vprintln!("QA: Clearing internal references..."); -			for idx in 2..COUNT { -				if idx != COUNT-1 { -					queue[idx].next = Some(&mut queue[idx+1] as *mut QueueItem<'a, T>); -				} else { -					queue[idx].next = None; -				} -			} -			vprintln!("QA: Initializing head and tail..."); -			queue[0].next = Some(&mut queue[2] as *mut QueueItem<'a, T>); -			queue[1].next = Some(&mut queue[COUNT-1] as *mut QueueItem<'a, T>); -		}); -		vprintln!("QA: Initialized Queue Allocator!"); -	} - -	/// # Allocate Data -	/// -	/// If there is a data chunk available, -	/// return it, otherwise return `None` -	#[allow(dead_code)] -	pub fn alloc(&self) -> Option<&mut QueueItem<'a,T>> { -		vprintln!("QA: Allocating chunk!"); -		return self.inner.lock(|pool| { -			if let Some(entry) = pool[0].next { -				vprintln!("QA: Found chunk!"); -				pool[0].next = unsafe { (*entry).next }; -				unsafe { -					(*entry).next = None; -				} -				match pool[0].next { -					None => { -						pool[1].next = None -					} -					_ => {} -				} -				vprintln!("QA: \x1b[92mAllocated {:x}\x1b[0m", unsafe{(*entry).ptr() as usize}); -				return Some(unsafe{&mut *entry as &mut QueueItem<'a,T>}); -			} else { -				vprintln!("QA: No chunks available!"); -				return None; -			} -		}); -	} - -	/// # Free -	/// -	/// Add the item to the end of the queue. -	/// If there were no items, set it as the head. -	#[allow(dead_code)] -	pub fn free(&self, freed_item: &mut QueueItem<'a,T>) { -		vprintln!("QA: Deallocating chunk!"); -		self.inner.lock(|pool| { -			freed_item.next = None; -			match pool[1].next { -				None => { -					pool[0].next = Some(freed_item as *mut QueueItem<'a,T>); -				} -				Some(entry) => { -					unsafe { -						(*entry).next = Some(freed_item as *mut QueueItem<'a,T>); -					} -				} -			} -			pool[1].next = Some(freed_item as *mut QueueItem<'a,T>); -			vprintln!("QA: \x1b[91mDeallocated {:x}\x1b[0m", freed_item.ptr() as usize); -		}); -	} -} - -impl<T: Debug,const COUNT: usize> Debug for QueueAllocator<'_,T,COUNT> { -	/// # Debug Formatted Output -	/// -	/// Output each data point in the array with -	/// its debug formatter. -	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { -		self.inner.lock(|queue| { -			#[cfg(feature="verbose")] -			return write!(f, "{:?}", queue); - -			#[cfg(not(feature="verbose"))] -			return write!(f, "{:?}", queue); -		}) -	} -} +use crate::util::{QueueAllocator,QueueItem}; +use crate::init_queue;  /// # Grand Allocator  /// diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..34ae1f2 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,5 @@ +//! # Utility crate +//! +//! Provides Queue structure +mod fifo_queue; +pub use fifo_queue::*; diff --git a/src/util/fifo_queue.rs b/src/util/fifo_queue.rs new file mode 100644 index 0000000..7ec939b --- /dev/null +++ b/src/util/fifo_queue.rs @@ -0,0 +1,183 @@ +use crate::sync::NullLock; +use crate::sync::interface::Mutex; +use crate::vprintln; +use core::fmt; +use core::fmt::{Debug,Formatter}; + +/// # Initialize Queue +/// - Name: Symbol name +/// - Size: Number of elements +/// - Default: Default value +/// - Type: Data Type +#[macro_export] +macro_rules! init_queue { +	($name:tt,$size:tt,$default:tt,$type:ty) => { +		init_queue!{@gen [$name,$size,$default,$type,concat!("# ", stringify!($type), " Queue Allocator")]} +	}; +	(@gen [$name:tt,$size:tt,$default:tt,$type:ty,$doc:expr]) => { +		#[doc = $doc] +		#[link_section = ".data.alloc"] +		pub static $name: QueueAllocator<'static, $type, {$size+2}> = QueueAllocator::<$type, {$size+2}>{inner: NullLock::new([QueueItem::new($default); {$size+2}])}; +	}; +} + +#[derive(Copy,Clone)] +/// # Queue Item +/// +/// Encapsulates a data element and a pointer to +/// the next `Queue` item +pub struct QueueItem<'a, T: Sized> { +	/// # Data +	/// +	/// The encapsulated data +	data: T, +	/// # Pointer to the next item +	/// +	/// Stores either `None` or points +	/// to the next item. +	next: Option<*mut QueueItem<'a, T>>, +} + +impl<T> QueueItem<'_,T> { +	/// # Constructor +	pub const fn new(data: T) -> Self { +		Self { +			data: data, +			next: None, +		} +	} +	/// # Get the inner data +	/// +	/// Returns a borrow of the underlying data. +	pub fn inner(&mut self) -> &mut T { +		&mut self.data +	} +	/// # Get pointer to inner data +	pub fn ptr(&mut self) -> *mut u8 { +		self.inner() as *mut T as *mut u8 +	} +} + +/// # Sharing Thread Safety for QueueItem +unsafe impl<T> Send for QueueItem<'_,T> {} + +impl<T: Debug> Debug for QueueItem<'_,T> { +	/// # Debug formatter for `QueueItem` +	/// +	/// Output the encapsulated data +	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +		#[cfg(feature="verbose")] +		return write!(f, "{:?} {:x} {:?}", self.data, self as *const QueueItem<'_,T> as usize, self.next); + +		#[cfg(not(feature="verbose"))] +		return write!(f, "{:?}", self.data); +	} +} + +/// # Queue Allocator +/// +/// Structure to store a pool of allocated data structures. +pub struct QueueAllocator<'a, T: Sized, const COUNT: usize> { +	/// # Synchronized Pool of items +	/// +	/// Stores synchronization wrapper around the data pool +	pub inner: NullLock<[QueueItem<'a, T>;COUNT]>, +} + +/// # Sharing Thread Safety for QueueAllocator +unsafe impl<T,const COUNT: usize> Send for QueueAllocator<'_,T,COUNT> {} + +impl<'a, T: Sized,const COUNT: usize> QueueAllocator<'a, T, COUNT> { +	/// # Initialization of Fixed-Size Pool +	///  +	/// Establishes the header and footer of the queue +	/// as the first and second elements respectively. +	/// All of the internal elements point to the next +	/// one and the final element points to `None` +	pub fn init(&self) { +		vprintln!("QA: Initializing Queue Allocator!"); +		self.inner.lock(|queue| { +			vprintln!("QA: Clearing internal references..."); +			for idx in 2..COUNT { +				if idx != COUNT-1 { +					queue[idx].next = Some(&mut queue[idx+1] as *mut QueueItem<'a, T>); +				} else { +					queue[idx].next = None; +				} +			} +			vprintln!("QA: Initializing head and tail..."); +			queue[0].next = Some(&mut queue[2] as *mut QueueItem<'a, T>); +			queue[1].next = Some(&mut queue[COUNT-1] as *mut QueueItem<'a, T>); +		}); +		vprintln!("QA: Initialized Queue Allocator!"); +	} + +	/// # Allocate Data +	/// +	/// If there is a data chunk available, +	/// return it, otherwise return `None` +	#[allow(dead_code)] +	pub fn alloc(&self) -> Option<&mut QueueItem<'a,T>> { +		vprintln!("QA: Allocating chunk!"); +		return self.inner.lock(|pool| { +			if let Some(entry) = pool[0].next { +				vprintln!("QA: Found chunk!"); +				pool[0].next = unsafe { (*entry).next }; +				unsafe { +					(*entry).next = None; +				} +				match pool[0].next { +					None => { +						pool[1].next = None +					} +					_ => {} +				} +				vprintln!("QA: \x1b[92mAllocated {:x}\x1b[0m", unsafe{(*entry).ptr() as usize}); +				return Some(unsafe{&mut *entry as &mut QueueItem<'a,T>}); +			} else { +				vprintln!("QA: No chunks available!"); +				return None; +			} +		}); +	} + +	/// # Free +	/// +	/// Add the item to the end of the queue. +	/// If there were no items, set it as the head. +	#[allow(dead_code)] +	pub fn free(&self, freed_item: &mut QueueItem<'a,T>) { +		vprintln!("QA: Deallocating chunk!"); +		self.inner.lock(|pool| { +			freed_item.next = None; +			match pool[1].next { +				None => { +					pool[0].next = Some(freed_item as *mut QueueItem<'a,T>); +				} +				Some(entry) => { +					unsafe { +						(*entry).next = Some(freed_item as *mut QueueItem<'a,T>); +					} +				} +			} +			pool[1].next = Some(freed_item as *mut QueueItem<'a,T>); +			vprintln!("QA: \x1b[91mDeallocated {:x}\x1b[0m", freed_item.ptr() as usize); +		}); +	} +} + +impl<T: Debug,const COUNT: usize> Debug for QueueAllocator<'_,T,COUNT> { +	/// # Debug Formatted Output +	/// +	/// Output each data point in the array with +	/// its debug formatter. +	fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +		self.inner.lock(|queue| { +			#[cfg(feature="verbose")] +			return write!(f, "{:?}", queue); + +			#[cfg(not(feature="verbose"))] +			return write!(f, "{:?}", queue); +		}) +	} +} | 
