Skip to content

Commit 89e1db3

Browse files
committed
libstd: Change atomically to use RAII.
1 parent 6bd80f7 commit 89e1db3

File tree

3 files changed

+78
-54
lines changed

3 files changed

+78
-54
lines changed

src/libstd/rt/comm.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ impl<'self, T: Send> SelectPortInner<T> for &'self Port<T> {
565565
impl<'self, T: Send> SelectPort<T> for &'self Port<T> { }
566566

567567
pub struct SharedChan<T> {
568-
// Just like Chan, but a shared AtomicOption instead of Cell
568+
// Just like Chan, but a shared AtomicOption
569569
priv next: UnsafeArc<AtomicOption<StreamChanOne<T>>>
570570
}
571571

@@ -716,7 +716,6 @@ mod test {
716716
use super::*;
717717
use option::*;
718718
use rt::test::*;
719-
use cell::Cell;
720719
use num::Times;
721720
use rt::util;
722721

@@ -1113,7 +1112,7 @@ mod test {
11131112

11141113
#[test]
11151114
fn send_deferred() {
1116-
use unstable::sync::atomically;
1115+
use unstable::sync::atomic;
11171116

11181117
// Tests no-rescheduling of send_deferred on all types of channels.
11191118
do run_in_newsched_task {
@@ -1129,15 +1128,12 @@ mod test {
11291128
let p_mp = mp.clone();
11301129
do spawntask { p_mp.recv(); }
11311130

1132-
let cs = Cell::new((cone, cstream, cshared, mp));
11331131
unsafe {
1134-
atomically(|| {
1135-
let (cone, cstream, cshared, mp) = cs.take();
1136-
cone.send_deferred(());
1137-
cstream.send_deferred(());
1138-
cshared.send_deferred(());
1139-
mp.send_deferred(());
1140-
})
1132+
let _guard = atomic();
1133+
cone.send_deferred(());
1134+
cstream.send_deferred(());
1135+
cshared.send_deferred(());
1136+
mp.send_deferred(());
11411137
}
11421138
}
11431139
}

src/libstd/unstable/dynamic_lib.rs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub mod dl {
140140
use path;
141141
use ptr;
142142
use str;
143-
use unstable::sync::atomically;
143+
use unstable::sync::atomic;
144144
use result::*;
145145

146146
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
@@ -158,25 +158,24 @@ pub mod dl {
158158
static mut lock: Mutex = MUTEX_INIT;
159159
unsafe {
160160
// dlerror isn't thread safe, so we need to lock around this entire
161-
// sequence. `atomically` asserts that we don't do anything that
161+
// sequence. `atomic` asserts that we don't do anything that
162162
// would cause this task to be descheduled, which could deadlock
163163
// the scheduler if it happens while the lock is held.
164164
// FIXME #9105 use a Rust mutex instead of C++ mutexes.
165-
atomically(|| {
166-
lock.lock();
167-
let _old_error = dlerror();
168-
169-
let result = f();
170-
171-
let last_error = dlerror();
172-
let ret = if ptr::null() == last_error {
173-
Ok(result)
174-
} else {
175-
Err(str::raw::from_c_str(last_error))
176-
};
177-
lock.unlock();
178-
ret
179-
})
165+
let _guard = atomic();
166+
lock.lock();
167+
let _old_error = dlerror();
168+
169+
let result = f();
170+
171+
let last_error = dlerror();
172+
let ret = if ptr::null() == last_error {
173+
Ok(result)
174+
} else {
175+
Err(str::raw::from_c_str(last_error))
176+
};
177+
lock.unlock();
178+
ret
180179
}
181180
}
182181

@@ -209,7 +208,7 @@ pub mod dl {
209208
use libc;
210209
use path;
211210
use ptr;
212-
use unstable::sync::atomically;
211+
use unstable::sync::atomic;
213212
use result::*;
214213

215214
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
@@ -226,18 +225,17 @@ pub mod dl {
226225

227226
pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
228227
unsafe {
229-
atomically(|| {
230-
SetLastError(0);
228+
let _guard = atomic();
229+
SetLastError(0);
231230

232-
let result = f();
231+
let result = f();
233232

234-
let error = os::errno();
235-
if 0 == error {
236-
Ok(result)
237-
} else {
238-
Err(format!("Error code {}", error))
239-
}
240-
})
233+
let error = os::errno();
234+
if 0 == error {
235+
Ok(result)
236+
} else {
237+
Err(format!("Error code {}", error))
238+
}
241239
}
242240
}
243241

src/libstd/unstable/sync.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use ptr;
1414
use option::{Option,Some,None};
1515
use task;
1616
use unstable::atomics::{AtomicOption,AtomicUint,Acquire,Release,Relaxed,SeqCst};
17-
use unstable::finally::Finally;
1817
use unstable::mutex::Mutex;
1918
use ops::Drop;
2019
use clone::Clone;
@@ -295,17 +294,44 @@ impl<T> Drop for UnsafeArc<T>{
295294

296295
/****************************************************************************/
297296

297+
pub struct AtomicGuard {
298+
on: bool,
299+
}
300+
301+
impl Drop for AtomicGuard {
302+
fn drop(&mut self) {
303+
use rt::task::{Task, GreenTask, SchedTask};
304+
use rt::local::Local;
305+
306+
if self.on {
307+
unsafe {
308+
let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
309+
match task_opt {
310+
Some(t) => {
311+
match (*t).task_type {
312+
GreenTask(_) => (*t).death.allow_deschedule(),
313+
SchedTask => {}
314+
}
315+
}
316+
None => {}
317+
}
318+
}
319+
}
320+
}
321+
}
322+
298323
/**
299-
* Enables a runtime assertion that no operation in the argument closure shall
300-
* use scheduler operations (deschedule, recv, spawn, etc). This is for use with
301-
* pthread mutexes, which may block the entire scheduler thread, rather than
302-
* just one task, and is hence prone to deadlocks if mixed with descheduling.
324+
* Enables a runtime assertion that no operation while the returned guard is
325+
* live uses scheduler operations (deschedule, recv, spawn, etc). This is for
326+
* use with pthread mutexes, which may block the entire scheduler thread,
327+
* rather than just one task, and is hence prone to deadlocks if mixed with
328+
* descheduling.
303329
*
304330
* NOTE: THIS DOES NOT PROVIDE LOCKING, or any sort of critical-section
305331
* synchronization whatsoever. It only makes sense to use for CPU-local issues.
306332
*/
307333
// FIXME(#8140) should not be pub
308-
pub unsafe fn atomically<U>(f: || -> U) -> U {
334+
pub unsafe fn atomic() -> AtomicGuard {
309335
use rt::task::{Task, GreenTask, SchedTask};
310336
use rt::local::Local;
311337

@@ -314,15 +340,19 @@ pub unsafe fn atomically<U>(f: || -> U) -> U {
314340
Some(t) => {
315341
match (*t).task_type {
316342
GreenTask(_) => {
317-
(|| {
318-
(*t).death.inhibit_deschedule();
319-
f()
320-
}).finally(|| (*t).death.allow_deschedule())
343+
(*t).death.inhibit_deschedule();
344+
return AtomicGuard {
345+
on: true,
346+
};
321347
}
322-
SchedTask => f()
348+
SchedTask => {}
323349
}
324350
}
325-
None => f()
351+
None => {}
352+
}
353+
354+
AtomicGuard {
355+
on: false,
326356
}
327357
}
328358

@@ -481,7 +511,7 @@ mod tests {
481511
use comm;
482512
use option::*;
483513
use prelude::*;
484-
use super::{Exclusive, UnsafeArc, atomically};
514+
use super::{Exclusive, UnsafeArc, atomic};
485515
use task;
486516
use mem::size_of;
487517

@@ -493,10 +523,10 @@ mod tests {
493523
}
494524

495525
#[test]
496-
fn test_atomically() {
526+
fn test_atomic() {
497527
// NB. The whole runtime will abort on an 'atomic-sleep' violation,
498528
// so we can't really test for the converse behaviour.
499-
unsafe { atomically(|| ()) } task::deschedule(); // oughtn't fail
529+
unsafe { let _ = atomic(); } // oughtn't fail
500530
}
501531

502532
#[test]

0 commit comments

Comments
 (0)