@@ -822,3 +822,57 @@ mod tokio_tests {
822822 }
823823 }
824824}
825+
826+ #[ cfg( test) ]
827+ #[ cfg( loom) ]
828+ mod loom_test {
829+ use cassette:: Cassette ;
830+ use loom:: thread;
831+
832+ #[ macro_export]
833+ #[ allow( missing_docs) ]
834+ macro_rules! make_loom_channel {
835+ ( $type: ty, $size: expr) => { {
836+ let channel: crate :: channel:: Channel <$type, $size> = super :: Channel :: new( ) ;
837+ let boxed = Box :: new( channel) ;
838+ let boxed = Box :: leak( boxed) ;
839+
840+ // SAFETY: This is safe as we hide the static mut from others to access it.
841+ // Only this point is where the mutable access happens.
842+ boxed. split( )
843+ } } ;
844+ }
845+
846+ // This test tests the following scenarios:
847+ // 1. Receiver is dropped while concurrent senders are waiting to send.
848+ // 2. Concurrent senders are competing for the same free slot.
849+ #[ test]
850+ pub fn concurrent_send_while_full_and_drop ( ) {
851+ loom:: model ( || {
852+ let ( mut tx, mut rx) = make_loom_channel ! ( [ u8 ; 20 ] , 1 ) ;
853+ let mut cloned = tx. clone ( ) ;
854+
855+ tx. try_send ( [ 1 ; 20 ] ) . unwrap ( ) ;
856+
857+ let handle1 = thread:: spawn ( move || {
858+ let future = std:: pin:: pin!( tx. send( [ 1 ; 20 ] ) ) ;
859+ let mut future = Cassette :: new ( future) ;
860+ if future. poll_on ( ) . is_none ( ) {
861+ future. poll_on ( ) ;
862+ }
863+ } ) ;
864+
865+ rx. try_recv ( ) . ok ( ) ;
866+
867+ let future = std:: pin:: pin!( cloned. send( [ 1 ; 20 ] ) ) ;
868+ let mut future = Cassette :: new ( future) ;
869+ if future. poll_on ( ) . is_none ( ) {
870+ future. poll_on ( ) ;
871+ }
872+
873+ drop ( rx) ;
874+
875+ handle1. join ( ) . unwrap ( ) ;
876+ } ) ;
877+ }
878+ }
0 commit comments