    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111

    //!Implementation of [`PidAllocator`]
    use crate::config::{KERNEL_STACK_SIZE, PAGE_SIZE, TRAMPOLINE};
    use crate::mm::{MapPermission, VirtAddr, KERNEL_SPACE};
    use crate::sync::UPSafeCell;
    use alloc::vec::Vec;
    use lazy_static::*;
    ///Pid Allocator struct
    pub struct PidAllocator {
        current: usize,
        recycled: Vec<usize>,
    }

    impl PidAllocator {
        ///Create an empty `PidAllocator`
        pub fn new() -> Self {
            PidAllocator {
                current: 0,
                recycled: Vec::new(),
            }
        }
        ///Allocate a pid
        pub fn alloc(&mut self) -> PidHandle {
            if let Some(pid) = self.recycled.pop() {
                PidHandle(pid)
            } else {
                self.current += 1;
                PidHandle(self.current - 1)
            }
        }
        ///Recycle a pid
        pub fn dealloc(&mut self, pid: usize) {
            assert!(pid < self.current);
            assert!(
                !self.recycled.iter().any(|ppid| *ppid == pid),
                "pid {} has been deallocated!",
                pid
            );
            self.recycled.push(pid);
        }
    }

    lazy_static! {
        pub static ref PID_ALLOCATOR: UPSafeCell<PidAllocator> =
            unsafe { UPSafeCell::new(PidAllocator::new()) };
    }
    ///Bind pid lifetime to `PidHandle`
    pub struct PidHandle(pub usize);

    impl Drop for PidHandle {
        fn drop(&mut self) {
            //println!("drop pid {}", self.0);
            PID_ALLOCATOR.exclusive_access().dealloc(self.0);
        }
    }
    ///Allocate a pid from PID_ALLOCATOR
    pub fn pid_alloc() -> PidHandle {
        PID_ALLOCATOR.exclusive_access().alloc()
    }

    /// Return (bottom, top) of a kernel stack in kernel space.
    pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
        let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
        let bottom = top - KERNEL_STACK_SIZE;
        (bottom, top)
    }
    ///Kernelstack for app
    pub struct KernelStack {
        pid: usize,
    }

    impl KernelStack {
        ///Create a kernelstack from pid
        pub fn new(pid_handle: &PidHandle) -> Self {
            let pid = pid_handle.0;
            let (kernel_stack_bottom, kernel_stack_top) = kernel_stack_position(pid);
            KERNEL_SPACE.exclusive_access().insert_framed_area(
                kernel_stack_bottom.into(),
                kernel_stack_top.into(),
                MapPermission::R | MapPermission::W,
            );
            KernelStack { pid: pid_handle.0 }
        }
        #[allow(unused)]
        ///Push a value on top of kernelstack
        pub fn push_on_top<T>(&self, value: T) -> *mut T
        where
            T: Sized,
        {
            let kernel_stack_top = self.get_top();
            let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
            unsafe {
                *ptr_mut = value;
            }
            ptr_mut
        }
        ///Get the value on the top of kernelstack
        pub fn get_top(&self) -> usize {
            let (_, kernel_stack_top) = kernel_stack_position(self.pid);
            kernel_stack_top
        }
    }

    impl Drop for KernelStack {
        fn drop(&mut self) {
            let (kernel_stack_bottom, _) = kernel_stack_position(self.pid);
            let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into();
            KERNEL_SPACE
                .exclusive_access()
                .remove_area_with_start_vpn(kernel_stack_bottom_va.into());
        }
    }