os: add Process.finalise() and Process.free() methods to cleanup pipe descriptors

pull/10071/head
Delyan Angelov 2021-05-09 21:31:04 +03:00
parent 2a6a9c5222
commit 4728d102d9
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
3 changed files with 38 additions and 2 deletions

View File

@ -245,6 +245,7 @@ fn (mut context Context) compilation_runner_loop() {
} }
if !context.child_process.is_alive() { if !context.child_process.is_alive() {
context.child_process.wait() context.child_process.wait()
context.child_process.close()
break break
} }
} }
@ -315,18 +316,20 @@ fn (mut context Context) manager_main() {
time.sleep(200 * time.millisecond) time.sleep(200 * time.millisecond)
} }
if !(worker_process.code == 255 && worker_process.status == .exited) { if !(worker_process.code == 255 && worker_process.status == .exited) {
worker_process.close()
break break
} }
worker_process.close()
} }
} }
fn (mut context Context) worker_main() { fn (mut context Context) worker_main() {
context.rerun_channel = chan RerunCommand{cap: 10} context.rerun_channel = chan RerunCommand{cap: 10}
os.signal(C.SIGINT, fn () { os.signal_opt(.int, fn (_ os.Signal) {
mut context := unsafe { &Context(voidptr(&ccontext)) } mut context := unsafe { &Context(voidptr(&ccontext)) }
context.is_exiting = true context.is_exiting = true
context.kill_pgroup() context.kill_pgroup()
}) }) or { panic(err) }
go context.compilation_runner_loop() go context.compilation_runner_loop()
change_detection_loop(context) change_detection_loop(context)
} }

View File

@ -5,12 +5,14 @@ module os
// ProcessState.stopped - the process was running, but was stopped temporarily // ProcessState.stopped - the process was running, but was stopped temporarily
// ProcessState.exited - the process has finished/exited // ProcessState.exited - the process has finished/exited
// ProcessState.aborted - the process was terminated by a signal // ProcessState.aborted - the process was terminated by a signal
// ProcessState.closed - the process resources like opened file descriptors were freed/discarded, final state.
pub enum ProcessState { pub enum ProcessState {
not_started not_started
running running
stopped stopped
exited exited
aborted aborted
closed
} }
[heap] [heap]
@ -132,6 +134,34 @@ pub fn (mut p Process) wait() {
return return
} }
// close - free the OS resources associated with the process.
// Can be called multiple times, but will free the resources just once.
// This sets the process state to .closed, which is final.
pub fn (mut p Process) close() {
if p.status in [.not_started, .closed] {
return
}
p.status = .closed
$if !windows {
for i in 0 .. 3 {
if p.stdio_fd[i] != 0 {
fd_close(p.stdio_fd[i])
}
}
}
}
[unsafe]
pub fn (mut p Process) free() {
p.close()
unsafe {
p.filename.free()
p.err.free()
p.args.free()
p.env.free()
}
}
// //
// _spawn - should not be called directly, but only by p.run()/p.wait() . // _spawn - should not be called directly, but only by p.run()/p.wait() .
// It encapsulates the fork/execve mechanism that allows the // It encapsulates the fork/execve mechanism that allows the

View File

@ -52,6 +52,7 @@ fn test_run() {
// //
eprintln('polling iterations: $i') eprintln('polling iterations: $i')
assert i < 50 assert i < 50
p.close()
} }
fn test_wait() { fn test_wait() {
@ -61,6 +62,7 @@ fn test_wait() {
assert p.status == .exited assert p.status == .exited
assert p.code == 0 assert p.code == 0
assert p.pid != os.getpid() assert p.pid != os.getpid()
p.close()
} }
fn test_slurping_output() { fn test_slurping_output() {
@ -73,6 +75,7 @@ fn test_slurping_output() {
assert p.code == 0 assert p.code == 0
output := p.stdout_slurp().trim_space() output := p.stdout_slurp().trim_space()
errors := p.stderr_slurp().trim_space() errors := p.stderr_slurp().trim_space()
p.close()
$if trace_process_output ? { $if trace_process_output ? {
eprintln('---------------------------') eprintln('---------------------------')
eprintln('p output: "$output"') eprintln('p output: "$output"')