2014-01-16 19:53:42 -08:00
|
|
|
/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
|
|
* EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* The views and conclusions contained in the software and documentation are
|
|
|
|
* those of the authors and should not be interpreted as representing official
|
|
|
|
* policies, either expressed or implied, of Dmitry Vyukov.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//! A mostly lock-free multi-producer, single consumer queue.
|
|
|
|
//!
|
|
|
|
//! This module implements an intrusive MPSC queue. This queue is incredibly
|
|
|
|
//! unsafe (due to use of unsafe pointers for nodes), and hence is not public.
|
|
|
|
|
|
|
|
// http://www.1024cores.net/home/lock-free-algorithms
|
|
|
|
// /queues/intrusive-mpsc-node-based-queue
|
|
|
|
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
use std::mem;
|
2014-01-16 19:53:42 -08:00
|
|
|
use std::sync::atomics;
|
2014-03-22 00:46:57 -07:00
|
|
|
use std::ty::Unsafe;
|
2014-01-16 19:53:42 -08:00
|
|
|
|
|
|
|
// NB: all links are done as AtomicUint instead of AtomicPtr to allow for static
|
|
|
|
// initialization.
|
|
|
|
|
|
|
|
pub struct Node<T> {
|
2014-03-27 15:10:45 -07:00
|
|
|
pub next: atomics::AtomicUint,
|
|
|
|
pub data: T,
|
2014-01-16 19:53:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DummyNode {
|
2014-03-27 15:10:45 -07:00
|
|
|
pub next: atomics::AtomicUint,
|
2014-01-16 19:53:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Queue<T> {
|
2014-03-27 15:10:45 -07:00
|
|
|
pub head: atomics::AtomicUint,
|
|
|
|
pub tail: Unsafe<*mut Node<T>>,
|
|
|
|
pub stub: DummyNode,
|
2014-01-16 19:53:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Send> Queue<T> {
|
|
|
|
pub fn new() -> Queue<T> {
|
|
|
|
Queue {
|
|
|
|
head: atomics::AtomicUint::new(0),
|
2014-03-22 00:46:57 -07:00
|
|
|
tail: Unsafe::new(0 as *mut Node<T>),
|
2014-01-16 19:53:42 -08:00
|
|
|
stub: DummyNode {
|
|
|
|
next: atomics::AtomicUint::new(0),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-22 00:46:57 -07:00
|
|
|
pub unsafe fn push(&self, node: *mut Node<T>) {
|
2014-01-16 19:53:42 -08:00
|
|
|
(*node).next.store(0, atomics::Release);
|
|
|
|
let prev = self.head.swap(node as uint, atomics::AcqRel);
|
|
|
|
|
|
|
|
// Note that this code is slightly modified to allow static
|
|
|
|
// initialization of these queues with rust's flavor of static
|
|
|
|
// initialization.
|
|
|
|
if prev == 0 {
|
|
|
|
self.stub.next.store(node as uint, atomics::Release);
|
|
|
|
} else {
|
|
|
|
let prev = prev as *mut Node<T>;
|
|
|
|
(*prev).next.store(node as uint, atomics::Release);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// You'll note that the other MPSC queue in std::sync is non-intrusive and
|
|
|
|
/// returns a `PopResult` here to indicate when the queue is inconsistent.
|
|
|
|
/// An "inconsistent state" in the other queue means that a pusher has
|
|
|
|
/// pushed, but it hasn't finished linking the rest of the chain.
|
|
|
|
///
|
|
|
|
/// This queue also suffers from this problem, but I currently haven't been
|
|
|
|
/// able to detangle when this actually happens. This code is translated
|
|
|
|
/// verbatim from the website above, and is more complicated than the
|
|
|
|
/// non-intrusive version.
|
|
|
|
///
|
|
|
|
/// Right now consumers of this queue must be ready for this fact. Just
|
|
|
|
/// because `pop` returns `None` does not mean that there is not data
|
|
|
|
/// on the queue.
|
2014-03-22 00:46:57 -07:00
|
|
|
pub unsafe fn pop(&self) -> Option<*mut Node<T>> {
|
|
|
|
let tail = *self.tail.get();
|
2014-01-16 19:53:42 -08:00
|
|
|
let mut tail = if !tail.is_null() {tail} else {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
mem::transmute(&self.stub)
|
2014-01-16 19:53:42 -08:00
|
|
|
};
|
|
|
|
let mut next = (*tail).next(atomics::Relaxed);
|
|
|
|
if tail as uint == &self.stub as *DummyNode as uint {
|
|
|
|
if next.is_null() {
|
|
|
|
return None;
|
|
|
|
}
|
2014-03-22 00:46:57 -07:00
|
|
|
*self.tail.get() = next;
|
2014-01-16 19:53:42 -08:00
|
|
|
tail = next;
|
|
|
|
next = (*next).next(atomics::Relaxed);
|
|
|
|
}
|
|
|
|
if !next.is_null() {
|
2014-03-22 00:46:57 -07:00
|
|
|
*self.tail.get() = next;
|
2014-01-16 19:53:42 -08:00
|
|
|
return Some(tail);
|
|
|
|
}
|
|
|
|
let head = self.head.load(atomics::Acquire) as *mut Node<T>;
|
|
|
|
if tail != head {
|
|
|
|
return None;
|
|
|
|
}
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
let stub = mem::transmute(&self.stub);
|
2014-01-16 19:53:42 -08:00
|
|
|
self.push(stub);
|
|
|
|
next = (*tail).next(atomics::Relaxed);
|
|
|
|
if !next.is_null() {
|
2014-03-22 00:46:57 -07:00
|
|
|
*self.tail.get() = next;
|
2014-01-16 19:53:42 -08:00
|
|
|
return Some(tail);
|
|
|
|
}
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Send> Node<T> {
|
|
|
|
pub fn new(t: T) -> Node<T> {
|
|
|
|
Node {
|
|
|
|
data: t,
|
|
|
|
next: atomics::AtomicUint::new(0),
|
|
|
|
}
|
|
|
|
}
|
2014-03-22 00:46:57 -07:00
|
|
|
pub unsafe fn next(&self, ord: atomics::Ordering) -> *mut Node<T> {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
mem::transmute::<uint, *mut Node<T>>(self.next.load(ord))
|
2014-01-16 19:53:42 -08:00
|
|
|
}
|
|
|
|
}
|