Skip to content

Commit b81da27

Browse files
committed
libstd: add an RAII utility for sys_common::mutex::Mutex
Signed-off-by: NODA, Kai <nodakai@gmail.com>
1 parent 0f8f490 commit b81da27

File tree

9 files changed

+73
-69
lines changed

9 files changed

+73
-69
lines changed

src/libstd/io/lazy.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ pub struct Lazy<T> {
2020
init: fn() -> Arc<T>,
2121
}
2222

23+
#[inline]
24+
const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
25+
2326
unsafe impl<T> Sync for Lazy<T> {}
2427

2528
impl<T: Send + Sync + 'static> Lazy<T> {
@@ -33,17 +36,15 @@ impl<T: Send + Sync + 'static> Lazy<T> {
3336

3437
pub fn get(&'static self) -> Option<Arc<T>> {
3538
unsafe {
36-
self.lock.lock();
39+
let _guard = self.lock.lock();
3740
let ptr = self.ptr.get();
38-
let ret = if ptr.is_null() {
41+
if ptr.is_null() {
3942
Some(self.init())
40-
} else if ptr as usize == 1 {
43+
} else if ptr == done() {
4144
None
4245
} else {
4346
Some((*ptr).clone())
44-
};
45-
self.lock.unlock();
46-
return ret
47+
}
4748
}
4849
}
4950

@@ -53,10 +54,10 @@ impl<T: Send + Sync + 'static> Lazy<T> {
5354
// the at exit handler). Otherwise we just return the freshly allocated
5455
// `Arc`.
5556
let registered = sys_common::at_exit(move || {
56-
self.lock.lock();
57-
let ptr = self.ptr.get();
58-
self.ptr.set(1 as *mut _);
59-
self.lock.unlock();
57+
let ptr = {
58+
let _guard = self.lock.lock();
59+
self.ptr.replace(done())
60+
};
6061
drop(Box::from_raw(ptr))
6162
});
6263
let ret = (self.init)();

src/libstd/sync/mutex.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl<T: ?Sized> Mutex<T> {
227227
#[stable(feature = "rust1", since = "1.0.0")]
228228
pub fn lock(&self) -> LockResult<MutexGuard<T>> {
229229
unsafe {
230-
self.inner.lock();
230+
self.inner.raw_lock();
231231
MutexGuard::new(self)
232232
}
233233
}
@@ -454,7 +454,7 @@ impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
454454
fn drop(&mut self) {
455455
unsafe {
456456
self.__lock.poison.done(&self.__poison);
457-
self.__lock.inner.unlock();
457+
self.__lock.inner.raw_unlock();
458458
}
459459
}
460460
}

src/libstd/sys/redox/args.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,15 @@ mod imp {
7373
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
7474
}).collect();
7575

76-
LOCK.lock();
76+
let _guard = LOCK.lock();
7777
let ptr = get_global_ptr();
7878
assert!((*ptr).is_none());
7979
(*ptr) = Some(box args);
80-
LOCK.unlock();
8180
}
8281

8382
pub unsafe fn cleanup() {
84-
LOCK.lock();
83+
let _guard = LOCK.lock();
8584
*get_global_ptr() = None;
86-
LOCK.unlock();
8785
}
8886

8987
pub fn args() -> Args {
@@ -96,16 +94,14 @@ mod imp {
9694

9795
fn clone() -> Option<Vec<Vec<u8>>> {
9896
unsafe {
99-
LOCK.lock();
97+
let _guard = LOCK.lock();
10098
let ptr = get_global_ptr();
101-
let ret = (*ptr).as_ref().map(|s| (**s).clone());
102-
LOCK.unlock();
103-
return ret
99+
(*ptr).as_ref().map(|s| (**s).clone())
104100
}
105101
}
106102

107-
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
108-
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
103+
unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
104+
mem::transmute(&GLOBAL_ARGS_PTR)
109105
}
110106

111107
}

