rust_shell/
local_shell.rs1use shell_child::ShellChildArc;
16use libc::c_int;
17use process_manager::PROCESS_MANAGER;
18use std::any::Any;
19use std::cell::RefCell;
20use std::ops::Deref;
21use std::sync::Arc;
22use std::sync::Mutex;
23use std::thread::JoinHandle;
24use std::thread::ThreadId;
25use std::thread;
26
27pub struct LocalShell {
29 processes: Vec<ShellChildArc>,
30 signaled: bool
31}
32
33impl LocalShell {
34 fn new() -> LocalShell {
35 LocalShell {
36 processes: Vec::new(),
37 signaled: false
38 }
39 }
40
41 pub fn add_process(&mut self, process: &ShellChildArc) {
42 self.processes.push(process.clone());
43 }
44
45 pub fn remove_process(&mut self, process: &ShellChildArc) {
46 self.processes.retain(|p| !Arc::ptr_eq(p, process));
47 }
48
49 pub fn signal(&mut self, signal: c_int) {
50 self.signaled = true;
51 for process in &self.processes {
52 let lock = process.read().unwrap();
53 if let Some(child) = lock.as_ref() {
54 if let Err(error) = child.signal(signal) {
55 error!("Failed to send a signal {:?}", error);
56 }
57 }
58 }
59 }
60
61 pub fn wait(&mut self) {
62 for process in &self.processes {
63 let mut lock = process.write().unwrap();
64 if let Some(child) = lock.take() {
65 if let Err(error) = child.wait() {
66 error!("Failed to wait process {:?}", error);
67 }
68 }
69 }
70 }
71
72 pub fn signaled(&self) -> bool {
73 self.signaled
74 }
75}
76
77struct LocalShellScope(ThreadId, Arc<Mutex<LocalShell>>);
78
79impl LocalShellScope {
80 fn new(arc: &Arc<Mutex<LocalShell>>) -> LocalShellScope {
81 let mut lock = PROCESS_MANAGER.lock().unwrap();
82 let id = thread::current().id();
83 lock.add_local_shell(&id, arc);
84
85 LocalShellScope(id, arc.clone())
86 }
87}
88
89impl Default for LocalShellScope {
90 fn default() -> LocalShellScope {
91 LocalShellScope::new(&Arc::new(Mutex::new(LocalShell::new())))
92 }
93}
94
95impl Drop for LocalShellScope {
96 fn drop(&mut self) {
97 let mut lock = PROCESS_MANAGER.lock().unwrap();
98 lock.remove_local_shell(&self.0);
99 }
100}
101
102pub struct ShellHandle<T> {
103 join_handle: JoinHandle<T>,
104 shell: Arc<Mutex<LocalShell>>
105}
106
107impl <T> ShellHandle<T> {
108 pub fn signal(&self, signal: c_int) {
109 let mut lock = self.shell.lock().unwrap();
110 lock.signal(signal);
111 }
112
113 pub fn join(self) -> Result<T, Box<Any + Send + 'static>> {
114 self.join_handle.join()
115 }
116}
117
118impl <T> Deref for ShellHandle<T> {
119 type Target = JoinHandle<T>;
120 fn deref(&self) -> &Self::Target {
121 &self.join_handle
122 }
123}
124
125pub fn spawn<F, T>(f: F) -> ShellHandle<T> where
126 F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
127 let arc = Arc::new(Mutex::new(LocalShell::new()));
128 let arc_clone = arc.clone();
129 let join_handle = thread::spawn(move || -> T {
130 LOCAL_SHELL_SCOPE.with(|shell| {
131 let mut shell = shell.borrow_mut();
132 if shell.is_some() {
133 panic!("Shell has already registered");
134 }
135 *shell = Some(LocalShellScope::new(&arc_clone));
136 });
137 f()
138 });
139 ShellHandle {
140 join_handle: join_handle,
141 shell: arc
142 }
143}
144
145pub fn current_shell() -> Arc<Mutex<LocalShell>> {
146 LOCAL_SHELL_SCOPE.with(|shell| {
147 shell.borrow_mut()
148 .get_or_insert(LocalShellScope::default()).1.clone()
149 })
150}
151
152thread_local! {
153 static LOCAL_SHELL_SCOPE: RefCell<Option<LocalShellScope>> =
154 RefCell::new(None);
155}
156