@@ -822,3 +822,57 @@ mod tokio_tests {
822
822
}
823
823
}
824
824
}
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