good_os_framework/task/
process.rs1use alloc::collections::VecDeque;
2use alloc::string::String;
3use alloc::sync::{Arc, Weak};
4use core::fmt::Debug;
5use core::sync::atomic::{AtomicU64, Ordering};
6use object::{File, Object, ObjectSegment};
7use spin::{Lazy, RwLock};
8use x86_64::instructions::interrupts;
9use x86_64::structures::paging::mapper::CleanUp;
10use x86_64::structures::paging::PageTableFlags;
11use x86_64::VirtAddr;
12
13use super::signal::SignalManager;
14use super::thread::{SharedThread, Thread};
15use crate::memory::MemoryManager;
16use crate::memory::{create_page_table_from_kernel, HeapType, ProcessHeap};
17use crate::memory::{GeneralPageTable, FRAME_ALLOCATOR};
18
19pub(super) type SharedProcess = Arc<RwLock<Process>>;
20pub(super) type WeakSharedProcess = Weak<RwLock<Process>>;
21
22static PROCESSES: RwLock<VecDeque<SharedProcess>> = RwLock::new(VecDeque::new());
23pub static KERNEL_PROCESS: Lazy<SharedProcess> = Lazy::new(|| Process::new_kernel_process());
24
25const KERNEL_PROCESS_NAME: &str = "kernel";
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
28pub struct ProcessId(pub u64);
29
30impl ProcessId {
31 fn new() -> Self {
32 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
33 ProcessId(NEXT_ID.fetch_add(1, Ordering::Relaxed))
34 }
35}
36
37#[allow(dead_code)]
38pub struct Process {
39 pub id: ProcessId,
40 name: String,
41 pub page_table: GeneralPageTable,
42 pub threads: VecDeque<SharedThread>,
43 pub heap: ProcessHeap,
44 pub signal_manager: SignalManager,
45 pub father: Option<WeakSharedProcess>,
46}
47
48impl Process {
49 pub fn new(name: &str, heap_type: HeapType) -> Self {
52 let page_table = create_page_table_from_kernel();
53 let pid = ProcessId::new();
54 let process = Process {
55 id: pid,
56 name: String::from(name),
57 page_table,
58 threads: Default::default(),
59 heap: ProcessHeap::new(heap_type),
60 signal_manager: SignalManager::new(64),
61 father: None,
62 };
63
64 process
65 }
66
67 pub fn new_kernel_process() -> SharedProcess {
70 let process = Arc::new(RwLock::new(Self::new(
71 KERNEL_PROCESS_NAME,
72 HeapType::Kernel,
73 )));
74 process.read().heap.init(Arc::downgrade(&process));
75 process
76 }
77
78 pub fn new_user_process(name: &str, elf_data: &'static [u8]) -> SharedProcess {
80 let binary = ProcessBinary::parse(elf_data);
81 let process = Arc::new(RwLock::new(Self::new(name, HeapType::User)));
82 process.read().heap.init(Arc::downgrade(&process));
83 ProcessBinary::map_segments(&binary, &mut process.write().page_table);
84 Thread::new_user_thread(Arc::downgrade(&process), binary.entry() as usize);
86 PROCESSES.write().push_back(process.clone());
87 process
88 }
89
90 pub fn exit_process(&self) {
91 let mut processes = PROCESSES.write();
92 if let Some(index) = processes
93 .iter()
94 .position(|process| process.read().id == self.id)
95 {
96 processes.remove(index);
97 }
98 }
99}
100
101impl Drop for Process {
102 fn drop(&mut self) {
104 unsafe { self.page_table.clean_up(&mut *FRAME_ALLOCATOR.lock()) };
105 }
106}
107
108struct ProcessBinary;
109
110impl ProcessBinary {
111 fn parse(bin: &'static [u8]) -> File<'static> {
112 File::parse(bin).expect("Failed to parse ELF binary!")
113 }
114
115 fn map_segments(elf_file: &File, page_table: &mut GeneralPageTable) {
116 interrupts::without_interrupts(|| {
117 for segment in elf_file.segments() {
118 let segment_address = VirtAddr::new(segment.address() as u64);
119
120 let flags = PageTableFlags::PRESENT
121 | PageTableFlags::WRITABLE
122 | PageTableFlags::USER_ACCESSIBLE;
123
124 <MemoryManager>::alloc_range(segment_address, segment.size(), flags, page_table)
125 .expect("Failed to allocate memory for ELF segment!");
126
127 if let Ok(data) = segment.data() {
128 page_table.write(data, segment_address).unwrap();
129 }
130 }
131 });
132 }
133}