@@ -169,6 +169,47 @@ pub fn kernel_waitid(
169169 Ok ( 0 )
170170}
171171
172+ /// 检查子进程是否可以被当前线程等待
173+ ///
174+ /// 根据 Linux wait 语义:
175+ /// - 默认情况下,线程组中的任何线程都可以等待同一线程组中任何线程 fork 的子进程
176+ /// - 如果指定了 __WNOTHREAD,则只能等待当前线程自己创建的子进程
177+ ///
178+ /// # 参数
179+ /// - `child_pcb`: 要检查的子进程
180+ /// - `options`: 等待选项
181+ ///
182+ /// # 返回值
183+ /// 返回 true 如果当前线程可以等待该子进程
184+ fn is_eligible_child ( child_pcb : & Arc < ProcessControlBlock > , options : WaitOption ) -> bool {
185+ let current = ProcessManager :: current_pcb ( ) ;
186+ let current_tgid = current. tgid ;
187+
188+ // 获取子进程的 real_parent
189+ let child_parent = match child_pcb. real_parent_pcb ( ) {
190+ Some ( p) => p,
191+ None => return false ,
192+ } ;
193+
194+ if options. contains ( WaitOption :: WNOTHREAD ) {
195+ // 带 __WNOTHREAD:只能等待当前线程自己创建的子进程
196+ // 检查子进程的 real_parent 是否就是当前线程
197+ Arc :: ptr_eq ( & child_parent, & current)
198+ } else {
199+ // 默认情况:线程组中的任何线程都可以等待同一线程组中任何线程创建的子进程
200+ // 检查子进程的 real_parent 的 tgid 是否与当前线程的 tgid 相同
201+ child_parent. tgid == current_tgid
202+ }
203+ }
204+
205+ /// 获取当前线程组 leader 的 PCB
206+ ///
207+ /// 用于在 wait 时遍历整个线程组的 children
208+ fn get_thread_group_leader ( pcb : & Arc < ProcessControlBlock > ) -> Arc < ProcessControlBlock > {
209+ let ti = pcb. thread . read_irqsave ( ) ;
210+ ti. group_leader ( ) . unwrap_or_else ( || pcb. clone ( ) )
211+ }
212+
172213/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/exit.c#1573
173214fn do_wait ( kwo : & mut KernelWaitOption ) -> Result < usize , SystemError > {
174215 let mut retval: Result < usize , SystemError > = Ok ( 0 ) ;
@@ -207,11 +248,13 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
207248
208249 let child_pcb = pid. pid_task ( PidType :: PID ) . ok_or ( SystemError :: ECHILD ) ?;
209250
210- let parent = ProcessManager :: current_pcb ( ) ;
251+ let current = ProcessManager :: current_pcb ( ) ;
211252
212- // 检查是否是当前进程的子进程,否则返回ECHILD
213- let is_child = parent. children . read ( ) . contains ( & child_pcb. raw_pid ( ) ) ;
214- if !is_child {
253+ // 检查子进程是否可以被当前线程等待
254+ // 根据 Linux 语义:
255+ // - 默认情况下,线程组中的任何线程都可以等待同一线程组中任何线程 fork 的子进程
256+ // - 如果指定了 __WNOTHREAD,则只能等待当前线程自己创建的子进程
257+ if !is_eligible_child ( & child_pcb, kwo. options ) {
215258 return Err ( SystemError :: ECHILD ) ;
216259 }
217260
@@ -220,6 +263,13 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
220263 return Err ( SystemError :: ECHILD ) ;
221264 }
222265
266+ // 获取用于等待的 PCB(线程组 leader 或当前线程,取决于 WNOTHREAD)
267+ let parent = if kwo. options . contains ( WaitOption :: WNOTHREAD ) {
268+ current. clone ( )
269+ } else {
270+ get_thread_group_leader ( & current)
271+ } ;
272+
223273 // 等待指定子进程:睡眠在父进程自己的 wait_queue 上
224274 // 子进程退出时会发送信号并唤醒父进程的 wait_queue
225275 loop {
@@ -265,8 +315,16 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
265315 }
266316 }
267317 PidConverter :: All => {
268- // 等待任意子进程:使用父进程的 wait_queue,避免丢唤醒
269- let parent = ProcessManager :: current_pcb ( ) ;
318+ // 等待任意子进程:使用线程组 leader 的 wait_queue 和 children 列表
319+ // 这样线程组中的任何线程都可以等待同一线程组中任何线程 fork 的子进程
320+ let current = ProcessManager :: current_pcb ( ) ;
321+ let parent = if kwo. options . contains ( WaitOption :: WNOTHREAD ) {
322+ // 带 __WNOTHREAD:只使用当前线程的 children
323+ current. clone ( )
324+ } else {
325+ // 默认:使用线程组 leader 的 children
326+ get_thread_group_leader ( & current)
327+ } ;
270328 loop {
271329 // 注册等待
272330 let _ = parent. wait_queue . prepare_to_wait_event ( true ) ;
@@ -285,6 +343,11 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
285343 let pcb =
286344 ProcessManager :: find_task_by_vpid ( * pid) . ok_or ( SystemError :: ECHILD ) ?;
287345
346+ // 检查子进程是否可以被当前线程等待(考虑 __WNOTHREAD)
347+ if !is_eligible_child ( & pcb, kwo. options ) {
348+ continue ;
349+ }
350+
288351 // 检查子进程是否匹配等待选项(__WALL/__WCLONE)
289352 if !child_matches_wait_options ( & pcb, kwo. options ) {
290353 continue ;
@@ -387,8 +450,13 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
387450 PidConverter :: Pgid ( Some ( pgid) ) => {
388451 // 修复:根据 Linux waitpid 语义,waitpid(-pgid, ...) 只等待调用者的
389452 // **子进程**中属于指定进程组的进程,而不是进程组中的所有进程。
390- // 因此,这里遍历父进程的 children 列表,检查每个子进程是否属于目标进程组。
391- let parent = ProcessManager :: current_pcb ( ) ;
453+ // 因此,这里遍历线程组 leader 的 children 列表,检查每个子进程是否属于目标进程组。
454+ let current = ProcessManager :: current_pcb ( ) ;
455+ let parent = if kwo. options . contains ( WaitOption :: WNOTHREAD ) {
456+ current. clone ( )
457+ } else {
458+ get_thread_group_leader ( & current)
459+ } ;
392460 loop {
393461 // 注册等待
394462 let _ = parent. wait_queue . prepare_to_wait_event ( true ) ;
@@ -416,6 +484,11 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
416484 }
417485 } ;
418486
487+ // 检查子进程是否可以被当前线程等待(考虑 __WNOTHREAD)
488+ if !is_eligible_child ( & pcb, kwo. options ) {
489+ continue ;
490+ }
491+
419492 // 检查子进程是否属于目标进程组
420493 // 注意:即使进程已退出并从进程组的 tasks 列表中 detach,
421494 // task_pgrp() 仍然返回它之前所属的进程组
0 commit comments