src/libstd/sys/unix/args.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,15 @@ mod imp {
8282
static LOCK: Mutex = Mutex::new();
8383

8484
pub unsafe fn init(argc: isize, argv: *const *const u8) {
85-
LOCK.lock();
85+
let _guard = LOCK.lock();
8686
ARGC = argc;
8787
ARGV = argv;
88-
LOCK.unlock();
8988
}
9089

9190
pub unsafe fn cleanup() {
92-
LOCK.lock();
91+
let _guard = LOCK.lock();
9392
ARGC = 0;
9493
ARGV = ptr::null();
95-
LOCK.unlock();
9694
}
9795

9896
pub fn args() -> Args {
@@ -104,13 +102,11 @@ mod imp {
104102

105103
fn clone() -> Vec<OsString> {
106104
unsafe {
107-
LOCK.lock();
108-
let ret = (0..ARGC).map(|i| {
105+
let _guard = LOCK.lock();
106+
(0..ARGC).map(|i| {
109107
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
110108
OsStringExt::from_vec(cstr.to_bytes().to_vec())
111-
}).collect();
112-
LOCK.unlock();
113-
return ret
109+
}).collect()
114110
}
115111
}
116112
}

src/libstd/sys/unix/os.rs

+9-17
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,9 @@ pub unsafe fn environ() -> *mut *const *const c_char {
409409
/// environment variables of the current process.
410410
pub fn env() -> Env {
411411
unsafe {
412-
ENV_LOCK.lock();
412+
let _guard = ENV_LOCK.lock();
413413
let mut environ = *environ();
414414
if environ == ptr::null() {
415-
ENV_LOCK.unlock();
416415
panic!("os::env() failure getting env string from OS: {}",
417416
io::Error::last_os_error());
418417
}
@@ -423,12 +422,10 @@ pub fn env() -> Env {
423422
}
424423
environ = environ.offset(1);
425424
}
426-
let ret = Env {
425+
return Env {
427426
iter: result.into_iter(),
428427
_dont_send_or_sync_me: PhantomData,
429-
};
430-
ENV_LOCK.unlock();
431-
return ret
428+
}
432429
}
433430

434431
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
@@ -452,15 +449,14 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
452449
// always None as well
453450
let k = CString::new(k.as_bytes())?;
454451
unsafe {
455-
ENV_LOCK.lock();
452+
let _guard = ENV_LOCK.lock();
456453
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
457454
let ret = if s.is_null() {
458455
None
459456
} else {
460457
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
461458
};
462-
ENV_LOCK.unlock();
463-
return Ok(ret)
459+
Ok(ret)
464460
}
465461
}
466462

@@ -469,21 +465,17 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
469465
let v = CString::new(v.as_bytes())?;
470466

471467
unsafe {
472-
ENV_LOCK.lock();
473-
let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ());
474-
ENV_LOCK.unlock();
475-
return ret
468+
let _guard = ENV_LOCK.lock();
469+
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
476470
}
477471
}
478472

479473
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
480474
let nbuf = CString::new(n.as_bytes())?;
481475

482476
unsafe {
483-
ENV_LOCK.lock();
484-
let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ());
485-
ENV_LOCK.unlock();
486-
return ret
477+
let _guard = ENV_LOCK.lock();
478+
cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
487479
}
488480
}
489481

src/libstd/sys_common/at_exit_imp.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
1515
use boxed::FnBox;
1616
use ptr;
17+
use mem;
1718
use sys_common::mutex::Mutex;
1819

1920
type Queue = Vec<Box<FnBox()>>;
@@ -25,6 +26,8 @@ type Queue = Vec<Box<FnBox()>>;
2526
static LOCK: Mutex = Mutex::new();
2627
static mut QUEUE: *mut Queue = ptr::null_mut();
2728

