227
227
228
228
use cast;
229
229
use clone:: Clone ;
230
- use container:: Container ;
231
230
use int;
232
231
use iter:: Iterator ;
233
232
use kinds:: Send ;
@@ -295,32 +294,32 @@ pub struct PortIterator<'a, T> {
295
294
/// task
296
295
#[ no_freeze] // can't share chans in an arc
297
296
pub struct Chan < T > {
298
- priv inner : UnsafeArc < SingleInner < T > > ,
297
+ priv inner : UnsafeArc < Stream < T > > ,
299
298
}
300
299
301
300
/// The sending-half of Rust's channel type. This half can be shared among many
302
301
/// tasks by creating copies of itself through the `clone` method.
303
302
#[ no_freeze] // technically this implementation is shareable, but it shouldn't
304
303
// be required to be shareable in an arc
305
304
pub struct SharedChan < T > {
306
- priv inner : UnsafeArc < SharedInner < T > > ,
305
+ priv inner : UnsafeArc < Shared < T > > ,
307
306
}
308
307
309
308
///////////////////////////////////////////////////////////////////////////////
310
309
// Internal struct definitions
311
310
///////////////////////////////////////////////////////////////////////////////
312
311
313
312
enum PortInner < T > {
314
- Single ( UnsafeArc < SingleInner < T > > ) ,
315
- Shared ( UnsafeArc < SharedInner < T > > ) ,
313
+ SingleInner ( UnsafeArc < Stream < T > > ) ,
314
+ SharedInner ( UnsafeArc < Shared < T > > ) ,
316
315
}
317
316
318
- struct SingleInner < T > {
317
+ struct Stream < T > {
319
318
queue : spsc:: Queue < T > ,
320
319
packet : Packet ,
321
320
}
322
321
323
- struct SharedInner < T > {
322
+ struct Shared < T > {
324
323
queue : mpsc:: Queue < T > ,
325
324
packet : Packet ,
326
325
}
@@ -339,6 +338,11 @@ struct Packet {
339
338
select_next : * mut Packet ,
340
339
select_prev : * mut Packet ,
341
340
recv_cnt : int ,
341
+
342
+ // See the discussion in Port::drop and the channel send methods for what
343
+ // these are used for
344
+ go_home : AtomicBool ,
345
+ sender_drain : AtomicInt ,
342
346
}
343
347
344
348
///////////////////////////////////////////////////////////////////////////////
@@ -351,8 +355,8 @@ static RESCHED_FREQ: int = 200;
351
355
impl < T : Send > PortInner < T > {
352
356
fn packet < ' a > ( & ' a mut self ) -> & ' a mut Packet {
353
357
match * self {
354
- Single ( ref arc) => unsafe { & mut ( * arc. get ( ) ) . packet } ,
355
- Shared ( ref arc) => unsafe { & mut ( * arc. get ( ) ) . packet } ,
358
+ SingleInner ( ref arc) => unsafe { & mut ( * arc. get ( ) ) . packet } ,
359
+ SharedInner ( ref arc) => unsafe { & mut ( * arc. get ( ) ) . packet } ,
356
360
}
357
361
}
358
362
}
@@ -370,6 +374,9 @@ impl Packet {
370
374
select_next : 0 as * mut Packet ,
371
375
select_prev : 0 as * mut Packet ,
372
376
recv_cnt : 0 ,
377
+
378
+ go_home : AtomicBool :: new ( false ) ,
379
+ sender_drain : AtomicInt :: new ( 0 ) ,
373
380
}
374
381
}
375
382
@@ -530,11 +537,11 @@ impl<T: Send> Chan<T> {
530
537
pub fn new ( ) -> ( Port < T > , Chan < T > ) {
531
538
// arbitrary 128 size cache -- this is just a max cache size, not a
532
539
// maximum buffer size
533
- let ( a, b) = UnsafeArc :: new2 ( SingleInner {
540
+ let ( a, b) = UnsafeArc :: new2 ( Stream {
534
541
queue : spsc:: Queue :: new ( 128 ) ,
535
542
packet : Packet :: new ( ) ,
536
543
} ) ;
537
- ( Port { inner : Single ( a) } , Chan { inner : b } )
544
+ ( Port { inner : SingleInner ( a) } , Chan { inner : b } )
538
545
}
539
546
540
547
/// Sends a value along this channel to be received by the corresponding
@@ -584,14 +591,35 @@ impl<T: Send> Chan<T> {
584
591
fn try ( & self , t : T , can_resched : bool ) -> bool {
585
592
unsafe {
586
593
let inner = self . inner . get ( ) ;
594
+
595
+ // See the discussion in Port::drop for what's going on here
596
+ if ( * inner) . packet . go_home . load ( Relaxed ) { return false }
597
+
587
598
( * inner) . queue . push ( t) ;
588
599
match ( * inner) . packet . increment ( ) {
589
600
// As described above, -1 == wakeup
590
601
-1 => { ( * inner) . packet . wakeup ( can_resched) ; true }
591
602
// Also as above, SPSC queues must be >= -2
592
603
-2 => true ,
593
- // We succeeded if we sent data
594
- DISCONNECTED => ( * inner) . queue . is_empty ( ) ,
604
+
605
+ DISCONNECTED => {
606
+ // After the go_home check, the port could have been
607
+ // dropped, so we need to be sure to drain the queue here
608
+ // (we own the queue now that the port is gone). Note that
609
+ // it is only possible for there to be one item in the queue
610
+ // because the port ensures that there is 0 data in the
611
+ // queue when it flags disconnected, and we could have only
612
+ // pushed on one more item
613
+ let first = ( * inner) . queue . pop ( ) ;
614
+ let second = ( * inner) . queue . pop ( ) ;
615
+ assert ! ( second. is_none( ) ) ;
616
+
617
+ match first {
618
+ Some ( ..) => false , // we failed to send the data
619
+ None => true , // we successfully sent data
620
+ }
621
+ }
622
+
595
623
// In order to prevent starvation of other tasks in situations
596
624
// where a task sends repeatedly without ever receiving, we
597
625
// occassionally yield instead of doing a send immediately.
@@ -626,11 +654,11 @@ impl<T: Send> SharedChan<T> {
626
654
/// same time. All data sent on any channel will become available on the
627
655
/// provided port as well.
628
656
pub fn new ( ) -> ( Port < T > , SharedChan < T > ) {
629
- let ( a, b) = UnsafeArc :: new2 ( SharedInner {
657
+ let ( a, b) = UnsafeArc :: new2 ( Shared {
630
658
queue : mpsc:: Queue :: new ( ) ,
631
659
packet : Packet :: new ( ) ,
632
660
} ) ;
633
- ( Port { inner : Shared ( a) } , SharedChan { inner : b } )
661
+ ( Port { inner : SharedInner ( a) } , SharedChan { inner : b } )
634
662
}
635
663
636
664
/// Equivalent method to `send` on the `Chan` type (using the same
@@ -645,6 +673,10 @@ impl<T: Send> SharedChan<T> {
645
673
/// semantics)
646
674
pub fn try_send ( & self , t : T ) -> bool {
647
675
unsafe {
676
+ let inner = self . inner . get ( ) ;
677
+ // See Port::drop for what's going on
678
+ if ( * inner) . packet . go_home . load ( Relaxed ) { return false }
679
+
648
680
// Note that the multiple sender case is a little tricker
649
681
// semantically than the single sender case. The logic for
650
682
// incrementing is "add and if disconnected store disconnected".
@@ -670,15 +702,49 @@ impl<T: Send> SharedChan<T> {
670
702
// preflight check serves as the definitive "this will never be
671
703
// received". Once we get beyond this check, we have permanently
672
704
// entered the realm of "this may be received"
673
- let inner = self . inner . get ( ) ;
674
705
if ( * inner) . packet . cnt . load ( Relaxed ) < DISCONNECTED + 1024 {
675
706
return false
676
707
}
677
708
678
709
( * inner) . queue . push ( t) ;
679
710
match ( * inner) . packet . increment ( ) {
680
- DISCONNECTED => { } // oh well, we tried
681
711
-1 => { ( * inner) . packet . wakeup ( true ) ; }
712
+
713
+ // In this case, we have possibly failed to send our data, and
714
+ // we need to consider re-popping the data in order to fully
715
+ // destroy it. We must arbitrate among the multiple senders,
716
+ // however, because the queues that we're using are
717
+ // single-consumer queues. In order to do this, all exiting
718
+ // pushers will use an atomic count in order to count those
719
+ // flowing through. Pushers who see 0 are required to drain as
720
+ // much as possible, and then can only exit when they are the
721
+ // only pusher (otherwise they must try again).
722
+ n if n < DISCONNECTED + 1024 => {
723
+ if ( * inner) . packet . sender_drain . fetch_add ( 1 , SeqCst ) == 0 {
724
+ loop {
725
+ // drain the queue
726
+ loop {
727
+ match ( * inner) . queue . pop ( ) {
728
+ mpsc:: Data ( ..) => { }
729
+ mpsc:: Empty => break ,
730
+ mpsc:: Inconsistent => Thread :: yield_now ( ) ,
731
+ }
732
+ }
733
+ // maybe we're done, if we're not the last ones
734
+ // here, then we need to go try again.
735
+ if ( * inner) . packet . sender_drain . compare_and_swap (
736
+ 1 , 0 , SeqCst ) == 1 {
737
+ break
738
+ }
739
+ }
740
+
741
+ // At this point, there may still be data on the queue,
742
+ // but only if the count hasn't been incremented and
743
+ // some other sender hasn't finished pushing data just
744
+ // yet.
745
+ }
746
+ }
747
+
682
748
n => {
683
749
if n > 0 && n % RESCHED_FREQ == 0 {
684
750
let task: ~Task = Local :: take ( ) ;
@@ -763,8 +829,8 @@ impl<T: Send> Port<T> {
763
829
}
764
830
765
831
let ret = match this. inner {
766
- Single ( ref mut arc) => unsafe { ( * arc. get ( ) ) . queue . pop ( ) } ,
767
- Shared ( ref mut arc) => match unsafe { ( * arc. get ( ) ) . queue . pop ( ) } {
832
+ SingleInner ( ref mut arc) => unsafe { ( * arc. get ( ) ) . queue . pop ( ) } ,
833
+ SharedInner ( ref mut arc) => match unsafe { ( * arc. get ( ) ) . queue . pop ( ) } {
768
834
mpsc:: Data ( t) => Some ( t) ,
769
835
mpsc:: Empty => None ,
770
836
@@ -868,10 +934,69 @@ impl<'a, T: Send> Iterator<T> for PortIterator<'a, T> {
868
934
#[ unsafe_destructor]
869
935
impl < T : Send > Drop for Port < T > {
870
936
fn drop ( & mut self ) {
871
- // All we need to do is store that we're disconnected. If the channel
872
- // half has already disconnected, then we'll just deallocate everything
873
- // when the shared packet is deallocated.
874
- self . inner . packet ( ) . cnt . store ( DISCONNECTED , SeqCst ) ;
937
+ // Dropping a port seems like a fairly trivial thing. In theory all we
938
+ // need to do is flag that we're disconnected and then everything else
939
+ // can take over (we don't have anyone to wake up).
940
+ //
941
+ // The catch for Ports is that we want to drop the entire contents of
942
+ // the queue. There are multiple reasons for having this property, the
943
+ // largest of which is that if another port is waiting in this channel
944
+ // (but not received yet), then waiting on that port will cause a
945
+ // deadlock.
946
+ //
947
+ // So if we accept that we must now destroy the entire contents of the
948
+ // queue, this code may make a bit more sense. The tricky part is that
949
+ // we can't let any in-flight sends go un-dropped, we have to make sure
950
+ // *everything* is dropped and nothing new will come onto the channel.
951
+
952
+ // The first thing we do is set a flag saying that we're done for. All
953
+ // sends are gated on this flag, so we're immediately guaranteed that
954
+ // there are a bounded number of active sends that we'll have to deal
955
+ // with.
956
+ self . inner . packet ( ) . go_home . store ( true , Relaxed ) ;
957
+
958
+ // Now that we're guaranteed to deal with a bounded number of senders,
959
+ // we need to drain the queue. This draining process happens atomically
960
+ // with respect to the "count" of the channel. If the count is nonzero
961
+ // (with steals taken into account), then there must be data on the
962
+ // channel. In this case we drain everything and then try again. We will
963
+ // continue to fail while active senders send data while we're dropping
964
+ // data, but eventually we're guaranteed to break out of this loop
965
+ // (because there is a bounded number of senders).
966
+ let mut steals = self . inner . packet ( ) . steals ;
967
+ while {
968
+ let cnt = self . inner . packet ( ) . cnt . compare_and_swap (
969
+ steals, DISCONNECTED , SeqCst ) ;
970
+ cnt != DISCONNECTED && cnt != steals
971
+ } {
972
+ match self . inner {
973
+ SingleInner ( ref mut arc) => {
974
+ loop {
975
+ match unsafe { ( * arc. get ( ) ) . queue . pop ( ) } {
976
+ Some ( ..) => { steals += 1 ; }
977
+ None => break
978
+ }
979
+ }
980
+ }
981
+ SharedInner ( ref mut arc) => {
982
+ // See the discussion in 'try_recv_inc' for why we yield
983
+ // control of this thread.
984
+ loop {
985
+ match unsafe { ( * arc. get ( ) ) . queue . pop ( ) } {
986
+ mpsc:: Data ( ..) => { steals += 1 ; }
987
+ mpsc:: Empty => break ,
988
+ mpsc:: Inconsistent => Thread :: yield_now ( ) ,
989
+ }
990
+ }
991
+ }
992
+ }
993
+ }
994
+
995
+ // At this point in time, we have gated all future senders from sending,
996
+ // and we have flagged the channel as being disconnected. The senders
997
+ // still have some responsibility, however, because some sends may not
998
+ // complete until after we flag the disconnection. There are more
999
+ // details in the sending methods that see DISCONNECTED
875
1000
}
876
1001
}
877
1002
@@ -1322,4 +1447,24 @@ mod test {
1322
1447
drop( chan) ;
1323
1448
assert_eq!( count_port. recv( ) , 4 ) ;
1324
1449
} )
1450
+
1451
+ test ! ( fn pending_dropped( ) {
1452
+ let ( a, b) = Chan :: new( ) ;
1453
+ let ( c, d) = Chan :: <( ) >:: new( ) ;
1454
+ b. send( d) ;
1455
+ drop( a) ;
1456
+ c. recv( ) ;
1457
+ } #[ should_fail] )
1458
+
1459
+ test ! ( fn pending_dropped_stress( ) {
1460
+ let ( a, b) = Chan :: new( ) ;
1461
+ let ( c, d) = Chan :: new( ) ;
1462
+ do spawn {
1463
+ while b. try_send( ~3 ) { continue }
1464
+ d. send( ( ) ) ;
1465
+ }
1466
+ a. recv( ) ;
1467
+ drop( a) ;
1468
+ c. recv( ) ;
1469
+ } )
1325
1470
}
0 commit comments