Repository navigation
Feature_Addition
Zikithezikit edited this page Mar 2, 2026
·
2 revisions
This guide provides a comprehensive walkthrough for adding new features to the rust-kernel project. It covers the entire development process from planning to testing.
Before starting, consider:
- What problem does this feature solve?
- Is it aligned with project goals?
- What are the performance implications?
- Does it introduce security risks?
- How complex is the implementation?
Look for similar implementations:
# Search for related code
grep -r "similar_feature" src/
# Check if similar functionality exists
rg "pattern" src/Plan your public interfaces:
- Function signatures - What parameters and return types?
- Error handling - What can go wrong?
- Thread safety - Does it need synchronization?
- Resource management - How are resources cleaned up?
Decide where to place your code:
- New module - If it's a standalone feature
- Existing module - If it's an extension
- Architecture-specific - If it's CPU-dependent
- Driver - If it's hardware-related
# Create module directory
mkdir -p src/implementation/kernel/new_feature
# Create main module file
touch src/implementation/kernel/new_feature/mod.rs
# Create implementation files
touch src/implementation/kernel/new_feature/lib.rsAdd to existing module structure:
// src/implementation/kernel/new_feature/mod.rs
pub mod lib;
pub mod utils;// src/implementation/kernel/new_feature/lib.rs
//! New feature implementation
use crate::error::{KernelError, KernelResult};
/// Main feature struct
pub struct NewFeature {
// Internal state
}
impl NewFeature {
/// Creates a new instance
pub fn new() -> Self {
Self {
// Initialize state
}
}
/// Main feature operation
pub fn perform_operation(&self, input: Input) -> KernelResult<Output> {
// Implementation
Ok(output)
}
}
/// Error type for this feature
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NewFeatureError {
InvalidInput,
OperationFailed,
ResourceUnavailable,
}
impl From<NewFeatureError> for KernelError {
fn from(err: NewFeatureError) -> Self {
match err {
NewFeatureError::InvalidInput => KernelError::InvalidArgument,
NewFeatureError::OperationFailed => KernelError::Unknown,
NewFeatureError::ResourceUnavailable => KernelError::OutOfMemory,
}
}
}use crate::error::KernelError;
impl NewFeature {
pub fn perform_operation(&self, input: Input) -> KernelResult<Output> {
if input.is_invalid() {
return Err(KernelError::InvalidArgument);
}
// Operation that might fail
let result = some_operation()?;
Ok(result)
}
}If needed, create custom error types that map to KernelError:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NewFeatureError {
InvalidInput,
OperationFailed,
}
impl From<NewFeatureError> for KernelError {
fn from(err: NewFeatureError) -> Self {
match err {
NewFeatureError::InvalidInput => KernelError::InvalidArgument,
NewFeatureError::OperationFailed => KernelError::Unknown,
}
}
}use spin::Mutex;
static FEATURE_INSTANCE: Mutex<Option<NewFeature>> = Mutex::new(None);
pub fn get_instance() -> &'static NewFeature {
let mut instance = FEATURE_INSTANCE.lock();
if instance.is_none() {
*instance = Some(NewFeature::new());
}
instance.as_ref().unwrap()
}For one-time initialization:
use spin::Once;
static INIT: Once<KernelResult<NewFeature>> = Once::new();
pub fn get_instance() -> KernelResult<&'static NewFeature> {
INIT.call_once(|| {
Ok(NewFeature::new())
})
}// src/implementation/kernel/new_feature/init.rs
use crate::error::KernelResult;
pub fn init() -> KernelResult<()> {
// Initialize feature
let feature = NewFeature::new();
// Store in global state if needed
let mut kernel = crate::kernel::kernel();
kernel.set_new_feature(feature);
Ok(())
}Add to main initialization:
// src/implementation/kernel/main.rs
mod new_feature;
// In init_submodules()
halt_on_err(new_feature::init(), "New feature init failed");// src/implementation/kernel/new_feature/tests.rs
use crate::error::KernelResult;
use super::NewFeature;
#[test_case]
fn test_new_feature_creation() -> KernelResult<()> {
let feature = NewFeature::new();
assert!(feature.is_valid());
Ok(())
}
#[test_case]
fn test_feature_operation() -> KernelResult<()> {
let feature = NewFeature::new();
let input = Input::valid();
let result = feature.perform_operation(input)?;
assert_eq!(result, expected_output);
Ok(())
}
#[test_case]
fn test_error_handling() -> KernelResult<()> {
let feature = NewFeature::new();
let input = Input::invalid();
match feature.perform_operation(input) {
Err(KernelError::InvalidArgument) -> Ok(()),
_ -> Err(KernelError::Unknown),
}
}// src/implementation/kernel/tests/mod.rs
mod new_feature;
pub fn run_tests() -> KernelResult<()> {
new_feature::run_tests()?;
Ok(())
}Test boundary conditions:
#[test_case]
fn test_edge_cases() -> KernelResult<()> {
let feature = NewFeature::new();
// Test with minimum valid input
let min_input = Input::min();
feature.perform_operation(min_input)?;
// Test with maximum valid input
let max_input = Input::max();
feature.perform_operation(max_input)?;
// Test with empty input
let empty_input = Input::empty();
feature.perform_operation(empty_input)?;
Ok(())
}//! New Feature Module
//!
//! This module provides functionality for [feature description].
//! It is used for [use cases] and integrates with [related systems].
//!
//! ## Features
//! - [Feature 1 description]
//! - [Feature 2 description]
//! - [Feature 3 description]
/// Main feature struct
///
/// This struct provides the core functionality for the new feature.
/// It manages [what it manages] and provides [what it provides].
///
/// # Examples
///
/// ```
/// let feature = NewFeature::new();
/// let result = feature.perform_operation(input);
/// ```
pub struct NewFeature {
// Fields
}
impl NewFeature {
/// Creates a new instance
///
/// # Arguments
///
/// * `param` - [parameter description]
///
/// # Returns
///
/// A new `NewFeature` instance
///
/// # Errors
///
/// Returns `KernelError::InvalidState` if [condition]
pub fn new() -> Self {
Self {
// Implementation
}
}
/// Performs the main operation
///
/// This is the primary function that users will call.
/// It [what it does] and returns [what it returns].
///
/// # Arguments
///
/// * `input` - [input description]
///
/// # Returns
///
/// The result of the operation
///
/// # Errors
///
/// Returns `KernelError::InvalidArgument` if [condition]
/// Returns `KernelError::OperationFailed` if [condition]
pub fn perform_operation(&self, input: Input) -> KernelResult<Output> {
// Implementation
Ok(output)
}
}// Good: Clear explanation of complex logic
// SAFETY: We can dereference this pointer because it was allocated by our allocator
// and we have exclusive access to it during this operation.
let ptr = unsafe { &mut *allocated_ptr };-
Build passes -
make buildshould succeed -
Tests pass -
make run-testsshould pass - No warnings - Fix all compiler warnings
- Documentation complete - All public APIs documented
- Error handling complete - All error cases handled
- Thread safety verified - All shared state protected
- Unsafe blocks - Are they necessary and documented?
- Pointer usage - Are raw pointers properly managed?
- Lifetime issues - Are references valid for their entire use?
- Missing error cases - Are all failure modes handled?
-
Error propagation - Are errors properly propagated with
?? - Error context - Do errors provide useful debugging information?
- Add syscall number to
syscall/numbers.rs - Implement handler in
syscall/handler.rs - Add to syscall dispatch table
- Write tests
// syscall/numbers.rs
#[repr(u32)]
pub enum SyscallNumber {
// ... existing calls
MySyscall = 60,
}
// syscall/handler.rs
pub fn handle_syscall(num: u32, args: &[usize; 6]) -> SyscallResult {
match num {
// ... existing handlers
SyscallNumber::MySyscall as u32 => sys_my_syscall(args),
_ -> Err(KernelError::InvalidSyscall),
}
}- Create module in
vfs/directory - Implement
Inodetrait - Add to VFS mount system
- Write tests
// vfs/myfs.rs
pub struct MyFsInode {
// Internal state
}
impl Inode for MyFsInode {
fn read(&self, offset: u64, buffer: &mut [u8]) -> KernelResult<usize> {
// Implementation
Ok(bytes_read)
}
// Other trait methods
}- Create driver in
drivers/directory - Implement initialization in
drivers/init.rs - Add to driver initialization sequence
- Write tests
// drivers/my_device.rs
pub struct MyDevice {
base_addr: usize,
}
impl MyDevice {
pub fn new(base_addr: usize) -> Self {
Self { base_addr }
}
pub fn read(&self, reg: u8) -> u8 {
// Memory-mapped I/O
unsafe { &*(self.base_addr as *const u8).add(reg as usize) }
}
}- Create new scheduler in
task/scheduler/ - Implement scheduling algorithm
- Add to scheduler selection
- Write tests
// task/scheduler/priority.rs
pub struct PriorityScheduler {
// Priority queue implementation
}
impl Scheduler for PriorityScheduler {
fn schedule_next(&mut self) -> Option<TaskId> {
// Priority-based scheduling
self.queue.pop()
}
// Other scheduler methods
}