9
9
// except according to those terms.
10
10
11
11
use std:: cell:: Cell ;
12
+ use std:: libc:: c_int;
12
13
use std:: libc;
13
14
use std:: ptr;
14
- use std:: vec;
15
+ use std:: rt:: BlockedTask ;
16
+ use std:: rt:: io:: IoError ;
15
17
use std:: rt:: io:: process:: * ;
18
+ use std:: rt:: local:: Local ;
19
+ use std:: rt:: rtio:: RtioProcess ;
20
+ use std:: rt:: sched:: { Scheduler , SchedHandle } ;
21
+ use std:: vec;
16
22
17
- use super :: { Watcher , Loop , NativeHandle , UvError } ;
18
- use super :: { status_to_maybe_uv_error, ExitCallback } ;
19
- use uvio:: { UvPipeStream , UvUnboundPipe } ;
23
+ use super :: { Loop , NativeHandle , UvHandle , UvError , uv_error_to_io_error} ;
24
+ use uvio:: { HomingIO , UvPipeStream , UvUnboundPipe } ;
20
25
use uvll;
21
26
22
- /// A process wraps the handle of the underlying uv_process_t.
23
- pub struct Process ( * uvll:: uv_process_t ) ;
27
+ pub struct Process {
28
+ handle : * uvll:: uv_process_t ,
29
+ home : SchedHandle ,
24
30
25
- impl Watcher for Process { }
31
+ /// Task to wake up (may be null) for when the process exits
32
+ to_wake : Option < BlockedTask > ,
26
33
27
- impl Process {
28
- /// Creates a new process, ready to spawn inside an event loop
29
- pub fn new ( ) -> Process {
30
- let handle = unsafe { uvll:: malloc_handle ( uvll:: UV_PROCESS ) } ;
31
- assert ! ( handle. is_not_null( ) ) ;
32
- let mut ret: Process = NativeHandle :: from_native_handle ( handle) ;
33
- ret. install_watcher_data ( ) ;
34
- return ret;
35
- }
34
+ /// Collected from the exit_cb
35
+ exit_status : Option < int > ,
36
+ term_signal : Option < int > ,
37
+ }
36
38
39
+ impl Process {
37
40
/// Spawn a new process inside the specified event loop.
38
41
///
39
- /// The `config` variable will be passed down to libuv, and the `exit_cb`
40
- /// will be run only once, when the process exits.
41
- ///
42
42
/// Returns either the corresponding process object or an error which
43
43
/// occurred.
44
- pub fn spawn ( & mut self , loop_ : & Loop , config : ProcessConfig ,
45
- exit_cb : ExitCallback )
46
- -> Result < ~[ Option < ~UvPipeStream > ] , UvError >
44
+ pub fn spawn ( loop_ : & Loop , config : ProcessConfig )
45
+ -> Result < ( ~Process , ~[ Option < ~UvPipeStream > ] ) , UvError >
47
46
{
48
47
let cwd = config. cwd . map ( |s| s. to_c_str ( ) ) ;
49
-
50
- extern fn on_exit ( p : * uvll:: uv_process_t ,
51
- exit_status : libc:: c_int ,
52
- term_signal : libc:: c_int ) {
53
- let mut p: Process = NativeHandle :: from_native_handle ( p) ;
54
- let err = match exit_status {
55
- 0 => None ,
56
- _ => status_to_maybe_uv_error ( -1 )
57
- } ;
58
- p. get_watcher_data ( ) . exit_cb . take_unwrap ( ) ( p,
59
- exit_status as int ,
60
- term_signal as int ,
61
- err) ;
62
- }
63
-
64
48
let io = config. io ;
65
49
let mut stdio = vec:: with_capacity :: < uvll:: uv_stdio_container_t > ( io. len ( ) ) ;
66
50
let mut ret_io = vec:: with_capacity ( io. len ( ) ) ;
@@ -73,7 +57,6 @@ impl Process {
73
57
}
74
58
}
75
59
76
- let exit_cb = Cell :: new ( exit_cb) ;
77
60
let ret_io = Cell :: new ( ret_io) ;
78
61
do with_argv( config. program , config. args ) |argv| {
79
62
do with_env ( config. env ) |envp| {
@@ -93,34 +76,47 @@ impl Process {
93
76
gid : 0 ,
94
77
} ;
95
78
79
+ let handle = UvHandle :: alloc ( None :: < Process > , uvll:: UV_PROCESS ) ;
96
80
match unsafe {
97
- uvll:: uv_spawn ( loop_. native_handle ( ) , * * self , options)
81
+ uvll:: uv_spawn ( loop_. native_handle ( ) , handle , options)
98
82
} {
99
83
0 => {
100
- ( * self ) . get_watcher_data ( ) . exit_cb = Some ( exit_cb. take ( ) ) ;
101
- Ok ( ret_io. take ( ) )
84
+ let process = ~Process {
85
+ handle : handle,
86
+ home : get_handle_to_current_scheduler ! ( ) ,
87
+ to_wake : None ,
88
+ exit_status : None ,
89
+ term_signal : None ,
90
+ } ;
91
+ Ok ( ( process. install ( ) , ret_io. take ( ) ) )
92
+ }
93
+ err => {
94
+ unsafe { uvll:: free_handle ( handle) }
95
+ Err ( UvError ( err) )
102
96
}
103
- err => Err ( UvError ( err) )
104
97
}
105
98
}
106
99
}
107
100
}
101
+ }
108
102
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 < ( ) , UvError > {
113
- match unsafe {
114
- uvll:: uv_process_kill ( self . native_handle ( ) , signum as libc:: c_int )
115
- } {
116
- 0 => Ok ( ( ) ) ,
117
- err => Err ( UvError ( err) )
103
+ extern fn on_exit ( handle : * uvll:: uv_process_t ,
104
+ exit_status : libc:: c_int ,
105
+ term_signal : libc:: c_int ) {
106
+ let handle = handle as * uvll:: uv_handle_t ;
107
+ let p: & mut Process = unsafe { UvHandle :: from_uv_handle ( & handle) } ;
108
+
109
+ assert ! ( p. exit_status. is_none( ) ) ;
110
+ assert ! ( p. term_signal. is_none( ) ) ;
111
+ p. exit_status = Some ( exit_status as int ) ;
112
+ p. term_signal = Some ( term_signal as int ) ;
113
+
114
+ match p. to_wake . take ( ) {
115
+ Some ( task) => {
116
+ let scheduler: ~Scheduler = Local :: take ( ) ;
117
+ scheduler. resume_blocked_task_immediately ( task) ;
118
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 }
119
+ None => { }
124
120
}
125
121
}
126
122
@@ -192,11 +188,59 @@ fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
192
188
c_envp. as_imm_buf ( |buf, _| f ( buf) )
193
189
}
194
190
195
- impl NativeHandle < * uvll:: uv_process_t > for Process {
196
- fn from_native_handle ( handle : * uvll:: uv_process_t ) -> Process {
197
- Process ( handle)
191
+ impl HomingIO for Process {
192
+ fn home < ' r > ( & ' r mut self ) -> & ' r mut SchedHandle { & mut self . home }
193
+ }
194
+
195
+ impl UvHandle < uvll:: uv_process_t > for Process {
196
+ fn uv_handle ( & self ) -> * uvll:: uv_process_t { self . handle }
197
+ }
198
+
199
+ impl RtioProcess for Process {
200
+ fn id ( & self ) -> libc:: pid_t {
201
+ unsafe { uvll:: process_pid ( self . handle ) as libc:: pid_t }
202
+ }
203
+
204
+ fn kill ( & mut self , signal : int ) -> Result < ( ) , IoError > {
205
+ do self . home_for_io |self_| {
206
+ match unsafe {
207
+ uvll:: process_kill ( self_. handle , signal as libc:: c_int )
208
+ } {
209
+ 0 => Ok ( ( ) ) ,
210
+ err => Err ( uv_error_to_io_error ( UvError ( err) ) )
211
+ }
212
+ }
213
+ }
214
+
215
+ fn wait ( & mut self ) -> int {
216
+ // Make sure (on the home scheduler) that we have an exit status listed
217
+ do self . home_for_io |self_| {
218
+ match self_. exit_status {
219
+ Some ( * ) => { }
220
+ None => {
221
+ // If there's no exit code previously listed, then the
222
+ // process's exit callback has yet to be invoked. We just
223
+ // need to deschedule ourselves and wait to be reawoken.
224
+ let scheduler: ~Scheduler = Local :: take ( ) ;
225
+ do scheduler. deschedule_running_task_and_then |_, task| {
226
+ assert ! ( self_. to_wake. is_none( ) ) ;
227
+ self_. to_wake = Some ( task) ;
228
+ }
229
+ assert ! ( self_. exit_status. is_some( ) ) ;
230
+ }
231
+ }
232
+ }
233
+
234
+ // FIXME(#10109): this is wrong
235
+ self . exit_status . unwrap ( )
198
236
}
199
- fn native_handle ( & self ) -> * uvll:: uv_process_t {
200
- match self { & Process ( ptr) => ptr }
237
+ }
238
+
239
+ impl Drop for Process {
240
+ fn drop ( & mut self ) {
241
+ do self . home_for_io |self_| {
242
+ assert ! ( self_. to_wake. is_none( ) ) ;
243
+ self_. close_async_ ( ) ;
244
+ }
201
245
}
202
246
}
0 commit comments