Nothing to see here, move along
1use crate::mem::phys::BitmapFrameAllocator;
2use crate::proc::address_space;
3use crate::proc::{ProcessState, PROCESSES};
4
5crate::kernel_test!(
6 fn thread_create_shares_pml4() {
7 let mut allocator = BitmapFrameAllocator;
8 let mut ptable = PROCESSES.lock();
9
10 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
11 let parent_pid = parent.pid();
12 let parent_pml4 = ptable[parent_pid].pml4_phys;
13
14 let child = ptable
15 .allocate_thread(parent_pid, &mut allocator)
16 .expect("alloc thread");
17 let child_pid = child.pid();
18
19 assert!(
20 ptable[child_pid].pml4_phys == parent_pml4,
21 "thread must share parent PML4"
22 );
23
24 let refcount = address_space::pml4_ref_get(parent_pml4.raw());
25 assert!(refcount == 2, "PML4 refcount must be 2, got {}", refcount);
26
27 ptable.destroy(child_pid, &mut allocator);
28 ptable.destroy(parent_pid, &mut allocator);
29 }
30);
31
32crate::kernel_test!(
33 fn thread_create_independent_context() {
34 let mut allocator = BitmapFrameAllocator;
35 let mut ptable = PROCESSES.lock();
36
37 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
38 let parent_pid = parent.pid();
39
40 let child = ptable
41 .allocate_thread(parent_pid, &mut allocator)
42 .expect("alloc thread");
43 let child_pid = child.pid();
44
45 assert!(
46 ptable[child_pid].kernel_stack_top != ptable[parent_pid].kernel_stack_top,
47 "thread must have its own kernel stack"
48 );
49
50 assert!(
51 ptable[child_pid].state() == ProcessState::Created,
52 "thread initial state must be Created"
53 );
54
55 assert!(
56 child_pid != parent_pid,
57 "thread must have a different PID"
58 );
59
60 ptable.destroy(child_pid, &mut allocator);
61 ptable.destroy(parent_pid, &mut allocator);
62 }
63);
64
65crate::kernel_test!(
66 fn thread_teardown_preserves_address_space() {
67 let mut allocator = BitmapFrameAllocator;
68 let mut ptable = PROCESSES.lock();
69
70 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
71 let parent_pid = parent.pid();
72 let pml4 = ptable[parent_pid].pml4_phys;
73
74 let child = ptable
75 .allocate_thread(parent_pid, &mut allocator)
76 .expect("alloc thread");
77 let child_pid = child.pid();
78
79 assert!(address_space::pml4_ref_get(pml4.raw()) == 2, "refcount should be 2");
80
81 ptable.destroy(child_pid, &mut allocator);
82
83 assert!(
84 address_space::pml4_ref_get(pml4.raw()) == 1,
85 "refcount should drop to 1 after thread destroy"
86 );
87
88 assert!(
89 ptable.get(parent_pid).is_some(),
90 "parent must still exist"
91 );
92 assert!(
93 ptable[parent_pid].pml4_phys == pml4,
94 "parent PML4 must be unchanged"
95 );
96
97 ptable.destroy(parent_pid, &mut allocator);
98 }
99);
100
101crate::kernel_test!(
102 fn last_thread_teardown_frees_pml4() {
103 let mut allocator = BitmapFrameAllocator;
104 let mut ptable = PROCESSES.lock();
105
106 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
107 let parent_pid = parent.pid();
108 let pml4 = ptable[parent_pid].pml4_phys;
109
110 let child = ptable
111 .allocate_thread(parent_pid, &mut allocator)
112 .expect("alloc thread");
113 let child_pid = child.pid();
114
115 ptable.destroy(parent_pid, &mut allocator);
116
117 assert!(
118 address_space::pml4_ref_get(pml4.raw()) == 1,
119 "refcount should be 1 after parent destroy"
120 );
121
122 ptable.destroy(child_pid, &mut allocator);
123
124 assert!(
125 address_space::pml4_ref_get(pml4.raw()) == 0,
126 "refcount should be 0 after last thread destroy"
127 );
128 }
129);
130
131crate::kernel_test!(
132 fn fs_base_default_zero() {
133 let mut allocator = BitmapFrameAllocator;
134 let mut ptable = PROCESSES.lock();
135
136 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
137 let parent_pid = parent.pid();
138
139 let child = ptable
140 .allocate_thread(parent_pid, &mut allocator)
141 .expect("alloc thread");
142 let child_pid = child.pid();
143
144 assert!(
145 ptable[child_pid].fs_base == 0,
146 "thread fs_base must default to 0"
147 );
148 assert!(
149 ptable[parent_pid].fs_base == 0,
150 "parent fs_base must default to 0"
151 );
152
153 ptable.destroy(child_pid, &mut allocator);
154 ptable.destroy(parent_pid, &mut allocator);
155 }
156);
157
158crate::kernel_test!(
159 fn fs_base_stored_per_process() {
160 let mut allocator = BitmapFrameAllocator;
161 let mut ptable = PROCESSES.lock();
162
163 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
164 let parent_pid = parent.pid();
165
166 let child = ptable
167 .allocate_thread(parent_pid, &mut allocator)
168 .expect("alloc thread");
169 let child_pid = child.pid();
170
171 ptable[parent_pid].fs_base = 0x7FFF_0000_1000;
172 ptable[child_pid].fs_base = 0x7FFF_0000_2000;
173
174 assert!(
175 ptable[parent_pid].fs_base == 0x7FFF_0000_1000,
176 "parent fs_base mismatch"
177 );
178 assert!(
179 ptable[child_pid].fs_base == 0x7FFF_0000_2000,
180 "child fs_base mismatch"
181 );
182
183 ptable.destroy(child_pid, &mut allocator);
184 ptable.destroy(parent_pid, &mut allocator);
185 }
186);
187
188crate::kernel_test!(
189 fn thread_inherits_parent_cnode() {
190 let mut allocator = BitmapFrameAllocator;
191 let mut ptable = PROCESSES.lock();
192
193 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
194 let parent_pid = parent.pid();
195
196 let child = ptable
197 .allocate_thread(parent_pid, &mut allocator)
198 .expect("alloc thread");
199 let child_pid = child.pid();
200
201 assert!(
202 ptable[child_pid].root_cnode() == ptable[parent_pid].root_cnode(),
203 "thread must inherit parent's root cnode"
204 );
205
206 ptable.destroy(child_pid, &mut allocator);
207 ptable.destroy(parent_pid, &mut allocator);
208 }
209);
210
211crate::kernel_test!(
212 fn thread_stack_canary_valid() {
213 let mut allocator = BitmapFrameAllocator;
214 let mut ptable = PROCESSES.lock();
215
216 let parent = ptable.allocate(&mut allocator).expect("alloc parent");
217 let parent_pid = parent.pid();
218
219 let child = ptable
220 .allocate_thread(parent_pid, &mut allocator)
221 .expect("alloc thread");
222 let child_pid = child.pid();
223
224 ptable.verify_stack_canary(child_pid);
225
226 assert!(
227 ptable.stack_high_water_mark(child_pid) == 0,
228 "fresh thread stack should have zero high water mark"
229 );
230
231 ptable.destroy(child_pid, &mut allocator);
232 ptable.destroy(parent_pid, &mut allocator);
233 }
234);