1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 use std::mem::MaybeUninit;
15 use std::process::Child as StdChild;
16 use std::sync::{Mutex, MutexGuard, Once};
17
18 use crate::signal::unix::signal_return_watch;
19 use crate::signal::SignalKind;
20 use crate::sync::watch;
21 use crate::sync::watch::Receiver;
22
23 pub(crate) struct GlobalZombieChild {
24 child_signal: Mutex<Option<watch::Receiver<()>>>,
25 vec: Mutex<Vec<StdChild>>,
26 }
27
28 impl GlobalZombieChild {
get_instance() -> &'static GlobalZombieChild29 pub(crate) fn get_instance() -> &'static GlobalZombieChild {
30 static mut GLOBAL_ZOMBIE_CHILD: MaybeUninit<GlobalZombieChild> = MaybeUninit::uninit();
31 static ONCE: Once = Once::new();
32
33 unsafe {
34 ONCE.call_once(|| {
35 let global = GlobalZombieChild {
36 child_signal: Mutex::new(None),
37 vec: Mutex::new(Vec::new()),
38 };
39 GLOBAL_ZOMBIE_CHILD = MaybeUninit::new(global);
40 });
41 &*GLOBAL_ZOMBIE_CHILD.as_ptr()
42 }
43 }
44
push(&self, child: StdChild)45 pub(crate) fn push(&self, child: StdChild) {
46 self.vec.lock().unwrap().push(child)
47 }
48
release_zombie(&self)49 pub(crate) fn release_zombie(&self) {
50 if let Ok(mut guard) = self.child_signal.try_lock() {
51 match &mut *guard {
52 Some(child_signal) => self.release_zombie_when_some_receiver(child_signal),
53 None => self.release_zombile_when_no_receiver(&mut guard),
54 }
55 }
56 }
57
release_zombie_when_some_receiver(&self, child_signal: &mut Receiver<()>)58 fn release_zombie_when_some_receiver(&self, child_signal: &mut Receiver<()>) {
59 if child_signal.try_notified().and_then(Result::ok).is_some() {
60 reap_vec(self.vec.lock().unwrap())
61 }
62 }
63
release_zombile_when_no_receiver(&self, guard: &mut MutexGuard<Option<Receiver<()>>>)64 fn release_zombile_when_no_receiver(&self, guard: &mut MutexGuard<Option<Receiver<()>>>) {
65 let vec = self.vec.lock().unwrap();
66 if !vec.is_empty() {
67 if let Ok(recv) = signal_return_watch(SignalKind::child()) {
68 **guard = Some(recv);
69 reap_vec(vec);
70 }
71 }
72 }
73 }
74
reap_vec(mut vec: MutexGuard<'_, Vec<StdChild>>)75 fn reap_vec(mut vec: MutexGuard<'_, Vec<StdChild>>) {
76 vec.retain_mut(|child| {
77 match child.try_wait() {
78 // `Ok(None)` means the child has not exited
79 Ok(None) => true,
80 _ => false,
81 }
82 });
83 drop(vec)
84 }
85