Fall out of the std::sync rewrite
This commit is contained in:
parent
71d4e77db8
commit
c3adbd34c4
19 changed files with 99 additions and 188 deletions
|
@ -38,9 +38,8 @@ exceptions = [
|
||||||
"rt/isaac/randport.cpp", # public domain
|
"rt/isaac/randport.cpp", # public domain
|
||||||
"rt/isaac/rand.h", # public domain
|
"rt/isaac/rand.h", # public domain
|
||||||
"rt/isaac/standard.h", # public domain
|
"rt/isaac/standard.h", # public domain
|
||||||
"libstd/sync/mpsc_queue.rs", # BSD
|
"libstd/comm/mpsc_queue.rs", # BSD
|
||||||
"libstd/sync/spsc_queue.rs", # BSD
|
"libstd/comm/spsc_queue.rs", # BSD
|
||||||
"libstd/sync/mpmc_bounded_queue.rs", # BSD
|
|
||||||
"test/bench/shootout-binarytrees.rs", # BSD
|
"test/bench/shootout-binarytrees.rs", # BSD
|
||||||
"test/bench/shootout-chameneos-redux.rs", # BSD
|
"test/bench/shootout-chameneos-redux.rs", # BSD
|
||||||
"test/bench/shootout-fannkuch-redux.rs", # BSD
|
"test/bench/shootout-fannkuch-redux.rs", # BSD
|
||||||
|
|
|
@ -354,6 +354,8 @@ mod select;
|
||||||
mod shared;
|
mod shared;
|
||||||
mod stream;
|
mod stream;
|
||||||
mod sync;
|
mod sync;
|
||||||
|
mod mpsc_queue;
|
||||||
|
mod spsc_queue;
|
||||||
|
|
||||||
/// The receiving-half of Rust's channel type. This half can only be owned by
|
/// The receiving-half of Rust's channel type. This half can only be owned by
|
||||||
/// one task
|
/// one task
|
||||||
|
@ -628,24 +630,26 @@ impl<T: Send> Sender<T> {
|
||||||
#[unstable]
|
#[unstable]
|
||||||
impl<T: Send> Clone for Sender<T> {
|
impl<T: Send> Clone for Sender<T> {
|
||||||
fn clone(&self) -> Sender<T> {
|
fn clone(&self) -> Sender<T> {
|
||||||
let (packet, sleeper) = match *unsafe { self.inner() } {
|
let (packet, sleeper, guard) = match *unsafe { self.inner() } {
|
||||||
Oneshot(ref p) => {
|
Oneshot(ref p) => {
|
||||||
let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
|
let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
|
||||||
unsafe {
|
unsafe {
|
||||||
(*a.get()).postinit_lock();
|
let guard = (*a.get()).postinit_lock();
|
||||||
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
||||||
oneshot::UpSuccess | oneshot::UpDisconnected => (a, None),
|
oneshot::UpSuccess |
|
||||||
oneshot::UpWoke(task) => (a, Some(task))
|
oneshot::UpDisconnected => (a, None, guard),
|
||||||
|
oneshot::UpWoke(task) => (a, Some(task), guard)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stream(ref p) => {
|
Stream(ref p) => {
|
||||||
let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
|
let a = Arc::new(UnsafeCell::new(shared::Packet::new()));
|
||||||
unsafe {
|
unsafe {
|
||||||
(*a.get()).postinit_lock();
|
let guard = (*a.get()).postinit_lock();
|
||||||
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
|
||||||
stream::UpSuccess | stream::UpDisconnected => (a, None),
|
stream::UpSuccess |
|
||||||
stream::UpWoke(task) => (a, Some(task)),
|
stream::UpDisconnected => (a, None, guard),
|
||||||
|
stream::UpWoke(task) => (a, Some(task), guard),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,7 +661,7 @@ impl<T: Send> Clone for Sender<T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(*packet.get()).inherit_blocker(sleeper);
|
(*packet.get()).inherit_blocker(sleeper, guard);
|
||||||
|
|
||||||
let tmp = Sender::new(Shared(packet.clone()));
|
let tmp = Sender::new(Shared(packet.clone()));
|
||||||
mem::swap(self.inner_mut(), tmp.inner_mut());
|
mem::swap(self.inner_mut(), tmp.inner_mut());
|
||||||
|
|
|
@ -26,12 +26,11 @@ use alloc::boxed::Box;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::int;
|
use core::int;
|
||||||
use rustrt::local::Local;
|
use rustrt::local::Local;
|
||||||
use rustrt::mutex::NativeMutex;
|
|
||||||
use rustrt::task::{Task, BlockedTask};
|
use rustrt::task::{Task, BlockedTask};
|
||||||
use rustrt::thread::Thread;
|
use rustrt::thread::Thread;
|
||||||
|
|
||||||
use sync::atomic;
|
use sync::{atomic, Mutex, MutexGuard};
|
||||||
use sync::mpsc_queue as mpsc;
|
use comm::mpsc_queue as mpsc;
|
||||||
|
|
||||||
const DISCONNECTED: int = int::MIN;
|
const DISCONNECTED: int = int::MIN;
|
||||||
const FUDGE: int = 1024;
|
const FUDGE: int = 1024;
|
||||||
|
@ -56,7 +55,7 @@ pub struct Packet<T> {
|
||||||
|
|
||||||
// this lock protects various portions of this implementation during
|
// this lock protects various portions of this implementation during
|
||||||
// select()
|
// select()
|
||||||
select_lock: NativeMutex,
|
select_lock: Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Failure {
|
pub enum Failure {
|
||||||
|
@ -76,7 +75,7 @@ impl<T: Send> Packet<T> {
|
||||||
channels: atomic::AtomicInt::new(2),
|
channels: atomic::AtomicInt::new(2),
|
||||||
port_dropped: atomic::AtomicBool::new(false),
|
port_dropped: atomic::AtomicBool::new(false),
|
||||||
sender_drain: atomic::AtomicInt::new(0),
|
sender_drain: atomic::AtomicInt::new(0),
|
||||||
select_lock: unsafe { NativeMutex::new() },
|
select_lock: Mutex::new(()),
|
||||||
};
|
};
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -86,8 +85,8 @@ impl<T: Send> Packet<T> {
|
||||||
// In other case mutex data will be duplicated while cloning
|
// In other case mutex data will be duplicated while cloning
|
||||||
// and that could cause problems on platforms where it is
|
// and that could cause problems on platforms where it is
|
||||||
// represented by opaque data structure
|
// represented by opaque data structure
|
||||||
pub fn postinit_lock(&mut self) {
|
pub fn postinit_lock(&self) -> MutexGuard<()> {
|
||||||
unsafe { self.select_lock.lock_noguard() }
|
self.select_lock.lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is used at the creation of a shared packet to inherit a
|
// This function is used at the creation of a shared packet to inherit a
|
||||||
|
@ -95,7 +94,9 @@ impl<T: Send> Packet<T> {
|
||||||
// tasks in select().
|
// tasks in select().
|
||||||
//
|
//
|
||||||
// This can only be called at channel-creation time
|
// This can only be called at channel-creation time
|
||||||
pub fn inherit_blocker(&mut self, task: Option<BlockedTask>) {
|
pub fn inherit_blocker(&mut self,
|
||||||
|
task: Option<BlockedTask>,
|
||||||
|
guard: MutexGuard<()>) {
|
||||||
match task {
|
match task {
|
||||||
Some(task) => {
|
Some(task) => {
|
||||||
assert_eq!(self.cnt.load(atomic::SeqCst), 0);
|
assert_eq!(self.cnt.load(atomic::SeqCst), 0);
|
||||||
|
@ -135,7 +136,7 @@ impl<T: Send> Packet<T> {
|
||||||
// interfere with this method. After we unlock this lock, we're
|
// interfere with this method. After we unlock this lock, we're
|
||||||
// signifying that we're done modifying self.cnt and self.to_wake and
|
// signifying that we're done modifying self.cnt and self.to_wake and
|
||||||
// the port is ready for the world to continue using it.
|
// the port is ready for the world to continue using it.
|
||||||
unsafe { self.select_lock.unlock_noguard() }
|
drop(guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send(&mut self, t: T) -> Result<(), T> {
|
pub fn send(&mut self, t: T) -> Result<(), T> {
|
||||||
|
@ -441,7 +442,7 @@ impl<T: Send> Packet<T> {
|
||||||
// done with. Without this bounce, we can race with inherit_blocker
|
// done with. Without this bounce, we can race with inherit_blocker
|
||||||
// about looking at and dealing with to_wake. Once we have acquired the
|
// about looking at and dealing with to_wake. Once we have acquired the
|
||||||
// lock, we are guaranteed that inherit_blocker is done.
|
// lock, we are guaranteed that inherit_blocker is done.
|
||||||
unsafe {
|
{
|
||||||
let _guard = self.select_lock.lock();
|
let _guard = self.select_lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ use rustrt::task::{Task, BlockedTask};
|
||||||
use rustrt::thread::Thread;
|
use rustrt::thread::Thread;
|
||||||
|
|
||||||
use sync::atomic;
|
use sync::atomic;
|
||||||
use sync::spsc_queue as spsc;
|
use comm::spsc_queue as spsc;
|
||||||
use comm::Receiver;
|
use comm::Receiver;
|
||||||
|
|
||||||
const DISCONNECTED: int = int::MIN;
|
const DISCONNECTED: int = int::MIN;
|
||||||
|
|
|
@ -225,8 +225,8 @@ pub mod dl {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, String> {
|
pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, String> {
|
||||||
use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
static LOCK: StaticMutex = MUTEX_INIT;
|
||||||
unsafe {
|
unsafe {
|
||||||
// dlerror isn't thread safe, so we need to lock around this entire
|
// dlerror isn't thread safe, so we need to lock around this entire
|
||||||
// sequence
|
// sequence
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
#![allow(unknown_features)]
|
#![allow(unknown_features)]
|
||||||
#![feature(macro_rules, globs, linkage)]
|
#![feature(macro_rules, globs, linkage)]
|
||||||
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
|
||||||
#![feature(import_shadowing, slicing_syntax)]
|
#![feature(import_shadowing, slicing_syntax, tuple_indexing)]
|
||||||
|
|
||||||
// Don't link to std. We are std.
|
// Don't link to std. We are std.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
|
@ -209,14 +209,12 @@ Accessing environment variables is not generally threadsafe.
|
||||||
Serialize access through a global lock.
|
Serialize access through a global lock.
|
||||||
*/
|
*/
|
||||||
fn with_env_lock<T>(f: || -> T) -> T {
|
fn with_env_lock<T>(f: || -> T) -> T {
|
||||||
use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
|
|
||||||
static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
static LOCK: StaticMutex = MUTEX_INIT;
|
||||||
|
|
||||||
unsafe {
|
let _guard = LOCK.lock();
|
||||||
let _guard = LOCK.lock();
|
f()
|
||||||
f()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a vector of (variable, value) pairs, for all the environment
|
/// Returns a vector of (variable, value) pairs, for all the environment
|
||||||
|
|
|
@ -238,7 +238,7 @@ mod imp {
|
||||||
use mem;
|
use mem;
|
||||||
use option::{Some, None, Option};
|
use option::{Some, None, Option};
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
|
|
||||||
/// As always - iOS on arm uses SjLj exceptions and
|
/// As always - iOS on arm uses SjLj exceptions and
|
||||||
/// _Unwind_Backtrace is even not available there. Still,
|
/// _Unwind_Backtrace is even not available there. Still,
|
||||||
|
@ -264,8 +264,8 @@ mod imp {
|
||||||
// while it doesn't requires lock for work as everything is
|
// while it doesn't requires lock for work as everything is
|
||||||
// local, it still displays much nicer backtraces when a
|
// local, it still displays much nicer backtraces when a
|
||||||
// couple of tasks panic simultaneously
|
// couple of tasks panic simultaneously
|
||||||
static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
static LOCK: StaticMutex = MUTEX_INIT;
|
||||||
let _g = unsafe { LOCK.lock() };
|
let _g = LOCK.lock();
|
||||||
|
|
||||||
try!(writeln!(w, "stack backtrace:"));
|
try!(writeln!(w, "stack backtrace:"));
|
||||||
// 100 lines should be enough
|
// 100 lines should be enough
|
||||||
|
@ -297,8 +297,8 @@ mod imp {
|
||||||
// is semi-reasonable in terms of printing anyway, and we know that all
|
// is semi-reasonable in terms of printing anyway, and we know that all
|
||||||
// I/O done here is blocking I/O, not green I/O, so we don't have to
|
// I/O done here is blocking I/O, not green I/O, so we don't have to
|
||||||
// worry about this being a native vs green mutex.
|
// worry about this being a native vs green mutex.
|
||||||
static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
static LOCK: StaticMutex = MUTEX_INIT;
|
||||||
let _g = unsafe { LOCK.lock() };
|
let _g = LOCK.lock();
|
||||||
|
|
||||||
try!(writeln!(w, "stack backtrace:"));
|
try!(writeln!(w, "stack backtrace:"));
|
||||||
|
|
||||||
|
@ -667,7 +667,7 @@ mod imp {
|
||||||
use option::{Some, None};
|
use option::{Some, None};
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
use sync::{StaticMutex, MUTEX_INIT};
|
||||||
use slice::SlicePrelude;
|
use slice::SlicePrelude;
|
||||||
use str::StrPrelude;
|
use str::StrPrelude;
|
||||||
use dynamic_lib::DynamicLibrary;
|
use dynamic_lib::DynamicLibrary;
|
||||||
|
@ -928,8 +928,8 @@ mod imp {
|
||||||
pub fn write(w: &mut Writer) -> IoResult<()> {
|
pub fn write(w: &mut Writer) -> IoResult<()> {
|
||||||
// According to windows documentation, all dbghelp functions are
|
// According to windows documentation, all dbghelp functions are
|
||||||
// single-threaded.
|
// single-threaded.
|
||||||
static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
static LOCK: StaticMutex = MUTEX_INIT;
|
||||||
let _g = unsafe { LOCK.lock() };
|
let _g = LOCK.lock();
|
||||||
|
|
||||||
// Open up dbghelp.dll, we don't link to it explicitly because it can't
|
// Open up dbghelp.dll, we don't link to it explicitly because it can't
|
||||||
// always be found. Additionally, it's nice having fewer dependencies.
|
// always be found. Additionally, it's nice having fewer dependencies.
|
||||||
|
|
|
@ -143,8 +143,14 @@ impl Condvar {
|
||||||
///
|
///
|
||||||
/// Like `wait`, the lock specified will be re-acquired when this function
|
/// Like `wait`, the lock specified will be re-acquired when this function
|
||||||
/// returns, regardless of whether the timeout elapsed or not.
|
/// returns, regardless of whether the timeout elapsed or not.
|
||||||
pub fn wait_timeout<T: AsMutexGuard>(&self, mutex_guard: &T,
|
// Note that this method is *not* public, and this is quite intentional
|
||||||
dur: Duration) -> bool {
|
// because we're not quite sure about the semantics of relative vs absolute
|
||||||
|
// durations or how the timing guarantees play into what the system APIs
|
||||||
|
// provide. There are also additional concerns about the unix-specific
|
||||||
|
// implementation which may need to be addressed.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn wait_timeout<T: AsMutexGuard>(&self, mutex_guard: &T,
|
||||||
|
dur: Duration) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let me: &'static Condvar = &*(self as *const _);
|
let me: &'static Condvar = &*(self as *const _);
|
||||||
me.inner.wait_timeout(mutex_guard, dur)
|
me.inner.wait_timeout(mutex_guard, dur)
|
||||||
|
@ -195,8 +201,9 @@ impl StaticCondvar {
|
||||||
/// specified duration.
|
/// specified duration.
|
||||||
///
|
///
|
||||||
/// See `Condvar::wait_timeout`.
|
/// See `Condvar::wait_timeout`.
|
||||||
pub fn wait_timeout<T: AsMutexGuard>(&'static self, mutex_guard: &T,
|
#[allow(dead_code)] // may want to stabilize this later, see wait_timeout above
|
||||||
dur: Duration) -> bool {
|
fn wait_timeout<T: AsMutexGuard>(&'static self, mutex_guard: &T,
|
||||||
|
dur: Duration) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let lock = mutex_guard.as_mutex_guard();
|
let lock = mutex_guard.as_mutex_guard();
|
||||||
let sys = mutex::guard_lock(lock);
|
let sys = mutex::guard_lock(lock);
|
||||||
|
|
|
@ -45,7 +45,7 @@ use sys_common::mutex as sys;
|
||||||
/// let data = Arc::new(Mutex::new(0));
|
/// let data = Arc::new(Mutex::new(0));
|
||||||
///
|
///
|
||||||
/// let (tx, rx) = channel();
|
/// let (tx, rx) = channel();
|
||||||
/// for _ in range(0, 10) {
|
/// for _ in range(0u, 10) {
|
||||||
/// let (data, tx) = (data.clone(), tx.clone());
|
/// let (data, tx) = (data.clone(), tx.clone());
|
||||||
/// spawn(proc() {
|
/// spawn(proc() {
|
||||||
/// // The shared static can only be accessed once the lock is held.
|
/// // The shared static can only be accessed once the lock is held.
|
||||||
|
|
|
@ -20,13 +20,14 @@
|
||||||
//! can be created in the future and there must be no active timers at that
|
//! can be created in the future and there must be no active timers at that
|
||||||
//! time.
|
//! time.
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
|
use cell::UnsafeCell;
|
||||||
use mem;
|
use mem;
|
||||||
use rustrt::bookkeeping;
|
use rustrt::bookkeeping;
|
||||||
use rustrt::mutex::StaticNativeMutex;
|
|
||||||
use rustrt;
|
use rustrt;
|
||||||
use cell::UnsafeCell;
|
use sync::{StaticMutex, StaticCondvar};
|
||||||
use sys::helper_signal;
|
use sys::helper_signal;
|
||||||
use prelude::*;
|
|
||||||
|
|
||||||
use task;
|
use task;
|
||||||
|
|
||||||
|
@ -39,7 +40,8 @@ use task;
|
||||||
/// is for static initialization.
|
/// is for static initialization.
|
||||||
pub struct Helper<M> {
|
pub struct Helper<M> {
|
||||||
/// Internal lock which protects the remaining fields
|
/// Internal lock which protects the remaining fields
|
||||||
pub lock: StaticNativeMutex,
|
pub lock: StaticMutex,
|
||||||
|
pub cond: StaticCondvar,
|
||||||
|
|
||||||
// You'll notice that the remaining fields are UnsafeCell<T>, and this is
|
// You'll notice that the remaining fields are UnsafeCell<T>, and this is
|
||||||
// because all helper thread operations are done through &self, but we need
|
// because all helper thread operations are done through &self, but we need
|
||||||
|
@ -53,6 +55,9 @@ pub struct Helper<M> {
|
||||||
|
|
||||||
/// Flag if this helper thread has booted and been initialized yet.
|
/// Flag if this helper thread has booted and been initialized yet.
|
||||||
pub initialized: UnsafeCell<bool>,
|
pub initialized: UnsafeCell<bool>,
|
||||||
|
|
||||||
|
/// Flag if this helper thread has shut down
|
||||||
|
pub shutdown: UnsafeCell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Send> Helper<M> {
|
impl<M: Send> Helper<M> {
|
||||||
|
@ -80,7 +85,9 @@ impl<M: Send> Helper<M> {
|
||||||
task::spawn(proc() {
|
task::spawn(proc() {
|
||||||
bookkeeping::decrement();
|
bookkeeping::decrement();
|
||||||
helper(receive, rx, t);
|
helper(receive, rx, t);
|
||||||
self.lock.lock().signal()
|
let _g = self.lock.lock();
|
||||||
|
*self.shutdown.get() = true;
|
||||||
|
self.cond.notify_one()
|
||||||
});
|
});
|
||||||
|
|
||||||
rustrt::at_exit(proc() { self.shutdown() });
|
rustrt::at_exit(proc() { self.shutdown() });
|
||||||
|
@ -119,7 +126,9 @@ impl<M: Send> Helper<M> {
|
||||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||||
|
|
||||||
// Wait for the child to exit
|
// Wait for the child to exit
|
||||||
guard.wait();
|
while !*self.shutdown.get() {
|
||||||
|
self.cond.wait(&guard);
|
||||||
|
}
|
||||||
drop(guard);
|
drop(guard);
|
||||||
|
|
||||||
// Clean up after ourselves
|
// Clean up after ourselves
|
||||||
|
|
|
@ -16,13 +16,13 @@ use libc::{mod, c_char, c_int};
|
||||||
use mem;
|
use mem;
|
||||||
use num::Int;
|
use num::Int;
|
||||||
use ptr::{mod, null, null_mut};
|
use ptr::{mod, null, null_mut};
|
||||||
use rustrt::mutex;
|
|
||||||
use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use io::net::addrinfo;
|
use io::net::addrinfo;
|
||||||
use io::{IoResult, IoError};
|
use io::{IoResult, IoError};
|
||||||
use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
|
use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock,
|
||||||
wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
|
wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval,
|
||||||
decode_error_detailed};
|
decode_error_detailed};
|
||||||
|
use sync::{Mutex, MutexGuard};
|
||||||
use sys_common::{mod, keep_going, short_write, timeout};
|
use sys_common::{mod, keep_going, short_write, timeout};
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use cmp;
|
use cmp;
|
||||||
|
@ -557,12 +557,12 @@ struct Inner {
|
||||||
|
|
||||||
// Unused on Linux, where this lock is not necessary.
|
// Unused on Linux, where this lock is not necessary.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
lock: mutex::NativeMutex
|
lock: Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
fn new(fd: sock_t) -> Inner {
|
fn new(fd: sock_t) -> Inner {
|
||||||
Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
|
Inner { fd: fd, lock: Mutex::new(()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +572,7 @@ impl Drop for Inner {
|
||||||
|
|
||||||
pub struct Guard<'a> {
|
pub struct Guard<'a> {
|
||||||
pub fd: sock_t,
|
pub fd: sock_t,
|
||||||
pub guard: mutex::LockGuard<'a>,
|
pub guard: MutexGuard<'a, ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe_destructor]
|
#[unsafe_destructor]
|
||||||
|
@ -666,7 +666,7 @@ impl TcpStream {
|
||||||
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
||||||
let ret = Guard {
|
let ret = Guard {
|
||||||
fd: self.fd(),
|
fd: self.fd(),
|
||||||
guard: unsafe { self.inner.lock.lock() },
|
guard: self.inner.lock.lock(),
|
||||||
};
|
};
|
||||||
assert!(set_nonblocking(self.fd(), true).is_ok());
|
assert!(set_nonblocking(self.fd(), true).is_ok());
|
||||||
ret
|
ret
|
||||||
|
@ -805,7 +805,7 @@ impl UdpSocket {
|
||||||
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
||||||
let ret = Guard {
|
let ret = Guard {
|
||||||
fd: self.fd(),
|
fd: self.fd(),
|
||||||
guard: unsafe { self.inner.lock.lock() },
|
guard: self.inner.lock.lock(),
|
||||||
};
|
};
|
||||||
assert!(set_nonblocking(self.fd(), true).is_ok());
|
assert!(set_nonblocking(self.fd(), true).is_ok());
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -25,10 +25,12 @@ use sys_common::mkerr_libc;
|
||||||
|
|
||||||
macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
|
macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
|
||||||
static $name: Helper<$m> = Helper {
|
static $name: Helper<$m> = Helper {
|
||||||
lock: ::rustrt::mutex::NATIVE_MUTEX_INIT,
|
lock: ::sync::MUTEX_INIT,
|
||||||
|
cond: ::sync::CONDVAR_INIT,
|
||||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||||
signal: ::cell::UnsafeCell { value: 0 },
|
signal: ::cell::UnsafeCell { value: 0 },
|
||||||
initialized: ::cell::UnsafeCell { value: false },
|
initialized: ::cell::UnsafeCell { value: false },
|
||||||
|
shutdown: ::cell::UnsafeCell { value: false },
|
||||||
};
|
};
|
||||||
) )
|
) )
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,7 @@ use alloc::arc::Arc;
|
||||||
use libc;
|
use libc;
|
||||||
use c_str::CString;
|
use c_str::CString;
|
||||||
use mem;
|
use mem;
|
||||||
use rustrt::mutex;
|
use sync::{atomic, Mutex};
|
||||||
use sync::atomic;
|
|
||||||
use io::{mod, IoResult, IoError};
|
use io::{mod, IoResult, IoError};
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
|
@ -60,12 +59,12 @@ struct Inner {
|
||||||
|
|
||||||
// Unused on Linux, where this lock is not necessary.
|
// Unused on Linux, where this lock is not necessary.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
lock: mutex::NativeMutex
|
lock: Mutex<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
fn new(fd: fd_t) -> Inner {
|
fn new(fd: fd_t) -> Inner {
|
||||||
Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
|
Inner { fd: fd, lock: Mutex::new(()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,12 @@ use sync::{Once, ONCE_INIT};
|
||||||
|
|
||||||
macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
|
macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
|
||||||
static $name: Helper<$m> = Helper {
|
static $name: Helper<$m> = Helper {
|
||||||
lock: ::rustrt::mutex::NATIVE_MUTEX_INIT,
|
lock: ::sync::MUTEX_INIT,
|
||||||
|
cond: ::sync::CONDVAR_INIT,
|
||||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||||
signal: ::cell::UnsafeCell { value: 0 },
|
signal: ::cell::UnsafeCell { value: 0 },
|
||||||
initialized: ::cell::UnsafeCell { value: false },
|
initialized: ::cell::UnsafeCell { value: false },
|
||||||
|
shutdown: ::cell::UnsafeCell { value: false },
|
||||||
};
|
};
|
||||||
) )
|
) )
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
use sync::atomic;
|
use sync::atomic;
|
||||||
use alloc::{mod, heap};
|
use alloc::{mod, heap};
|
||||||
|
|
||||||
|
@ -21,8 +23,8 @@ pub struct Mutex { inner: atomic::AtomicUint }
|
||||||
pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT };
|
pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT };
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn raw(m: &super::Mutex) -> ffi::LPCRITICAL_SECTION {
|
pub unsafe fn raw(m: &Mutex) -> ffi::LPCRITICAL_SECTION {
|
||||||
m.0.get()
|
m.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mutex {
|
impl Mutex {
|
||||||
|
|
|
@ -89,8 +89,7 @@ use libc;
|
||||||
use c_str::CString;
|
use c_str::CString;
|
||||||
use mem;
|
use mem;
|
||||||
use ptr;
|
use ptr;
|
||||||
use sync::atomic;
|
use sync::{atomic, Mutex};
|
||||||
use rustrt::mutex;
|
|
||||||
use io::{mod, IoError, IoResult};
|
use io::{mod, IoError, IoResult};
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
|
@ -126,7 +125,7 @@ impl Drop for Event {
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
handle: libc::HANDLE,
|
handle: libc::HANDLE,
|
||||||
lock: mutex::NativeMutex,
|
lock: Mutex<()>,
|
||||||
read_closed: atomic::AtomicBool,
|
read_closed: atomic::AtomicBool,
|
||||||
write_closed: atomic::AtomicBool,
|
write_closed: atomic::AtomicBool,
|
||||||
}
|
}
|
||||||
|
@ -135,7 +134,7 @@ impl Inner {
|
||||||
fn new(handle: libc::HANDLE) -> Inner {
|
fn new(handle: libc::HANDLE) -> Inner {
|
||||||
Inner {
|
Inner {
|
||||||
handle: handle,
|
handle: handle,
|
||||||
lock: unsafe { mutex::NativeMutex::new() },
|
lock: Mutex::new(()),
|
||||||
read_closed: atomic::AtomicBool::new(false),
|
read_closed: atomic::AtomicBool::new(false),
|
||||||
write_closed: atomic::AtomicBool::new(false),
|
write_closed: atomic::AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,28 +19,30 @@
|
||||||
// ignore-lexer-test FIXME #15679
|
// ignore-lexer-test FIXME #15679
|
||||||
|
|
||||||
use std::os;
|
use std::os;
|
||||||
use std::sync::{Arc, Future, Mutex};
|
use std::sync::{Arc, Future, Mutex, Condvar};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::uint;
|
use std::uint;
|
||||||
|
|
||||||
// A poor man's pipe.
|
// A poor man's pipe.
|
||||||
type pipe = Arc<Mutex<Vec<uint>>>;
|
type pipe = Arc<(Mutex<Vec<uint>>, Condvar)>;
|
||||||
|
|
||||||
fn send(p: &pipe, msg: uint) {
|
fn send(p: &pipe, msg: uint) {
|
||||||
let mut arr = p.lock();
|
let &(ref lock, ref cond) = &**p;
|
||||||
|
let mut arr = lock.lock();
|
||||||
arr.push(msg);
|
arr.push(msg);
|
||||||
arr.cond.signal();
|
cond.notify_one();
|
||||||
}
|
}
|
||||||
fn recv(p: &pipe) -> uint {
|
fn recv(p: &pipe) -> uint {
|
||||||
let mut arr = p.lock();
|
let &(ref lock, ref cond) = &**p;
|
||||||
|
let mut arr = lock.lock();
|
||||||
while arr.is_empty() {
|
while arr.is_empty() {
|
||||||
arr.cond.wait();
|
cond.wait(&arr);
|
||||||
}
|
}
|
||||||
arr.pop().unwrap()
|
arr.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init() -> (pipe,pipe) {
|
fn init() -> (pipe,pipe) {
|
||||||
let m = Arc::new(Mutex::new(Vec::new()));
|
let m = Arc::new((Mutex::new(Vec::new()), Condvar::new()));
|
||||||
((&m).clone(), m)
|
((&m).clone(), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
// This test creates a bunch of tasks that simultaneously send to each
|
|
||||||
// other in a ring. The messages should all be basically
|
|
||||||
// independent.
|
|
||||||
// This is like msgsend-ring-pipes but adapted to use Arcs.
|
|
||||||
|
|
||||||
// This also serves as a pipes test, because Arcs are implemented with pipes.
|
|
||||||
|
|
||||||
// no-pretty-expanded FIXME #15189
|
|
||||||
// ignore-lexer-test FIXME #15679
|
|
||||||
|
|
||||||
use std::os;
|
|
||||||
use std::sync::{RWLock, Arc, Future};
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::uint;
|
|
||||||
|
|
||||||
// A poor man's pipe.
|
|
||||||
type pipe = Arc<RWLock<Vec<uint>>>;
|
|
||||||
|
|
||||||
fn send(p: &pipe, msg: uint) {
|
|
||||||
let mut arr = p.write();
|
|
||||||
arr.push(msg);
|
|
||||||
arr.cond.signal();
|
|
||||||
}
|
|
||||||
fn recv(p: &pipe) -> uint {
|
|
||||||
let mut arr = p.write();
|
|
||||||
while arr.is_empty() {
|
|
||||||
arr.cond.wait();
|
|
||||||
}
|
|
||||||
arr.pop().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init() -> (pipe,pipe) {
|
|
||||||
let x = Arc::new(RWLock::new(Vec::new()));
|
|
||||||
((&x).clone(), x)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn thread_ring(i: uint, count: uint, num_chan: pipe, num_port: pipe) {
|
|
||||||
let mut num_chan = Some(num_chan);
|
|
||||||
let mut num_port = Some(num_port);
|
|
||||||
// Send/Receive lots of messages.
|
|
||||||
for j in range(0u, count) {
|
|
||||||
//println!("task %?, iter %?", i, j);
|
|
||||||
let num_chan2 = num_chan.take().unwrap();
|
|
||||||
let num_port2 = num_port.take().unwrap();
|
|
||||||
send(&num_chan2, i * j);
|
|
||||||
num_chan = Some(num_chan2);
|
|
||||||
let _n = recv(&num_port2);
|
|
||||||
//log(error, _n);
|
|
||||||
num_port = Some(num_port2);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args = os::args();
|
|
||||||
let args = if os::getenv("RUST_BENCH").is_some() {
|
|
||||||
vec!("".to_string(), "100".to_string(), "10000".to_string())
|
|
||||||
} else if args.len() <= 1u {
|
|
||||||
vec!("".to_string(), "10".to_string(), "100".to_string())
|
|
||||||
} else {
|
|
||||||
args.clone().into_iter().collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
let num_tasks = from_str::<uint>(args[1].as_slice()).unwrap();
|
|
||||||
let msg_per_task = from_str::<uint>(args[2].as_slice()).unwrap();
|
|
||||||
|
|
||||||
let (mut num_chan, num_port) = init();
|
|
||||||
|
|
||||||
let mut p = Some((num_chan, num_port));
|
|
||||||
let dur = Duration::span(|| {
|
|
||||||
let (mut num_chan, num_port) = p.take().unwrap();
|
|
||||||
|
|
||||||
// create the ring
|
|
||||||
let mut futures = Vec::new();
|
|
||||||
|
|
||||||
for i in range(1u, num_tasks) {
|
|
||||||
//println!("spawning %?", i);
|
|
||||||
let (new_chan, num_port) = init();
|
|
||||||
let num_chan_2 = num_chan.clone();
|
|
||||||
let new_future = Future::spawn(proc() {
|
|
||||||
thread_ring(i, msg_per_task, num_chan_2, num_port)
|
|
||||||
});
|
|
||||||
futures.push(new_future);
|
|
||||||
num_chan = new_chan;
|
|
||||||
};
|
|
||||||
|
|
||||||
// do our iteration
|
|
||||||
thread_ring(0, msg_per_task, num_chan, num_port);
|
|
||||||
|
|
||||||
// synchronize
|
|
||||||
for f in futures.iter_mut() {
|
|
||||||
let _ = f.get();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// all done, report stats.
|
|
||||||
let num_msgs = num_tasks * msg_per_task;
|
|
||||||
let rate = (num_msgs as f64) / (dur.num_milliseconds() as f64);
|
|
||||||
|
|
||||||
println!("Sent {} messages in {} ms", num_msgs, dur.num_milliseconds());
|
|
||||||
println!(" {} messages / second", rate / 1000.0);
|
|
||||||
println!(" {} μs / message", 1000000. / rate / 1000.0);
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue