@@ -27,6 +27,7 @@ import task;
27
27
export send;
28
28
export recv;
29
29
export peek;
30
+ export select2;
30
31
export chan:: { } ;
31
32
export port:: { } ;
32
33
@@ -46,10 +47,14 @@ native mod rustrt {
46
47
fn port_recv ( dptr : * uint , po : * rust_port ,
47
48
yield : * ctypes:: uintptr_t ,
48
49
killed : * ctypes:: uintptr_t ) ;
50
+ fn rust_port_select ( dptr : * * rust_port , ports : * * rust_port ,
51
+ n_ports : ctypes:: size_t ,
52
+ yield : * ctypes:: uintptr_t ) ;
49
53
}
50
54
51
55
#[ abi = "rust-intrinsic" ]
52
56
native mod rusti {
57
+ // FIXME: This should probably not take a boxed closure
53
58
fn call_with_retptr < T : send > ( & & f: fn @( * uint ) ) -> T ;
54
59
}
55
60
@@ -154,6 +159,45 @@ fn recv_<T: send>(p: *rust_port) -> T {
154
159
ret res;
155
160
}
156
161
162
+ #[ doc = "Receive on one of two ports" ]
163
+ fn select2 < A : send , B : send > (
164
+ p_a : port < A > , p_b : port < B >
165
+ ) -> either:: t < A , B > unsafe {
166
+
167
+ fn select ( dptr : * * rust_port , ports : * * rust_port ,
168
+ n_ports : ctypes:: size_t , yield : * ctypes:: uintptr_t ) {
169
+ rustrt:: rust_port_select ( dptr, ports, n_ports, yield )
170
+ }
171
+
172
+ let ports = [ ] ;
173
+ ports += [ * * * p_a, * * * p_b] ;
174
+ let n_ports = 2 as ctypes:: size_t ;
175
+ let yield = 0 u;
176
+ let yieldp = ptr:: addr_of ( yield ) ;
177
+
178
+ let resport: * rust_port = vec:: as_buf ( ports) { |ports|
179
+ rusti:: call_with_retptr { |retptr|
180
+ select ( unsafe :: reinterpret_cast ( retptr) , ports, n_ports, yieldp)
181
+ }
182
+ } ;
183
+
184
+ if yield != 0 u {
185
+ // Wait for data
186
+ task:: yield ( ) ;
187
+ }
188
+
189
+ // Now we know the port we're supposed to receive from
190
+ assert resport != ptr:: null ( ) ;
191
+
192
+ if resport == * * * p_a {
193
+ either:: left ( recv ( p_a) )
194
+ } else if resport == * * * p_b {
195
+ either:: right ( recv ( p_b) )
196
+ } else {
197
+ fail "unexpected result from rust_port_select" ;
198
+ }
199
+ }
200
+
157
201
#[ doc = "Returns true if there are messages available" ]
158
202
fn peek < T : send > ( p : port < T > ) -> bool {
159
203
rustrt:: rust_port_size ( * * * p) != 0 u as ctypes:: size_t
@@ -218,4 +262,80 @@ fn test_peek() {
218
262
assert peek( po) ;
219
263
recv ( po) ;
220
264
assert ! peek( po) ;
221
- }
265
+ }
266
+
267
+ #[ test]
268
+ fn test_select2_available ( ) {
269
+ let po_a = port ( ) ;
270
+ let po_b = port ( ) ;
271
+ let ch_a = chan ( po_a) ;
272
+ let ch_b = chan ( po_b) ;
273
+
274
+ send ( ch_a, "a" ) ;
275
+
276
+ assert select2( po_a, po_b) == either:: left ( "a" ) ;
277
+
278
+ send ( ch_b, "b" ) ;
279
+
280
+ assert select2( po_a, po_b) == either:: right ( "b" ) ;
281
+ }
282
+
283
+ #[ test]
284
+ fn test_select2_rendezvous ( ) {
285
+ let po_a = port ( ) ;
286
+ let po_b = port ( ) ;
287
+ let ch_a = chan ( po_a) ;
288
+ let ch_b = chan ( po_b) ;
289
+
290
+ iter:: repeat ( 10 u) { ||
291
+ task:: spawn { ||
292
+ iter:: repeat ( 10 u) { || task:: yield ( ) }
293
+ send ( ch_a, "a" ) ;
294
+ } ;
295
+
296
+ assert select2( po_a, po_b) == either:: left ( "a" ) ;
297
+
298
+ task:: spawn { ||
299
+ iter:: repeat ( 10 u) { || task:: yield ( ) }
300
+ send ( ch_b, "b" ) ;
301
+ } ;
302
+
303
+ assert select2( po_a, po_b) == either:: right ( "b" ) ;
304
+ }
305
+ }
306
+
307
+ #[ test]
308
+ fn test_select2_stress ( ) {
309
+ let po_a = port ( ) ;
310
+ let po_b = port ( ) ;
311
+ let ch_a = chan ( po_a) ;
312
+ let ch_b = chan ( po_b) ;
313
+
314
+ let msgs = 100 u;
315
+ let times = 4 u;
316
+
317
+ iter:: repeat ( times) { ||
318
+ task:: spawn { ||
319
+ iter:: repeat ( msgs) { ||
320
+ send ( ch_a, "a" )
321
+ }
322
+ } ;
323
+ task:: spawn { ||
324
+ iter:: repeat ( msgs) { ||
325
+ send ( ch_b, "b" )
326
+ }
327
+ } ;
328
+ }
329
+
330
+ let as = 0 ;
331
+ let bs = 0 ;
332
+ iter:: repeat ( msgs * times * 2 u) { ||
333
+ alt check select2 ( po_a, po_b) {
334
+ either:: left ( "a" ) { as += 1 }
335
+ either:: right ( "b" ) { bs += 1 }
336
+ }
337
+ }
338
+
339
+ assert as == 400 ;
340
+ assert bs == 400 ;
341
+ }
0 commit comments