1
1
use anyhow:: { anyhow, Result } ;
2
2
use derive_more:: Display ;
3
3
use futures:: channel:: oneshot:: channel;
4
+ use futures:: future:: { AbortHandle , Abortable } ;
4
5
use shared_child:: SharedChild ;
5
6
use std:: process:: Command ;
6
7
use std:: sync:: Arc ;
@@ -11,17 +12,14 @@ use std::time::Duration;
11
12
pub mod lock;
12
13
13
14
#[ cfg( unix) ]
14
- use {
15
- futures:: future:: { AbortHandle , Abortable } ,
16
- shared_child:: unix:: SharedChildExt ,
17
- } ;
15
+ use shared_child:: unix:: SharedChildExt ;
18
16
19
17
#[ cfg( windows) ]
20
- use {
21
- winapi :: um :: handleapi :: CloseHandle ,
22
- winapi:: um:: processthreadsapi :: OpenProcess ,
23
- winapi :: um :: wincon :: { GenerateConsoleCtrlEvent , CTRL_BREAK_EVENT } ,
24
- winapi :: um :: winnt :: { PROCESS_QUERY_INFORMATION , PROCESS_TERMINATE , SYNCHRONIZE } ,
18
+ use std :: process :: ExitStatus ;
19
+ # [ cfg ( windows ) ]
20
+ use winapi:: um:: {
21
+ errhandlingapi ,
22
+ wincon :: { GenerateConsoleCtrlEvent , CTRL_BREAK_EVENT } ,
25
23
} ;
26
24
27
25
pub trait ProcessGroupExt < T > {
@@ -125,36 +123,28 @@ impl ProcessHandle {
125
123
}
126
124
127
125
#[ cfg( windows) ]
128
- pub async fn terminate ( & self , _timeout : Duration ) -> Result < ( ) > {
126
+ pub async fn terminate ( & self , timeout : Duration ) -> Result < ( ) > {
127
+ use anyhow:: bail;
128
+
129
129
let process = self . process . clone ( ) ;
130
- let process_pid = process. id ( ) ;
130
+ let ( abort_handle, abort_registration) = AbortHandle :: new_pair ( ) ;
131
+ let _process_pid = process. id ( ) ;
131
132
132
- unsafe {
133
- let process_handle = OpenProcess (
134
- PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE ,
135
- 0 ,
136
- process_pid,
137
- ) ;
138
-
139
- if process_handle. is_null ( ) {
140
- return Err ( anyhow ! (
141
- "Unable to open the process. Error code: {}" ,
142
- winapi:: um:: errhandlingapi:: GetLastError ( )
143
- ) ) ;
144
- }
145
-
146
- let event_result = GenerateConsoleCtrlEvent ( CTRL_BREAK_EVENT , process_pid) ;
147
-
148
- if event_result == 0 {
149
- return Err ( anyhow ! (
150
- "Unable to send CTRL+C event to the process. Error code: {}" ,
151
- winapi:: um:: errhandlingapi:: GetLastError ( )
152
- ) ) ;
153
- } ;
154
- CloseHandle ( process_handle) ;
133
+ tokio:: task:: spawn_local ( async move {
134
+ tokio:: time:: sleep ( timeout) . await ;
135
+ abort_handle. abort ( ) ;
136
+ } ) ;
137
+
138
+ if let Ok ( Err ( err) ) = Abortable :: new (
139
+ async { unsafe { ctrl_break_process ( process) } } ,
140
+ abort_registration,
141
+ )
142
+ . await
143
+ {
144
+ bail ! ( err. context( "Failed to CTRL-BREAK process" ) ) ;
155
145
}
156
146
157
- Ok ( ( ) )
147
+ self . check_if_running ( )
158
148
}
159
149
160
150
pub fn check_if_running ( & self ) -> Result < ( ) > {
@@ -200,3 +190,17 @@ impl ProcessHandle {
200
190
receiver. await . unwrap ( )
201
191
}
202
192
}
193
+
194
+ #[ cfg( windows) ]
195
+ unsafe fn ctrl_break_process ( process : Arc < SharedChild > ) -> Result < ExitStatus > {
196
+ let process_pid = process. id ( ) ;
197
+ let event_result = GenerateConsoleCtrlEvent ( CTRL_BREAK_EVENT , process_pid) ;
198
+
199
+ if event_result == 0 {
200
+ return Err ( anyhow ! (
201
+ "Unable to send CTRL-BREAK event to the process. Error code: {}" ,
202
+ errhandlingapi:: GetLastError ( )
203
+ ) ) ;
204
+ } ;
205
+ Ok ( process. wait ( ) ?)
206
+ }
0 commit comments