@@ -100,3 +100,231 @@ pub fn select2<TA, A: SelectPort<TA>, TB, B: SelectPort<TB>>(mut a: A, mut b: B)
100
100
}
101
101
102
102
*/
103
+
104
+ #[ cfg( test) ]
105
+ mod test {
106
+ use super :: * ;
107
+ use option:: * ;
108
+ use rt:: comm:: * ;
109
+ use rt:: test:: * ;
110
+ use vec:: * ;
111
+ use comm:: GenericChan ;
112
+ use task;
113
+ use cell:: Cell ;
114
+
115
+ #[ test] #[ ignore( cfg( windows) ) ] #[ should_fail]
116
+ fn select_doesnt_get_trolled ( ) {
117
+ select :: < PortOne < ( ) > > ( [ ] ) ;
118
+ }
119
+
120
+ /* non-blocking select tests */
121
+
122
+ #[ cfg( test) ]
123
+ fn select_helper ( num_ports : uint , send_on_chans : & [ uint ] ) {
124
+ // Unfortunately this does not actually test the block_on early-break
125
+ // codepath in select -- racing between the sender and the receiver in
126
+ // separate tasks is necessary to get around the optimistic check.
127
+ let ( ports, chans) = unzip ( from_fn ( num_ports, |_| oneshot :: < ( ) > ( ) ) ) ;
128
+ let mut dead_chans = ~[ ] ;
129
+ let mut ports = ports;
130
+ for chans. consume_iter( ) . enumerate( ) . advance |( i, chan) | {
131
+ if send_on_chans. contains( & i) {
132
+ chan. send( ( ) ) ;
133
+ } else {
134
+ dead_chans. push( chan) ;
135
+ }
136
+ }
137
+ let ready_index = select( ports) ;
138
+ assert ! ( send_on_chans. contains( & ready_index) ) ;
139
+ assert ! ( ports. swap_remove( ready_index) . recv_ready( ) . is_some( ) ) ;
140
+ let _ = dead_chans;
141
+
142
+ // Same thing with streams instead.
143
+ // FIXME(#7971): This should be in a macro but borrowck isn't smart enough.
144
+ let ( ports, chans) = unzip( from_fn( num_ports, |_| stream :: < ( ) > ( ) ) ) ;
145
+ let mut dead_chans = ~[ ] ;
146
+ let mut ports = ports;
147
+ for chans. consume_iter( ) . enumerate( ) . advance |( i, chan) | {
148
+ if send_on_chans. contains( & i) {
149
+ chan. send( ( ) ) ;
150
+ } else {
151
+ dead_chans. push( chan) ;
152
+ }
153
+ }
154
+ let ready_index = select( ports) ;
155
+ assert ! ( send_on_chans. contains( & ready_index) ) ;
156
+ assert ! ( ports. swap_remove( ready_index) . recv_ready( ) . is_some( ) ) ;
157
+ let _ = dead_chans;
158
+ }
159
+
160
+ #[ test]
161
+ fn select_one( ) {
162
+ do run_in_newsched_task { select_helper( 1 , [ 0 ] ) }
163
+ }
164
+
165
+ #[ test]
166
+ fn select_two( ) {
167
+ // NB. I would like to have a test that tests the first one that is
168
+ // ready is the one that's returned, but that can't be reliably tested
169
+ // with the randomized behaviour of optimistic_check.
170
+ do run_in_newsched_task { select_helper( 2 , [ 1 ] ) }
171
+ do run_in_newsched_task { select_helper( 2 , [ 0 ] ) }
172
+ do run_in_newsched_task { select_helper( 2 , [ 1 , 0 ] ) }
173
+ }
174
+
175
+ #[ test]
176
+ fn select_a_lot( ) {
177
+ do run_in_newsched_task { select_helper( 12 , [ 7 , 8 , 9 ] ) }
178
+ }
179
+
180
+ #[ test]
181
+ fn select_stream( ) {
182
+ use util;
183
+ use comm:: GenericChan ;
184
+
185
+ // Sends 10 buffered packets, and uses select to retrieve them all.
186
+ // Puts the port in a different spot in the vector each time.
187
+ do run_in_newsched_task {
188
+ let ( ports, _) = unzip( from_fn( 10 , |_| stream( ) ) ) ;
189
+ let ( port, chan) = stream( ) ;
190
+ for 10 . times { chan. send( 31337 ) ; }
191
+ let mut ports = ports;
192
+ let mut port = Some ( port) ;
193
+ let order = [ 5 u, 0 , 4 , 3 , 2 , 6 , 9 , 8 , 7 , 1 ] ;
194
+ for order. iter( ) . advance |& index| {
195
+ // put the port in the vector at any index
196
+ util:: swap( port. get_mut_ref( ) , & mut ports[ index] ) ;
197
+ assert ! ( select( ports) == index) ;
198
+ // get it back out
199
+ util:: swap( port. get_mut_ref( ) , & mut ports[ index] ) ;
200
+ // NB. Not recv(), because optimistic_check randomly fails.
201
+ let ( data, new_port) = port. take_unwrap ( ) . recv_ready ( ) . unwrap ( ) ;
202
+ assert ! ( data == 31337 ) ;
203
+ port = Some ( new_port) ;
204
+ }
205
+ }
206
+ }
207
+
208
+ #[ test]
209
+ fn select_unkillable ( ) {
210
+ do run_in_newsched_task {
211
+ unsafe { do task : : unkillable { select_helper( 2 , [ 1 ] ) } }
212
+ }
213
+ }
214
+
215
+ /* blocking select tests */
216
+
217
+ #[ test]
218
+ fn select_blocking ( ) {
219
+ select_blocking_helper ( true ) ;
220
+ select_blocking_helper ( false ) ;
221
+
222
+ fn select_blocking_helper ( killable : bool ) {
223
+ do run_in_newsched_task {
224
+ let ( p1, _c) = oneshot ( ) ;
225
+ let ( p2, c2) = oneshot ( ) ;
226
+ let mut ports = [ p1, p2] ;
227
+
228
+ let ( p3, c3) = oneshot ( ) ;
229
+ let ( p4, c4) = oneshot ( ) ;
230
+
231
+ let x = Cell :: new ( ( c2, p3, c4) ) ;
232
+ do task:: spawn {
233
+ let ( c2, p3, c4) = x. take ( ) ;
234
+ p3. recv ( ) ; // handshake parent
235
+ c4. send ( ( ) ) ; // normal receive
236
+ task:: yield ( ) ;
237
+ c2. send ( ( ) ) ; // select receive
238
+ }
239
+
240
+ // Try to block before child sends on c2.
241
+ c3. send ( ( ) ) ;
242
+ p4. recv ( ) ;
243
+ if killable {
244
+ assert ! ( select( ports) == 1 ) ;
245
+ } else {
246
+ unsafe { do task:: unkillable { assert!( select ( ports) == 1 ) ; } }
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ #[ test]
253
+ fn select_racing_senders ( ) {
254
+ static NUM_CHANS : uint = 10 ;
255
+
256
+ select_racing_senders_helper ( true , ~[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ) ;
257
+ select_racing_senders_helper ( false , ~[ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] ) ;
258
+ select_racing_senders_helper ( true , ~[ 0 , 1 , 2 ] ) ;
259
+ select_racing_senders_helper ( false , ~[ 0 , 1 , 2 ] ) ;
260
+ select_racing_senders_helper ( true , ~[ 3 , 4 , 5 , 6 ] ) ;
261
+ select_racing_senders_helper ( false , ~[ 3 , 4 , 5 , 6 ] ) ;
262
+ select_racing_senders_helper ( true , ~[ 7 , 8 , 9 ] ) ;
263
+ select_racing_senders_helper ( false , ~[ 7 , 8 , 9 ] ) ;
264
+
265
+ fn select_racing_senders_helper ( killable : bool , send_on_chans : ~[ uint ] ) {
266
+ use uint;
267
+ use rt:: test:: spawntask_random;
268
+
269
+ do run_in_newsched_task {
270
+ // A bit of stress, since ordinarily this is just smoke and mirrors.
271
+ for 4 . times {
272
+ let send_on_chans = send_on_chans. clone ( ) ;
273
+ do task:: spawn {
274
+ let mut ports = ~[ ] ;
275
+ for uint:: range( 0 , NUM_CHANS ) |i| {
276
+ let ( p, c) = oneshot ( ) ;
277
+ ports. push ( p) ;
278
+ if send_on_chans. contains ( & i) {
279
+ let c = Cell :: new ( c) ;
280
+ do spawntask_random {
281
+ task : : yield ( ) ;
282
+ c. take ( ) . send ( ( ) ) ;
283
+ }
284
+ }
285
+ }
286
+ // nondeterministic result, but should succeed
287
+ if killable {
288
+ select ( ports) ;
289
+ } else {
290
+ unsafe { do task:: unkillable { select( ports) ; } }
291
+ }
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+
298
+ #[ test] #[ ignore( cfg( windows) ) ]
299
+ fn select_killed ( ) {
300
+ do run_in_newsched_task {
301
+ let ( success_p, success_c) = oneshot :: < bool > ( ) ;
302
+ let success_c = Cell :: new ( success_c) ;
303
+ do task:: try {
304
+ unsafe {
305
+ let success_c = Cell :: new ( success_c. take ( ) ) ;
306
+ do task:: unkillable {
307
+ let ( p, c) = oneshot ( ) ;
308
+ let c = Cell :: new ( c) ;
309
+ do task:: spawn {
310
+ let ( dead_ps, dead_cs) = unzip ( from_fn ( 5 , |_| oneshot :: < ( ) > ( ) ) ) ;
311
+ let mut ports = dead_ps;
312
+ select ( ports) ; // should get killed; nothing should leak
313
+ c. take ( ) . send ( ( ) ) ; // must not happen
314
+ // Make sure dead_cs doesn't get closed until after select.
315
+ let _ = dead_cs;
316
+ }
317
+ do task:: spawn {
318
+ fail!( ) ; // should kill sibling awake
319
+ }
320
+
321
+ // wait for killed selector to close (NOT send on) its c.
322
+ // hope to send 'true'.
323
+ success_c. take ( ) . send ( p. try_recv ( ) . is_none ( ) ) ;
324
+ }
325
+ }
326
+ } ;
327
+ assert ! ( success_p. recv( ) ) ;
328
+ }
329
+ }
330
+ }
0 commit comments