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