@@ -33,6 +33,21 @@ fn new(signum: u32) -> io::Result<RxFuture> {
33
33
Ok ( RxFuture :: new ( rx) )
34
34
}
35
35
36
+ fn event_requires_infinite_sleep_in_handler ( signum : u32 ) -> bool {
37
+ // Returning from the handler function of those events immediately terminates the process.
38
+ // So for async systems, the easiest solution is to simply never return from
39
+ // the handler function.
40
+ //
41
+ // For more information, see:
42
+ // https://learn.microsoft.com/en-us/windows/console/handlerroutine#remarks
43
+ match signum {
44
+ console:: CTRL_CLOSE_EVENT => true ,
45
+ console:: CTRL_LOGOFF_EVENT => true ,
46
+ console:: CTRL_SHUTDOWN_EVENT => true ,
47
+ _ => false ,
48
+ }
49
+ }
50
+
36
51
#[ derive( Debug ) ]
37
52
pub ( crate ) struct OsStorage {
38
53
ctrl_break : EventInfo ,
@@ -114,7 +129,15 @@ unsafe extern "system" fn handler(ty: u32) -> BOOL {
114
129
// the handler routine is always invoked in a new thread, thus we don't
115
130
// have the same restrictions as in Unix signal handlers, meaning we can
116
131
// go ahead and perform the broadcast here.
117
- if globals. broadcast ( ) {
132
+ let event_was_handled = globals. broadcast ( ) ;
133
+
134
+ if event_was_handled && event_requires_infinite_sleep_in_handler ( ty) {
135
+ loop {
136
+ std:: thread:: park ( ) ;
137
+ }
138
+ }
139
+
140
+ if event_was_handled {
118
141
1
119
142
} else {
120
143
// No one is listening for this notification any more
@@ -130,6 +153,16 @@ mod tests {
130
153
131
154
use tokio_test:: { assert_ok, assert_pending, assert_ready_ok, task} ;
132
155
156
+ unsafe fn raise_event ( signum : u32 ) {
157
+ if event_requires_infinite_sleep_in_handler ( signum) {
158
+ // Those events will enter an infinite loop in `handler`, so
159
+ // we need to run them on a separate thread
160
+ std:: thread:: spawn ( move || super :: handler ( signum) ) ;
161
+ } else {
162
+ super :: handler ( signum) ;
163
+ }
164
+ }
165
+
133
166
#[ test]
134
167
fn ctrl_c ( ) {
135
168
let rt = rt ( ) ;
@@ -143,7 +176,7 @@ mod tests {
143
176
// like sending signals on Unix, so we'll stub out the actual OS
144
177
// integration and test that our handling works.
145
178
unsafe {
146
- super :: handler ( console:: CTRL_C_EVENT ) ;
179
+ raise_event ( console:: CTRL_C_EVENT ) ;
147
180
}
148
181
149
182
assert_ready_ok ! ( ctrl_c. poll( ) ) ;
@@ -160,7 +193,7 @@ mod tests {
160
193
// like sending signals on Unix, so we'll stub out the actual OS
161
194
// integration and test that our handling works.
162
195
unsafe {
163
- super :: handler ( console:: CTRL_BREAK_EVENT ) ;
196
+ raise_event ( console:: CTRL_BREAK_EVENT ) ;
164
197
}
165
198
166
199
ctrl_break. recv ( ) . await . unwrap ( ) ;
@@ -178,7 +211,7 @@ mod tests {
178
211
// like sending signals on Unix, so we'll stub out the actual OS
179
212
// integration and test that our handling works.
180
213
unsafe {
181
- super :: handler ( console:: CTRL_CLOSE_EVENT ) ;
214
+ raise_event ( console:: CTRL_CLOSE_EVENT ) ;
182
215
}
183
216
184
217
ctrl_close. recv ( ) . await . unwrap ( ) ;
@@ -196,7 +229,7 @@ mod tests {
196
229
// like sending signals on Unix, so we'll stub out the actual OS
197
230
// integration and test that our handling works.
198
231
unsafe {
199
- super :: handler ( console:: CTRL_SHUTDOWN_EVENT ) ;
232
+ raise_event ( console:: CTRL_SHUTDOWN_EVENT ) ;
200
233
}
201
234
202
235
ctrl_shutdown. recv ( ) . await . unwrap ( ) ;
@@ -214,7 +247,7 @@ mod tests {
214
247
// like sending signals on Unix, so we'll stub out the actual OS
215
248
// integration and test that our handling works.
216
249
unsafe {
217
- super :: handler ( console:: CTRL_LOGOFF_EVENT ) ;
250
+ raise_event ( console:: CTRL_LOGOFF_EVENT ) ;
218
251
}
219
252
220
253
ctrl_logoff. recv ( ) . await . unwrap ( ) ;
0 commit comments