1 | module os |
2 | |
3 | // signal_kill - kills the process, after that it is no longer running |
4 | pub fn (mut p Process) signal_kill() { |
5 | if p.status !in [.running, .stopped] { |
6 | return |
7 | } |
8 | p._signal_kill() |
9 | p.status = .aborted |
10 | return |
11 | } |
12 | |
13 | // signal_pgkill - kills the whole process group |
14 | pub fn (mut p Process) signal_pgkill() { |
15 | if p.status !in [.running, .stopped] { |
16 | return |
17 | } |
18 | p._signal_pgkill() |
19 | return |
20 | } |
21 | |
22 | // signal_stop - stops the process, you can resume it with p.signal_continue() |
23 | pub fn (mut p Process) signal_stop() { |
24 | if p.status != .running { |
25 | return |
26 | } |
27 | p._signal_stop() |
28 | p.status = .stopped |
29 | return |
30 | } |
31 | |
32 | // signal_continue - tell a stopped process to continue/resume its work |
33 | pub fn (mut p Process) signal_continue() { |
34 | if p.status != .stopped { |
35 | return |
36 | } |
37 | p._signal_continue() |
38 | p.status = .running |
39 | return |
40 | } |
41 | |
42 | // wait - wait for a process to finish. |
43 | // Note: You have to call p.wait(), otherwise a finished process |
44 | // would get to a zombie state, and its resources will not get |
45 | // released fully, until its parent process exits. |
46 | // Note: This call will block the calling process until the child |
47 | // process is finished. |
48 | pub fn (mut p Process) wait() { |
49 | if p.status == .not_started { |
50 | p._spawn() |
51 | } |
52 | if p.status !in [.running, .stopped] { |
53 | return |
54 | } |
55 | p._wait() |
56 | return |
57 | } |
58 | |
59 | // close - free the OS resources associated with the process. |
60 | // Can be called multiple times, but will free the resources just once. |
61 | // This sets the process state to .closed, which is final. |
62 | pub fn (mut p Process) close() { |
63 | if p.status in [.not_started, .closed] { |
64 | return |
65 | } |
66 | p.status = .closed |
67 | $if !windows { |
68 | for i in 0 .. 3 { |
69 | if p.stdio_fd[i] != 0 { |
70 | fd_close(p.stdio_fd[i]) |
71 | } |
72 | } |
73 | } |
74 | } |
75 | |
76 | [unsafe] |
77 | pub fn (mut p Process) free() { |
78 | p.close() |
79 | unsafe { |
80 | p.filename.free() |
81 | p.err.free() |
82 | p.args.free() |
83 | p.env.free() |
84 | } |
85 | } |
86 | |
87 | // |
88 | // _spawn - should not be called directly, but only by p.run()/p.wait() . |
89 | // It encapsulates the fork/execve mechanism that allows the |
90 | // asynchronous starting of the new child process. |
91 | fn (mut p Process) _spawn() int { |
92 | if !p.env_is_custom { |
93 | p.env = []string{} |
94 | current_environment := environ() |
95 | for k, v in current_environment { |
96 | p.env << '${k}=${v}' |
97 | } |
98 | } |
99 | mut pid := 0 |
100 | $if windows { |
101 | pid = p.win_spawn_process() |
102 | } $else { |
103 | pid = p.unix_spawn_process() |
104 | } |
105 | p.pid = pid |
106 | p.status = .running |
107 | return 0 |
108 | } |
109 | |
110 | // is_alive - query whether the process p.pid is still alive |
111 | pub fn (mut p Process) is_alive() bool { |
112 | if p.status in [.running, .stopped] { |
113 | return p._is_alive() |
114 | } |
115 | return false |
116 | } |
117 | |
118 | // |
119 | pub fn (mut p Process) set_redirect_stdio() { |
120 | p.use_stdio_ctl = true |
121 | return |
122 | } |
123 | |
124 | pub fn (mut p Process) stdin_write(s string) { |
125 | p._check_redirection_call('stdin_write') |
126 | $if windows { |
127 | p.win_write_string(0, s) |
128 | } $else { |
129 | fd_write(p.stdio_fd[0], s) |
130 | } |
131 | } |
132 | |
133 | // will read from stdout pipe, will only return when EOF (end of file) or data |
134 | // means this will block unless there is data |
135 | pub fn (mut p Process) stdout_slurp() string { |
136 | p._check_redirection_call('stdout_slurp') |
137 | $if windows { |
138 | return p.win_slurp(1) |
139 | } $else { |
140 | return fd_slurp(p.stdio_fd[1]).join('') |
141 | } |
142 | } |
143 | |
144 | // read from stderr pipe, wait for data or EOF |
145 | pub fn (mut p Process) stderr_slurp() string { |
146 | p._check_redirection_call('stderr_slurp') |
147 | $if windows { |
148 | return p.win_slurp(2) |
149 | } $else { |
150 | return fd_slurp(p.stdio_fd[2]).join('') |
151 | } |
152 | } |
153 | |
154 | // read from stdout, return if data or not |
155 | pub fn (mut p Process) stdout_read() string { |
156 | p._check_redirection_call('stdout_read') |
157 | $if windows { |
158 | s, _ := p.win_read_string(1, 4096) |
159 | return s |
160 | } $else { |
161 | s, _ := fd_read(p.stdio_fd[1], 4096) |
162 | return s |
163 | } |
164 | } |
165 | |
166 | pub fn (mut p Process) stderr_read() string { |
167 | p._check_redirection_call('stderr_read') |
168 | $if windows { |
169 | s, _ := p.win_read_string(2, 4096) |
170 | return s |
171 | } $else { |
172 | s, _ := fd_read(p.stdio_fd[2], 4096) |
173 | return s |
174 | } |
175 | } |
176 | |
177 | // _check_redirection_call - should be called just by stdxxx methods |
178 | fn (mut p Process) _check_redirection_call(fn_name string) { |
179 | if !p.use_stdio_ctl { |
180 | panic('Call p.set_redirect_stdio() before calling p.${fn_name}') |
181 | } |
182 | if p.status == .not_started { |
183 | panic('Call p.${fn_name}() after you have called p.run()') |
184 | } |
185 | } |
186 | |
187 | // _signal_stop - should not be called directly, except by p.signal_stop |
188 | fn (mut p Process) _signal_stop() { |
189 | $if windows { |
190 | p.win_stop_process() |
191 | } $else { |
192 | p.unix_stop_process() |
193 | } |
194 | } |
195 | |
196 | // _signal_continue - should not be called directly, just by p.signal_continue |
197 | fn (mut p Process) _signal_continue() { |
198 | $if windows { |
199 | p.win_resume_process() |
200 | } $else { |
201 | p.unix_resume_process() |
202 | } |
203 | } |
204 | |
205 | // _signal_kill - should not be called directly, except by p.signal_kill |
206 | fn (mut p Process) _signal_kill() { |
207 | $if windows { |
208 | p.win_kill_process() |
209 | } $else { |
210 | p.unix_kill_process() |
211 | } |
212 | } |
213 | |
214 | // _signal_pgkill - should not be called directly, except by p.signal_pgkill |
215 | fn (mut p Process) _signal_pgkill() { |
216 | $if windows { |
217 | p.win_kill_pgroup() |
218 | } $else { |
219 | p.unix_kill_pgroup() |
220 | } |
221 | } |
222 | |
223 | // _wait - should not be called directly, except by p.wait() |
224 | fn (mut p Process) _wait() { |
225 | $if windows { |
226 | p.win_wait() |
227 | } $else { |
228 | p.unix_wait() |
229 | } |
230 | } |
231 | |
232 | // _is_alive - should not be called directly, except by p.is_alive() |
233 | fn (mut p Process) _is_alive() bool { |
234 | $if windows { |
235 | return p.win_is_alive() |
236 | } $else { |
237 | return p.unix_is_alive() |
238 | } |
239 | } |
240 | |
241 | // run - starts the new process |
242 | pub fn (mut p Process) run() { |
243 | if p.status != .not_started { |
244 | return |
245 | } |
246 | p._spawn() |
247 | return |
248 | } |