@@ -280,3 +280,42 @@ fn coroutine_syscall_not_preemptive() -> std::io::Result<()> {
280280 ) )
281281 }
282282}
283+
284+ #[ cfg( all( unix, not( feature = "preemptive" ) ) ) ]
285+ #[ test]
286+ fn coroutine_cancel ( ) -> std:: io:: Result < ( ) > {
287+ use std:: os:: unix:: prelude:: JoinHandleExt ;
288+ let pair = std:: sync:: Arc :: new ( ( std:: sync:: Mutex :: new ( true ) , std:: sync:: Condvar :: new ( ) ) ) ;
289+ let pair2 = pair. clone ( ) ;
290+ let handle = std:: thread:: Builder :: new ( )
291+ . name ( "cancel" . to_string ( ) )
292+ . spawn ( move || {
293+ let mut coroutine: Coroutine < ( ) , ( ) , ( ) > = co ! ( |_, ( ) | { loop { } } ) ?;
294+ assert_eq ! ( CoroutineState :: Cancelled , coroutine. resume( ) ?) ;
295+ assert_eq ! ( CoroutineState :: Cancelled , coroutine. state( ) ) ;
296+ // should execute to here
297+ let ( lock, cvar) = & * pair2;
298+ let mut pending = lock. lock ( ) . unwrap ( ) ;
299+ * pending = false ;
300+ cvar. notify_one ( ) ;
301+ Ok :: < ( ) , std:: io:: Error > ( ( ) )
302+ } ) ?;
303+ // wait for the thread to start up
304+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) ;
305+ nix:: sys:: pthread:: pthread_kill ( handle. as_pthread_t ( ) , nix:: sys:: signal:: Signal :: SIGVTALRM ) ?;
306+ let ( lock, cvar) = & * pair;
307+ let result = cvar
308+ . wait_timeout_while (
309+ lock. lock ( ) . unwrap ( ) ,
310+ std:: time:: Duration :: from_millis ( 3000 ) ,
311+ |& mut pending| pending,
312+ )
313+ . unwrap ( ) ;
314+ if result. 1 . timed_out ( ) {
315+ Err ( std:: io:: Error :: other (
316+ "The test thread should send signals to coroutines in running state" ,
317+ ) )
318+ } else {
319+ Ok ( ( ) )
320+ }
321+ }
0 commit comments