29+
const DONE: *mut Queue = 1_usize as *mut _;
30+
2831
// The maximum number of times the cleanup routines will be run. While running
2932
// the at_exit closures new ones may be registered, and this count is the number
3033
// of times the new closures will be allowed to register successfully. After
@@ -35,7 +38,7 @@ unsafe fn init() -> bool {
3538
if QUEUE.is_null() {
3639
let state: Box<Queue> = box Vec::new();
3740
QUEUE = Box::into_raw(state);
38-
} else if QUEUE as usize == 1 {
41+
} else if QUEUE == DONE {
3942
// can't re-init after a cleanup
4043
return false
4144
}
@@ -44,18 +47,18 @@ unsafe fn init() -> bool {
4447
}
4548

4649
pub fn cleanup() {
47-
for i in 0..ITERS {
50+
for i in 1..=ITERS {
4851
unsafe {
49-
LOCK.lock();
50-
let queue = QUEUE;
51-
QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
52-
LOCK.unlock();
52+
let queue = {
53+
let _guard = LOCK.lock();
54+
mem::replace(&mut QUEUE, if i == ITERS { DONE } else { ptr::null_mut() })
55+
};
5356

5457
// make sure we're not recursively cleaning up
55-
assert!(queue as usize != 1);
58+
assert!(queue != DONE);
5659

5760
// If we never called init, not need to cleanup!
58-
if queue as usize != 0 {
61+
if !queue.is_null() {
5962
let queue: Box<Queue> = Box::from_raw(queue);
6063
for to_run in *queue {
6164
to_run();
@@ -66,15 +69,13 @@ pub fn cleanup() {
6669
}
6770

6871
pub fn push(f: Box<FnBox()>) -> bool {
69-
let mut ret = true;
7072
unsafe {
71-
LOCK.lock();
73+
let _guard = LOCK.lock();
7274
if init() {
7375
(*QUEUE).push(f);
76+
true
7477
} else {
75-
ret = false;
78+
false
7679
}
77-
LOCK.unlock();
7880
}
79-
ret
8081
}

src/libstd/sys_common/mutex.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ impl Mutex {
3737
/// Behavior is undefined if the mutex has been moved between this and any
3838
/// previous function call.
3939
#[inline]
40-
pub unsafe fn lock(&self) { self.0.lock() }
40+
pub unsafe fn raw_lock(&self) { self.0.lock() }
41+
42+
/// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
43+
/// will be unlocked.
44+
#[inline]
45+
pub unsafe fn lock(&self) -> MutexGuard {
46+
self.raw_lock();
47+
MutexGuard(&self.0)
48+
}
4149

4250
/// Attempts to lock the mutex without blocking, returning whether it was
4351
/// successfully acquired or not.
@@ -51,8 +59,11 @@ impl Mutex {
5159
///
5260
/// Behavior is undefined if the current thread does not actually hold the
5361
/// mutex.
62+
///
63+
/// Consider switching from the pair of raw_lock() and raw_unlock() to
64+
/// lock() whenever possible.
5465
#[inline]
55-
pub unsafe fn unlock(&self) { self.0.unlock() }
66+
pub unsafe fn raw_unlock(&self) { self.0.unlock() }
5667

5768
/// Deallocates all resources associated with this mutex.
5869
///
@@ -64,3 +75,14 @@ impl Mutex {
6475

6576
// not meant to be exported to the outside world, just the containing module
6677
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }
78+
79+
#[must_use]
80+
/// A simple RAII utility for the above Mutex without the poisoning semantics.
81+
pub struct MutexGuard<'a>(&'a imp::Mutex);
82+
83+
impl<'a> Drop for MutexGuard<'a> {
84+
#[inline]
85+
fn drop(&mut self) {
86+
unsafe { self.0.unlock(); }
87+
}
88+
}

src/libstd/sys_common/thread_local.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,12 @@ impl StaticKey {
162162
// we just simplify the whole branch.
163163
if imp::requires_synchronized_create() {
164164
static INIT_LOCK: Mutex = Mutex::new();
165-
INIT_LOCK.lock();
165+
let _guard = INIT_LOCK.lock();
166166
let mut key = self.key.load(Ordering::SeqCst);
167167
if key == 0 {
168168
key = imp::create(self.dtor) as usize;
169169
self.key.store(key, Ordering::SeqCst);
170170
}
171-
INIT_LOCK.unlock();
172171
rtassert!(key != 0);
173172
return key
174173
}

src/libstd/thread/mod.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -935,20 +935,17 @@ impl ThreadId {
935935
static mut COUNTER: u64 = 0;
936936

937937
unsafe {
938-
GUARD.lock();
938+
let _guard = GUARD.lock();
939939

940940
// If we somehow use up all our bits, panic so that we're not
941941
// covering up subtle bugs of IDs being reused.
942942
if COUNTER == ::u64::MAX {
943-
GUARD.unlock();
944943
panic!("failed to generate unique thread ID: bitspace exhausted");
945944
}
946945

947946
let id = COUNTER;
948947
COUNTER += 1;
949948

950-
GUARD.unlock();
951-
952949
ThreadId(id)
953950
}
954951
}

0 commit comments

Comments
 (0)