@@ -113,27 +113,29 @@ type buffer<T: send> = {
113
113
114
114
struct packet_header {
115
115
let mut state : state ;
116
- let mut blocked_task: option < * rust_task > ;
116
+ let mut blocked_task: * rust_task ;
117
117
118
118
// This is a reinterpret_cast of a ~buffer, that can also be cast
119
119
// to a buffer_header if need be.
120
120
let mut buffer: * libc:: c_void ;
121
121
122
122
new ( ) {
123
123
self . state = empty;
124
- self . blocked_task = none ;
124
+ self . blocked_task = ptr :: null ( ) ;
125
125
self . buffer = ptr:: null ( ) ;
126
126
}
127
127
128
128
// Returns the old state.
129
129
unsafe fn mark_blocked ( this : * rust_task ) -> state {
130
- self . blocked_task = some ( this) ;
130
+ rustrt:: rust_task_ref ( this) ;
131
+ let old_task = swap_task ( self . blocked_task , this) ;
132
+ assert old_task. is_null ( ) ;
131
133
swap_state_acq ( self . state , blocked)
132
134
}
133
135
134
136
unsafe fn unblock ( ) {
135
- assert self . state != blocked || self . blocked_task != none ;
136
- self . blocked_task = none ;
137
+ let old_task = swap_task ( self . blocked_task , ptr :: null ( ) ) ;
138
+ if !old_task . is_null ( ) { rustrt :: rust_task_deref ( old_task ) }
137
139
alt swap_state_acq ( self . state , empty) {
138
140
empty | blocked => ( ) ,
139
141
terminated => self . state = terminated,
@@ -240,12 +242,26 @@ fn atomic_sub_rel(&dst: int, src: int) -> int {
240
242
rusti:: atomic_sub_rel ( dst, src)
241
243
}
242
244
245
+ #[ doc( hidden) ]
246
+ fn swap_task ( & dst: * rust_task , src : * rust_task ) -> * rust_task {
247
+ // It might be worth making both acquire and release versions of
248
+ // this.
249
+ unsafe {
250
+ reinterpret_cast ( rusti:: atomic_xchng (
251
+ * ( ptr:: mut_addr_of ( dst) as * mut int ) ,
252
+ src as int ) )
253
+ }
254
+ }
255
+
243
256
#[ doc( hidden) ]
244
257
type rust_task = libc:: c_void ;
245
258
246
259
extern mod rustrt {
247
260
#[ rust_stack]
248
261
fn rust_get_task ( ) -> * rust_task ;
262
+ #[ rust_stack]
263
+ fn rust_task_ref ( task : * rust_task ) ;
264
+ fn rust_task_deref ( task : * rust_task ) ;
249
265
250
266
#[ rust_stack]
251
267
fn task_clear_event_reject ( task : * rust_task ) ;
@@ -334,10 +350,11 @@ fn send<T: send, Tbuffer: send>(-p: send_packet_buffered<T, Tbuffer>,
334
350
full => fail ~"duplicate send",
335
351
blocked => {
336
352
debug ! { "waking up task for %?" , p_} ;
337
- alt p. header . blocked_task {
338
- some ( task) => rustrt:: task_signal_event (
339
- task, ptr:: addr_of ( p. header ) as * libc:: c_void ) ,
340
- none => debug ! { "just kidding!" }
353
+ let old_task = swap_task ( p. header . blocked_task , ptr:: null ( ) ) ;
354
+ if !old_task. is_null ( ) {
355
+ rustrt:: task_signal_event (
356
+ old_task, ptr:: addr_of ( p. header ) as * libc:: c_void ) ;
357
+ rustrt:: rust_task_deref ( old_task) ;
341
358
}
342
359
343
360
// The receiver will eventually clean this up.
@@ -372,7 +389,9 @@ fn try_recv<T: send, Tbuffer: send>(-p: recv_packet_buffered<T, Tbuffer>)
372
389
let p = unsafe { & * p_ } ;
373
390
let this = rustrt:: rust_get_task ( ) ;
374
391
rustrt:: task_clear_event_reject ( this) ;
375
- p. header . blocked_task = some ( this) ;
392
+ rustrt:: rust_task_ref ( this) ;
393
+ let old_task = swap_task ( p. header . blocked_task , this) ;
394
+ assert old_task. is_null ( ) ;
376
395
let mut first = true ;
377
396
let mut count = SPIN_COUNT ;
378
397
loop {
@@ -402,14 +421,22 @@ fn try_recv<T: send, Tbuffer: send>(-p: recv_packet_buffered<T, Tbuffer>)
402
421
full => {
403
422
let mut payload = none;
404
423
payload <-> p. payload ;
405
- p. header . blocked_task = none;
424
+ let old_task = swap_task ( p. header . blocked_task , ptr:: null ( ) ) ;
425
+ if !old_task. is_null ( ) {
426
+ rustrt:: rust_task_deref ( old_task) ;
427
+ }
406
428
p. header . state = empty;
407
429
return some ( option:: unwrap ( payload) )
408
430
}
409
431
terminated => {
410
432
// This assert detects when we've accidentally unsafely
411
433
// casted too big of a number to a state.
412
434
assert old_state == terminated;
435
+
436
+ let old_task = swap_task ( p. header . blocked_task , ptr:: null ( ) ) ;
437
+ if !old_task. is_null ( ) {
438
+ rustrt:: rust_task_deref ( old_task) ;
439
+ }
413
440
return none;
414
441
}
415
442
}
@@ -437,17 +464,18 @@ fn sender_terminate<T: send>(p: *packet<T>) {
437
464
let p = unsafe { & * p } ;
438
465
alt swap_state_rel ( p. header . state , terminated) {
439
466
empty => {
467
+ assert p. header . blocked_task . is_null ( ) ;
440
468
// The receiver will eventually clean up.
441
469
//unsafe { forget(p) }
442
470
}
443
471
blocked => {
444
472
// wake up the target
445
- alt p. header . blocked_task {
446
- some ( target ) =>
473
+ let old_task = swap_task ( p. header . blocked_task , ptr :: null ( ) ) ;
474
+ if !old_task . is_null ( ) {
447
475
rustrt:: task_signal_event (
448
- target ,
449
- ptr:: addr_of ( p. header ) as * libc:: c_void ) ,
450
- none => { debug ! { "receiver is already shutting down" } }
476
+ old_task ,
477
+ ptr:: addr_of ( p. header ) as * libc:: c_void ) ;
478
+ rustrt :: rust_task_deref ( old_task ) ;
451
479
}
452
480
// The receiver will eventually clean up.
453
481
//unsafe { forget(p) }
@@ -457,6 +485,7 @@ fn sender_terminate<T: send>(p: *packet<T>) {
457
485
fail ~"you dun goofed"
458
486
}
459
487
terminated => {
488
+ assert p. header . blocked_task . is_null ( ) ;
460
489
// I have to clean up, use drop_glue
461
490
}
462
491
}
@@ -465,7 +494,7 @@ fn sender_terminate<T: send>(p: *packet<T>) {
465
494
#[ doc( hidden) ]
466
495
fn receiver_terminate < T : send > ( p : * packet < T > ) {
467
496
let p = unsafe { & * p } ;
468
- assert p. header . blocked_task == none ;
497
+ assert p. header . blocked_task . is_null ( ) ;
469
498
alt swap_state_rel ( p. header . state , terminated) {
470
499
empty => {
471
500
// the sender will clean up
0 commit comments