auto merge of #14708 : gereeter/rust/faster-sem, r=alexcrichton
Currently, `Sem`, which is used as a building block for all the blocking primitives, uses a very ugly hack to implement `Share` and be able to mutate the stored `WaitQueue` by hiding it all behind a `transmute`d `*()`. This PR replaces all that ugly machinery with `Unsafe`. Beyond being cleaner and not requiring `transmute`, this removes an allocation in the creation and removes an indirection for access.
This commit is contained in:
commit
8e9e484d70
@ -18,6 +18,7 @@
|
|||||||
use std::kinds::marker;
|
use std::kinds::marker;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomics;
|
use std::sync::atomics;
|
||||||
|
use std::ty::Unsafe;
|
||||||
use std::finally::Finally;
|
use std::finally::Finally;
|
||||||
|
|
||||||
use mutex;
|
use mutex;
|
||||||
@ -85,11 +86,8 @@ struct Sem<Q> {
|
|||||||
// n.b, we need Sem to be `Share`, but the WaitQueue type is not send/share
|
// n.b, we need Sem to be `Share`, but the WaitQueue type is not send/share
|
||||||
// (for good reason). We have an internal invariant on this semaphore,
|
// (for good reason). We have an internal invariant on this semaphore,
|
||||||
// however, that the queue is never accessed outside of a locked
|
// however, that the queue is never accessed outside of a locked
|
||||||
// context. For this reason, we shove these behind a pointer which will
|
// context.
|
||||||
// be inferred to be `Share`.
|
inner: Unsafe<SemInner<Q>>
|
||||||
//
|
|
||||||
// FIXME: this requires an extra allocation, which is bad.
|
|
||||||
inner: *()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SemInner<Q> {
|
struct SemInner<Q> {
|
||||||
@ -107,22 +105,20 @@ struct SemGuard<'a, Q> {
|
|||||||
|
|
||||||
impl<Q: Send> Sem<Q> {
|
impl<Q: Send> Sem<Q> {
|
||||||
fn new(count: int, q: Q) -> Sem<Q> {
|
fn new(count: int, q: Q) -> Sem<Q> {
|
||||||
let inner = unsafe {
|
Sem {
|
||||||
mem::transmute(box SemInner {
|
lock: mutex::Mutex::new(),
|
||||||
|
inner: Unsafe::new(SemInner {
|
||||||
waiters: WaitQueue::new(),
|
waiters: WaitQueue::new(),
|
||||||
count: count,
|
count: count,
|
||||||
blocked: q,
|
blocked: q,
|
||||||
})
|
})
|
||||||
};
|
|
||||||
Sem {
|
|
||||||
lock: mutex::Mutex::new(),
|
|
||||||
inner: inner,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn with(&self, f: |&mut SemInner<Q>|) {
|
unsafe fn with(&self, f: |&mut SemInner<Q>|) {
|
||||||
let _g = self.lock.lock();
|
let _g = self.lock.lock();
|
||||||
f(&mut *(self.inner as *mut SemInner<Q>))
|
// This &mut is safe because, due to the lock, we are the only one who can touch the data
|
||||||
|
f(&mut *self.inner.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acquire(&self) {
|
pub fn acquire(&self) {
|
||||||
@ -163,16 +159,6 @@ impl<Q: Send> Sem<Q> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
|
||||||
impl<Q: Send> Drop for Sem<Q> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _waiters: Box<SemInner<Q>> = unsafe {
|
|
||||||
mem::transmute(self.inner)
|
|
||||||
};
|
|
||||||
self.inner = 0 as *();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
impl<'a, Q: Send> Drop for SemGuard<'a, Q> {
|
impl<'a, Q: Send> Drop for SemGuard<'a, Q> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
Loading…
Reference in New Issue
Block a user