(index<- ) ./libstd/rt/uv/process.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use prelude::*;
12 use cell::Cell;
13 use libc;
14 use ptr;
15 use util;
16 use vec;
17
18 use rt::io::process::*;
19 use rt::uv;
20 use rt::uv::uvio::UvPipeStream;
21 use rt::uv::uvll;
22
23 /// A process wraps the handle of the underlying uv_process_t.
24 pub struct Process(*uvll::uv_process_t);
25
26 impl uv::Watcher for Process {}
27
28 impl Process {
29 /// Creates a new process, ready to spawn inside an event loop
30 pub fn new() -> Process {
31 let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
32 assert!(handle.is_not_null());
33 let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
34 ret.install_watcher_data();
35 return ret;
36 }
37
38 /// Spawn a new process inside the specified event loop.
39 ///
40 /// The `config` variable will be passed down to libuv, and the `exit_cb`
41 /// will be run only once, when the process exits.
42 ///
43 /// Returns either the corresponding process object or an error which
44 /// occurred.
45 pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig,
46 exit_cb: uv::ExitCallback)
47 -> Result<~[Option<UvPipeStream>], uv::UvError>
48 {
49 let cwd = config.cwd.map(|s| s.to_c_str());
50
51 extern fn on_exit(p: *uvll::uv_process_t,
52 exit_status: libc::c_int,
53 term_signal: libc::c_int) {
54 let mut p: Process = uv::NativeHandle::from_native_handle(p);
55 let err = match exit_status {
56 0 => None,
57 _ => uv::status_to_maybe_uv_error(-1)
58 };
59 p.get_watcher_data().exit_cb.take_unwrap()(p,
60 exit_status as int,
61 term_signal as int,
62 err);
63 }
64
65 let io = util::replace(&mut config.io, ~[]);
66 let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
67 let mut ret_io = vec::with_capacity(io.len());
68 unsafe {
69 vec::raw::set_len(&mut stdio, io.len());
70 for (slot, other) in stdio.iter().zip(io.move_iter()) {
71 let io = set_stdio(slot as *uvll::uv_stdio_container_t, other);
72 ret_io.push(io);
73 }
74 }
75
76 let exit_cb = Cell::new(exit_cb);
77 let ret_io = Cell::new(ret_io);
78 do with_argv(config.program, config.args) |argv| {
79 do with_env(config.env) |envp| {
80 let options = uvll::uv_process_options_t {
81 exit_cb: on_exit,
82 file: unsafe { *argv },
83 args: argv,
84 env: envp,
85 cwd: match cwd {
86 Some(ref cwd) => cwd.with_ref(|p| p),
87 None => ptr::null(),
88 },
89 flags: 0,
90 stdio_count: stdio.len() as libc::c_int,
91 stdio: stdio.as_imm_buf(|p, _| p),
92 uid: 0,
93 gid: 0,
94 };
95
96 match unsafe {
97 uvll::spawn(loop_.native_handle(), **self, options)
98 } {
99 0 => {
100 (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
101 Ok(ret_io.take())
102 }
103 err => Err(uv::UvError(err))
104 }
105 }
106 }
107 }
108
109 /// Sends a signal to this process.
110 ///
111 /// This is a wrapper around `uv_process_kill`
112 pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
113 match unsafe {
114 uvll::process_kill(self.native_handle(), signum as libc::c_int)
115 } {
116 0 => Ok(()),
117 err => Err(uv::UvError(err))
118 }
119 }
120
121 /// Returns the process id of a spawned process
122 pub fn pid(&self) -> libc::pid_t {
123 unsafe { uvll::process_pid(**self) as libc::pid_t }
124 }
125
126 /// Closes this handle, invoking the specified callback once closed
127 pub fn close(self, cb: uv::NullCallback) {
128 {
129 let mut this = self;
130 let data = this.get_watcher_data();
131 assert!(data.close_cb.is_none());
132 data.close_cb = Some(cb);
133 }
134
135 unsafe { uvll::close(self.native_handle(), close_cb); }
136
137 extern fn close_cb(handle: *uvll::uv_process_t) {
138 let mut process: Process = uv::NativeHandle::from_native_handle(handle);
139 process.get_watcher_data().close_cb.take_unwrap()();
140 process.drop_watcher_data();
141 unsafe { uvll::free_handle(handle as *libc::c_void) }
142 }
143 }
144 }
145
146 unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
147 io: StdioContainer) -> Option<UvPipeStream> {
148 match io {
149 Ignored => {
150 uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
151 None
152 }
153 InheritFd(fd) => {
154 uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
155 uvll::set_stdio_container_fd(dst, fd);
156 None
157 }
158 CreatePipe(pipe, readable, writable) => {
159 let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
160 if readable {
161 flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
162 }
163 if writable {
164 flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
165 }
166 let handle = pipe.pipe.as_stream().native_handle();
167 uvll::set_stdio_container_flags(dst, flags);
168 uvll::set_stdio_container_stream(dst, handle);
169 Some(pipe.bind())
170 }
171 }
172 }
173
174 /// Converts the program and arguments to the argv array expected by libuv
175 fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
176 // First, allocation space to put all the C-strings (we need to have
177 // ownership of them somewhere
178 let mut c_strs = vec::with_capacity(args.len() + 1);
179 c_strs.push(prog.to_c_str());
180 for arg in args.iter() {
181 c_strs.push(arg.to_c_str());
182 }
183
184 // Next, create the char** array
185 let mut c_args = vec::with_capacity(c_strs.len() + 1);
186 for s in c_strs.iter() {
187 c_args.push(s.with_ref(|p| p));
188 }
189 c_args.push(ptr::null());
190 c_args.as_imm_buf(|buf, _| f(buf))
191 }
192
193 /// Converts the environment to the env array expected by libuv
194 fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
195 let env = match env {
196 Some(s) => s,
197 None => { return f(ptr::null()); }
198 };
199 // As with argv, create some temporary storage and then the actual array
200 let mut envp = vec::with_capacity(env.len());
201 for &(ref key, ref value) in env.iter() {
202 envp.push(format!("{}={}", *key, *value).to_c_str());
203 }
204 let mut c_envp = vec::with_capacity(envp.len() + 1);
205 for s in envp.iter() {
206 c_envp.push(s.with_ref(|p| p));
207 }
208 c_envp.push(ptr::null());
209 c_envp.as_imm_buf(|buf, _| f(buf))
210 }
211
212 impl uv::NativeHandle<*uvll::uv_process_t> for Process {
213 fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
214 Process(handle)
215 }
216 fn native_handle(&self) -> *uvll::uv_process_t {
217 match self { &Process(ptr) => ptr }
218 }
219 }
libstd/rt/uv/process.rs:23:63-23:63 -struct- definition:
/// A process wraps the handle of the underlying uv_process_t.
pub struct Process(*uvll::uv_process_t);
references:-212: impl uv::NativeHandle<*uvll::uv_process_t> for Process {
54: let mut p: Process = uv::NativeHandle::from_native_handle(p);
26: impl uv::Watcher for Process {}
138: let mut process: Process = uv::NativeHandle::from_native_handle(handle);
213: fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
30: pub fn new() -> Process {
28: impl Process {
33: let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
libstd/rt/uv/mod.rs:
135: pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
libstd/rt/uv/uvio.rs:
1533: process: process::Process,
libstd/rt/uv/process.rs:137:8-137:8 -fn- definition:
extern fn close_cb(handle: *uvll::uv_process_t) {
let mut process: Process = uv::NativeHandle::from_native_handle(handle);
references:-135: unsafe { uvll::close(self.native_handle(), close_cb); }
libstd/rt/uv/process.rs:174:75-174:75 -fn- definition:
/// Converts the program and arguments to the argv array expected by libuv
fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
references:-78: do with_argv(config.program, config.args) |argv| {
libstd/rt/uv/process.rs:193:64-193:64 -fn- definition:
/// Converts the environment to the env array expected by libuv
fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
references:-79: do with_env(config.env) |envp| {
libstd/rt/uv/process.rs:145:1-145:1 -fn- definition:
unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
references:-71: let io = set_stdio(slot as *uvll::uv_stdio_container_t, other);
libstd/rt/uv/process.rs:51:8-51:8 -fn- definition:
extern fn on_exit(p: *uvll::uv_process_t,
exit_status: libc::c_int,
references:-81: exit_cb: on_exit,