@@ -107,20 +107,9 @@ fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool {
107
107
* Shared state & exclusive ARC
108
108
****************************************************************************/
109
109
110
- struct UnwrapProtoInner {
111
- contents : Option < ( comm:: ChanOne < ( ) > , comm:: PortOne < bool > ) > ,
112
- }
113
-
114
- // An unwrapper uses this protocol to communicate with the "other" task that
115
- // drops the last refcount on an arc. Unfortunately this can't be a proper
116
- // pipe protocol because the unwrapper has to access both stages at once.
117
- type UnwrapProto = ~UnwrapProtoInner ;
118
-
119
110
struct ArcData < T > {
120
111
mut count : libc:: intptr_t ,
121
- mut unwrapper : int , // either a UnwrapProto or 0
122
- // FIXME(#3224) should be able to make this non-option to save memory, and
123
- // in unwrap() use "let ~ArcData { data: result, _ } = thing" to unwrap it
112
+ // FIXME(#3224) should be able to make this non-option to save memory
124
113
mut data : Option < T > ,
125
114
}
126
115
@@ -131,37 +120,13 @@ struct ArcDestruct<T> {
131
120
impl < T > Drop for ArcDestruct < T > {
132
121
fn finalize ( & self ) {
133
122
unsafe {
134
- if self . data . is_null ( ) {
135
- return ; // Happens when destructing an unwrapper's handle.
136
- }
137
123
do task:: unkillable {
138
124
let data : ~ArcData <T > = cast:: reinterpret_cast ( & self . data ) ;
139
125
let new_count =
140
126
intrinsics:: atomic_xsub ( & mut data. count , 1 ) - 1 ;
141
127
assert new_count >= 0 ;
142
128
if new_count == 0 {
143
- // Were we really last, or should we hand off to an
144
- // unwrapper? It's safe to not xchg because the unwrapper
145
- // will set the unwrap lock *before* dropping his/her
146
- // reference. In effect, being here means we're the only
147
- // *awake* task with the data.
148
- if data. unwrapper != 0 {
149
- let mut p: UnwrapProto =
150
- cast:: reinterpret_cast ( & data. unwrapper ) ;
151
- let ( message, response) =
152
- option:: swap_unwrap ( & mut p. contents ) ;
153
- // Send 'ready' and wait for a response.
154
- comm:: send_one ( message, ( ) ) ;
155
- // Unkillable wait. Message guaranteed to come.
156
- if comm:: recv_one ( response) {
157
- // Other task got the data.
158
- cast:: forget ( data) ;
159
- } else {
160
- // Other task was killed. drop glue takes over.
161
- }
162
- } else {
163
- // drop glue takes over.
164
- }
129
+ // drop glue takes over.
165
130
} else {
166
131
cast:: forget ( data) ;
167
132
}
@@ -176,79 +141,6 @@ fn ArcDestruct<T>(data: *libc::c_void) -> ArcDestruct<T> {
176
141
}
177
142
}
178
143
179
- pub unsafe fn unwrap_shared_mutable_state < T : Owned > ( rc : SharedMutableState < T > )
180
- -> T {
181
- struct DeathThroes < T > {
182
- mut ptr : Option < ~ArcData < T > > ,
183
- mut response : Option < comm:: ChanOne < bool > > ,
184
- }
185
-
186
- impl < T > Drop for DeathThroes < T > {
187
- fn finalize ( & self ) {
188
- unsafe {
189
- let response = option:: swap_unwrap ( & mut self . response ) ;
190
- // In case we get killed early, we need to tell the person who
191
- // tried to wake us whether they should hand-off the data to
192
- // us.
193
- if task:: failing ( ) {
194
- comm:: send_one ( response, false ) ;
195
- // Either this swap_unwrap or the one below (at "Got
196
- // here") ought to run.
197
- cast:: forget ( option:: swap_unwrap ( & mut self . ptr ) ) ;
198
- } else {
199
- assert self. ptr . is_none ( ) ;
200
- comm:: send_one ( response, true ) ;
201
- }
202
- }
203
- }
204
- }
205
-
206
- do task:: unkillable {
207
- let ptr : ~ArcData <T > = cast:: reinterpret_cast ( & rc. data ) ;
208
- let ( p1, c1) = comm:: oneshot ( ) ; // ()
209
- let ( p2, c2) = comm:: oneshot ( ) ; // bool
210
- let mut server: UnwrapProto = ~UnwrapProtoInner {
211
- contents : Some ( ( c1, p2) )
212
- } ;
213
- let serverp: int = cast:: transmute ( server) ;
214
- // Try to put our server end in the unwrapper slot.
215
- if compare_and_swap ( & mut ptr. unwrapper , 0 , serverp) {
216
- // Got in. Step 0: Tell destructor not to run. We are now it.
217
- rc. data = ptr:: null ( ) ;
218
- // Step 1 - drop our own reference.
219
- let new_count = intrinsics:: atomic_xsub ( & mut ptr. count , 1 ) - 1 ;
220
- //assert new_count >= 0;
221
- if new_count == 0 {
222
- // We were the last owner. Can unwrap immediately.
223
- // Also we have to free the server endpoints.
224
- let _server: UnwrapProto = cast:: transmute ( serverp) ;
225
- option:: swap_unwrap ( & mut ptr. data )
226
- // drop glue takes over.
227
- } else {
228
- // The *next* person who sees the refcount hit 0 will wake us.
229
- let end_result =
230
- DeathThroes { ptr : Some ( ptr) ,
231
- response : Some ( c2) } ;
232
- let mut p1 = Some ( p1) ; // argh
233
- do task:: rekillable {
234
- comm : : recv_one ( option:: swap_unwrap ( & mut p1) ) ;
235
- }
236
- // Got here. Back in the 'unkillable' without getting killed.
237
- // Recover ownership of ptr, then take the data out.
238
- let ptr = option:: swap_unwrap ( & mut end_result. ptr ) ;
239
- option:: swap_unwrap ( & mut ptr. data )
240
- // drop glue takes over.
241
- }
242
- } else {
243
- // Somebody else was trying to unwrap. Avoid guaranteed deadlock.
244
- cast : : forget ( ptr) ;
245
- // Also we have to free the (rejected) server endpoints.
246
- let _server: UnwrapProto = cast:: transmute ( serverp) ;
247
- fail ! ( ~"Another task is already unwrapping this ARC !");
248
- }
249
- }
250
- }
251
-
252
144
/**
253
145
* COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc.
254
146
*
@@ -259,7 +151,7 @@ pub type SharedMutableState<T> = ArcDestruct<T>;
259
151
260
152
pub unsafe fn shared_mutable_state < T : Owned > ( data : T ) ->
261
153
SharedMutableState < T > {
262
- let data = ~ArcData { count: 1, unwrapper: 0, data: Some(data) };
154
+ let data = ~ArcData { count : 1 , data : Some ( data) } ;
263
155
unsafe {
264
156
let ptr = cast:: transmute ( data) ;
265
157
ArcDestruct ( ptr)
@@ -413,22 +305,14 @@ pub impl<T:Owned> Exclusive<T> {
413
305
}
414
306
}
415
307
416
- // FIXME(#3724) make this a by-move method on the exclusive
417
- pub fn unwrap_exclusive<T:Owned>(arc: Exclusive<T>) -> T {
418
- let Exclusive { x: x } = arc;
419
- let inner = unsafe { unwrap_shared_mutable_state(x) };
420
- let ExData { data: data, _ } = inner;
421
- data
422
- }
423
-
424
308
#[ cfg( test) ]
425
309
pub mod tests {
426
310
use core:: option:: { None , Some } ;
427
311
428
312
use cell:: Cell ;
429
313
use comm;
430
314
use option;
431
- use private::{ exclusive, unwrap_exclusive} ;
315
+ use private:: exclusive;
432
316
use result;
433
317
use task;
434
318
use uint;
@@ -479,70 +363,4 @@ pub mod tests {
479
363
assert * one == 1 ;
480
364
}
481
365
}
482
-
483
- #[test]
484
- pub fn exclusive_unwrap_basic() {
485
- let x = exclusive(~~" hello");
486
- assert unwrap_exclusive(x) == ~~" hello";
487
- }
488
-
489
- #[test]
490
- pub fn exclusive_unwrap_contended() {
491
- let x = exclusive(~~" hello");
492
- let x2 = Cell(x.clone());
493
- do task::spawn {
494
- let x2 = x2.take();
495
- do x2.with |_hello| { }
496
- task::yield();
497
- }
498
- assert unwrap_exclusive(x) == ~~" hello";
499
-
500
- // Now try the same thing, but with the child task blocking.
501
- let x = exclusive(~~" hello");
502
- let x2 = Cell(x.clone());
503
- let mut res = None;
504
- do task::task().future_result(|+r| res = Some(r)).spawn {
505
- let x2 = x2.take();
506
- assert unwrap_exclusive(x2) == ~~" hello";
507
- }
508
- // Have to get rid of our reference before blocking.
509
- { let _x = x; } // FIXME(#3161) util::ignore doesn't work here
510
- let res = option::swap_unwrap(&mut res);
511
- res.recv();
512
- }
513
-
514
- #[test] #[should_fail] #[ignore(cfg(windows))]
515
- pub fn exclusive_unwrap_conflict() {
516
- let x = exclusive(~~" hello");
517
- let x2 = Cell(x.clone());
518
- let mut res = None;
519
- do task::task().future_result(|+r| res = Some(r)).spawn {
520
- let x2 = x2.take();
521
- assert unwrap_exclusive(x2) == ~~" hello";
522
- }
523
- assert unwrap_exclusive(x) == ~~" hello";
524
- let res = option::swap_unwrap(&mut res);
525
- // See #4689 for why this can't be just " res. recv( ) ".
526
- assert res.recv() == task::Success;
527
- }
528
-
529
- #[test] #[ignore(cfg(windows))]
530
- pub fn exclusive_unwrap_deadlock() {
531
- // This is not guaranteed to get to the deadlock before being killed,
532
- // but it will show up sometimes, and if the deadlock were not there,
533
- // the test would nondeterministically fail.
534
- let result = do task::try {
535
- // a task that has two references to the same exclusive will
536
- // deadlock when it unwraps. nothing to be done about that.
537
- let x = exclusive(~~" hello" ) ;
538
- let x2 = x. clone ( ) ;
539
- do task:: spawn {
540
- for 10 . times { task : : yield ( ) ; } // try to let the unwrapper go
541
- fail ! ( ) ; // punt it awake from its deadlock
542
- }
543
- let _z = unwrap_exclusive ( x) ;
544
- do x2. with |_hello| { }
545
- } ;
546
- assert result. is_err ( ) ;
547
- }
548
366
}
0 commit comments