@@ -25,6 +25,7 @@ use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
25
25
use cell:: Cell ;
26
26
use clone:: Clone ;
27
27
use rt:: { context, SchedulerContext } ;
28
+ use tuple:: ImmutableTuple ;
28
29
29
30
/// A combined refcount / BlockedTask-as-uint pointer.
30
31
///
@@ -86,12 +87,32 @@ impl<T> ChanOne<T> {
86
87
}
87
88
}
88
89
90
+ /// Send a message on the one-shot channel. If a receiver task is blocked
91
+ /// waiting for the message, will wake it up and reschedule to it.
89
92
pub fn send ( self , val : T ) {
90
93
self . try_send ( val) ;
91
94
}
92
95
96
+ /// As `send`, but also returns whether or not the receiver endpoint is still open.
93
97
pub fn try_send ( self , val : T ) -> bool {
98
+ self . try_send_inner ( val, true )
99
+ }
100
+
101
+ /// Send a message without immediately rescheduling to a blocked receiver.
102
+ /// This can be useful in contexts where rescheduling is forbidden, or to
103
+ /// optimize for when the sender expects to still have useful work to do.
104
+ pub fn send_deferred ( self , val : T ) {
105
+ self . try_send_deferred ( val) ;
106
+ }
107
+
108
+ /// As `send_deferred` and `try_send` together.
109
+ pub fn try_send_deferred ( self , val : T ) -> bool {
110
+ self . try_send_inner ( val, false )
111
+ }
94
112
113
+ // 'do_resched' configures whether the scheduler immediately switches to
114
+ // the receiving task, or leaves the sending task still running.
115
+ fn try_send_inner ( self , val : T , do_resched : bool ) -> bool {
95
116
rtassert ! ( context( ) != SchedulerContext ) ;
96
117
97
118
let mut this = self ;
@@ -130,9 +151,16 @@ impl<T> ChanOne<T> {
130
151
task_as_state => {
131
152
// Port is blocked. Wake it up.
132
153
let recvr = BlockedTask :: cast_from_uint ( task_as_state) ;
133
- do recvr. wake ( ) . map_consume |woken_task| {
134
- Scheduler :: run_task ( woken_task) ;
135
- } ;
154
+ if do_resched {
155
+ do recvr. wake ( ) . map_consume |woken_task| {
156
+ Scheduler :: run_task ( woken_task) ;
157
+ } ;
158
+ } else {
159
+ let recvr = Cell :: new ( recvr) ;
160
+ do Local :: borrow :: < Scheduler , ( ) > |sched| {
161
+ sched. enqueue_blocked_task ( recvr. take ( ) ) ;
162
+ }
163
+ }
136
164
}
137
165
}
138
166
}
@@ -152,6 +180,7 @@ impl<T> PortOne<T> {
152
180
}
153
181
}
154
182
183
+ /// Wait for a message on the one-shot port. Fails if the send end is closed.
155
184
pub fn recv ( self ) -> T {
156
185
match self . try_recv ( ) {
157
186
Some ( val) => val,
@@ -161,6 +190,7 @@ impl<T> PortOne<T> {
161
190
}
162
191
}
163
192
193
+ /// As `recv`, but returns `None` if the send end is closed rather than failing.
164
194
pub fn try_recv ( self ) -> Option < T > {
165
195
let mut this = self ;
166
196
@@ -382,6 +412,12 @@ impl<T> Drop for PortOne<T> {
382
412
}
383
413
}
384
414
415
+ /// Trait for non-rescheduling send operations, similar to `send_deferred` on ChanOne.
416
+ pub trait SendDeferred < T > {
417
+ fn send_deferred ( & self , val : T ) ;
418
+ fn try_send_deferred ( & self , val : T ) -> bool ;
419
+ }
420
+
385
421
struct StreamPayload < T > {
386
422
val : T ,
387
423
next : PortOne < StreamPayload < T > >
@@ -409,6 +445,15 @@ pub fn stream<T: Send>() -> (Port<T>, Chan<T>) {
409
445
return ( port, chan) ;
410
446
}
411
447
448
+ impl < T : Send > Chan < T > {
449
+ fn try_send_inner ( & self , val : T , do_resched : bool ) -> bool {
450
+ let ( next_pone, next_cone) = oneshot ( ) ;
451
+ let cone = self . next . take ( ) ;
452
+ self . next . put_back ( next_cone) ;
453
+ cone. try_send_inner ( StreamPayload { val : val, next : next_pone } , do_resched)
454
+ }
455
+ }
456
+
412
457
impl < T : Send > GenericChan < T > for Chan < T > {
413
458
fn send ( & self , val : T ) {
414
459
self . try_send ( val) ;
@@ -417,10 +462,16 @@ impl<T: Send> GenericChan<T> for Chan<T> {
417
462
418
463
impl < T : Send > GenericSmartChan < T > for Chan < T > {
419
464
fn try_send ( & self , val : T ) -> bool {
420
- let ( next_pone, next_cone) = oneshot ( ) ;
421
- let cone = self . next . take ( ) ;
422
- self . next . put_back ( next_cone) ;
423
- cone. try_send ( StreamPayload { val : val, next : next_pone } )
465
+ self . try_send_inner ( val, true )
466
+ }
467
+ }
468
+
469
+ impl < T : Send > SendDeferred < T > for Chan < T > {
470
+ fn send_deferred ( & self , val : T ) {
471
+ self . try_send_deferred ( val) ;
472
+ }
473
+ fn try_send_deferred ( & self , val : T ) -> bool {
474
+ self . try_send_inner ( val, false )
424
475
}
425
476
}
426
477
@@ -495,6 +546,17 @@ impl<T> SharedChan<T> {
495
546
}
496
547
}
497
548
549
+ impl < T : Send > SharedChan < T > {
550
+ fn try_send_inner ( & self , val : T , do_resched : bool ) -> bool {
551
+ unsafe {
552
+ let ( next_pone, next_cone) = oneshot ( ) ;
553
+ let cone = ( * self . next . get ( ) ) . swap ( ~next_cone, SeqCst ) ;
554
+ cone. unwrap ( ) . try_send_inner ( StreamPayload { val : val, next : next_pone } ,
555
+ do_resched)
556
+ }
557
+ }
558
+ }
559
+
498
560
impl < T : Send > GenericChan < T > for SharedChan < T > {
499
561
fn send ( & self , val : T ) {
500
562
self . try_send ( val) ;
@@ -503,11 +565,16 @@ impl<T: Send> GenericChan<T> for SharedChan<T> {
503
565
504
566
impl < T : Send > GenericSmartChan < T > for SharedChan < T > {
505
567
fn try_send ( & self , val : T ) -> bool {
506
- unsafe {
507
- let ( next_pone, next_cone) = oneshot ( ) ;
508
- let cone = ( * self . next . get ( ) ) . swap ( ~next_cone, SeqCst ) ;
509
- cone. unwrap ( ) . try_send ( StreamPayload { val : val, next : next_pone } )
510
- }
568
+ self . try_send_inner ( val, true )
569
+ }
570
+ }
571
+
572
+ impl < T : Send > SendDeferred < T > for SharedChan < T > {
573
+ fn send_deferred ( & self , val : T ) {
574
+ self . try_send_deferred ( val) ;
575
+ }
576
+ fn try_send_deferred ( & self , val : T ) -> bool {
577
+ self . try_send_inner ( val, false )
511
578
}
512
579
}
513
580
@@ -584,31 +651,32 @@ pub fn megapipe<T: Send>() -> MegaPipe<T> {
584
651
585
652
impl < T : Send > GenericChan < T > for MegaPipe < T > {
586
653
fn send ( & self , val : T ) {
587
- match * self {
588
- ( _, ref c) => c. send ( val)
589
- }
654
+ self . second_ref ( ) . send ( val)
590
655
}
591
656
}
592
657
593
658
impl < T : Send > GenericSmartChan < T > for MegaPipe < T > {
594
659
fn try_send ( & self , val : T ) -> bool {
595
- match * self {
596
- ( _, ref c) => c. try_send ( val)
597
- }
660
+ self . second_ref ( ) . try_send ( val)
598
661
}
599
662
}
600
663
601
664
impl < T : Send > GenericPort < T > for MegaPipe < T > {
602
665
fn recv ( & self ) -> T {
603
- match * self {
604
- ( ref p, _) => p. recv ( )
605
- }
666
+ self . first_ref ( ) . recv ( )
606
667
}
607
668
608
669
fn try_recv ( & self ) -> Option < T > {
609
- match * self {
610
- ( ref p, _) => p. try_recv ( )
611
- }
670
+ self . first_ref ( ) . try_recv ( )
671
+ }
672
+ }
673
+
674
+ impl < T : Send > SendDeferred < T > for MegaPipe < T > {
675
+ fn send_deferred ( & self , val : T ) {
676
+ self . second_ref ( ) . send_deferred ( val)
677
+ }
678
+ fn try_send_deferred ( & self , val : T ) -> bool {
679
+ self . second_ref ( ) . try_send_deferred ( val)
612
680
}
613
681
}
614
682
@@ -1017,4 +1085,39 @@ mod test {
1017
1085
}
1018
1086
}
1019
1087
}
1088
+
1089
+ #[ test]
1090
+ fn send_deferred ( ) {
1091
+ use unstable:: sync:: atomically;
1092
+
1093
+ // Tests no-rescheduling of send_deferred on all types of channels.
1094
+ do run_in_newsched_task {
1095
+ let ( pone, cone) = oneshot ( ) ;
1096
+ let ( pstream, cstream) = stream ( ) ;
1097
+ let ( pshared, cshared) = stream ( ) ;
1098
+ let cshared = SharedChan :: new ( cshared) ;
1099
+ let mp = megapipe ( ) ;
1100
+
1101
+ let pone = Cell :: new ( pone) ;
1102
+ do spawntask { pone. take ( ) . recv ( ) ; }
1103
+ let pstream = Cell :: new ( pstream) ;
1104
+ do spawntask { pstream. take ( ) . recv ( ) ; }
1105
+ let pshared = Cell :: new ( pshared) ;
1106
+ do spawntask { pshared. take ( ) . recv ( ) ; }
1107
+ let p_mp = Cell :: new ( mp. clone ( ) ) ;
1108
+ do spawntask { p_mp. take ( ) . recv ( ) ; }
1109
+
1110
+ let cs = Cell :: new ( ( cone, cstream, cshared, mp) ) ;
1111
+ unsafe {
1112
+ do atomically {
1113
+ let ( cone, cstream, cshared, mp) = cs. take ( ) ;
1114
+ cone. send_deferred ( ( ) ) ;
1115
+ cstream. send_deferred ( ( ) ) ;
1116
+ cshared. send_deferred ( ( ) ) ;
1117
+ mp. send_deferred ( ( ) ) ;
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+
1020
1123
}
0 commit comments