@@ -0,0 +1,358 @@
// Copyright 2014 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.

use prelude::*;

use sync::atomic::{mod, AtomicUint};
use sync::{mutex, StaticMutexGuard};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use time::Duration;

/// A Condition Variable
///
/// Condition variables represent the ability to block a thread such that it
/// consumes no CPU time while waiting for an event to occur. Condition
/// variables are typically associated with a boolean predicate (a condition)
/// and a mutex. The predicate is always verified inside of the mutex before
/// determining that thread must block.
///
/// Functions in this module will block the current **thread** of execution and
/// are bindings to system-provided condition variables where possible. Note
/// that this module places one additional restriction over the system condition
/// variables: each condvar can be used with precisely one mutex at runtime. Any
/// attempt to use multiple mutexes on the same condition variable will result
/// in a runtime panic. If this is not desired, then the unsafe primitives in
/// `sys` do not have this restriction but may result in undefined behavior.
///
/// # Example
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start
/// spawn(proc() {
/// let &(ref lock, ref cvar) = &*pair2;
/// let mut started = lock.lock();
/// *started = true;
/// cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let started = lock.lock();
/// while !*started {
/// cvar.wait(&started);
/// }
/// ```
pub struct Condvar { inner: Box<StaticCondvar> }

/// Statically allocated condition variables.
///
/// This structure is identical to `Condvar` except that it is suitable for use
/// in static initializers for other structures.
///
/// # Example
///
/// ```
/// use std::sync::{StaticCondvar, CONDVAR_INIT};
///
/// static CVAR: StaticCondvar = CONDVAR_INIT;
/// ```
pub struct StaticCondvar {
inner: sys::Condvar,
mutex: AtomicUint,
}

/// Constant initializer for a statically allocated condition variable.
pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
inner: sys::CONDVAR_INIT,
mutex: atomic::INIT_ATOMIC_UINT,
};

/// A trait for vaules which can be passed to the waiting methods of condition
/// variables. This is implemented by the mutex guards in this module.
///
/// Note that this trait should likely not be implemented manually unless you
/// really know what you're doing.
pub trait AsMutexGuard {
#[allow(missing_docs)]
unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard;
}

impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
/// notified.
pub fn new() -> Condvar {
Condvar {
inner: box StaticCondvar {
inner: unsafe { sys::Condvar::new() },
mutex: AtomicUint::new(0),
}
}
}

/// Block the current thread until this condition variable receives a
/// notification.
///
/// This function will atomically unlock the mutex specified (represented by
/// `guard`) and block the current thread. This means that any calls to
/// `notify_*()` which happen logically after the mutex is unlocked are
/// candidates to wake this thread up. When this function call returns, the
/// lock specified will have been re-acquired.
///
/// Note that this function is susceptible to spurious wakeups. Condition
/// variables normally have a boolean predicate associated with them, and
/// the predicate must always be checked each time this function returns to
/// protect against spurious wakeups.
///
/// # Panics
///
/// This function will `panic!()` if it is used with more than one mutex
/// over time. Each condition variable is dynamically bound to exactly one
/// mutex to ensure defined behavior across platforms. If this functionality
/// is not desired, then unsafe primitives in `sys` are provided.
pub fn wait<T: AsMutexGuard>(&self, mutex_guard: &T) {
unsafe {
let me: &'static Condvar = &*(self as *const _);
me.inner.wait(mutex_guard)
}
}

/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to `wait()` except that
/// the thread will be blocked for roughly no longer than `dur`. This method
/// should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum amount
/// of time waited to be precisely `dur`.
///
/// If the wait timed out, then `false` will be returned. Otherwise if a
/// notification was received then `true` will be returned.
///
/// Like `wait`, the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
pub fn wait_timeout<T: AsMutexGuard>(&self, mutex_guard: &T,
dur: Duration) -> bool {
unsafe {
let me: &'static Condvar = &*(self as *const _);
me.inner.wait_timeout(mutex_guard, dur)
}
}

/// Wake up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
/// be woken up from its call to `wait` or `wait_timeout`. Calls to
/// `notify_one` are not buffered in any way.
///
/// To wake up all threads, see `notify_one()`.
pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }

/// Wake up all blocked threads on this condvar.
///
/// This method will ensure that any current waiters on the condition
/// variable are awoken. Calls to `notify_all()` are not buffered in any
/// way.
///
/// To wake up only one thread, see `notify_one()`.
pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } }
}

impl Drop for Condvar {
fn drop(&mut self) {
unsafe { self.inner.inner.destroy() }
}
}

impl StaticCondvar {
/// Block the current thread until this condition variable receives a
/// notification.
///
/// See `Condvar::wait`.
pub fn wait<T: AsMutexGuard>(&'static self, mutex_guard: &T) {
unsafe {
let lock = mutex_guard.as_mutex_guard();
let sys = mutex::guard_lock(lock);
self.verify(sys);
self.inner.wait(sys);
(*mutex::guard_poison(lock)).check("mutex");
}
}

/// Wait on this condition variable for a notification, timing out after a
/// specified duration.
///
/// See `Condvar::wait_timeout`.
pub fn wait_timeout<T: AsMutexGuard>(&'static self, mutex_guard: &T,
dur: Duration) -> bool {
unsafe {
let lock = mutex_guard.as_mutex_guard();
let sys = mutex::guard_lock(lock);
self.verify(sys);
let ret = self.inner.wait_timeout(sys, dur);
(*mutex::guard_poison(lock)).check("mutex");
return ret;
}
}

/// Wake up one blocked thread on this condvar.
///
/// See `Condvar::notify_one`.
pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }

/// Wake up all blocked threads on this condvar.
///
/// See `Condvar::notify_all`.
pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }

/// Deallocate all resources associated with this static condvar.
///
/// This method is unsafe to call as there is no guarantee that there are no
/// active users of the condvar, and this also doesn't prevent any future
/// users of the condvar. This method is required to be called to not leak
/// memory on all platforms.
pub unsafe fn destroy(&'static self) {
self.inner.destroy()
}

fn verify(&self, mutex: &sys_mutex::Mutex) {
let addr = mutex as *const _ as uint;
match self.mutex.compare_and_swap(0, addr, atomic::SeqCst) {
// If we got out 0, then we have successfully bound the mutex to
// this cvar.
0 => {}

// If we get out a value that's the same as `addr`, then someone
// already beat us to the punch.
n if n == addr => {}

// Anything else and we're using more than one mutex on this cvar,
// which is currently disallowed.
_ => panic!("attempted to use a condition variable with two \
mutexes"),
}
}
}

#[cfg(test)]
mod tests {
use prelude::*;

use time::Duration;
use super::{StaticCondvar, CONDVAR_INIT};
use sync::{StaticMutex, MUTEX_INIT, Condvar, Mutex, Arc};

#[test]
fn smoke() {
let c = Condvar::new();
c.notify_one();
c.notify_all();
}

#[test]
fn static_smoke() {
static C: StaticCondvar = CONDVAR_INIT;
C.notify_one();
C.notify_all();
unsafe { C.destroy(); }
}

#[test]
fn notify_one() {
static C: StaticCondvar = CONDVAR_INIT;
static M: StaticMutex = MUTEX_INIT;

let g = M.lock();
spawn(proc() {
let _g = M.lock();
C.notify_one();
});
C.wait(&g);
drop(g);
unsafe { C.destroy(); M.destroy(); }
}

#[test]
fn notify_all() {
const N: uint = 10;

let data = Arc::new((Mutex::new(0), Condvar::new()));
let (tx, rx) = channel();
for _ in range(0, N) {
let data = data.clone();
let tx = tx.clone();
spawn(proc() {
let &(ref lock, ref cond) = &*data;
let mut cnt = lock.lock();
*cnt += 1;
if *cnt == N {
tx.send(());
}
while *cnt != 0 {
cond.wait(&cnt);
}
tx.send(());
});
}
drop(tx);

let &(ref lock, ref cond) = &*data;
rx.recv();
let mut cnt = lock.lock();
*cnt = 0;
cond.notify_all();
drop(cnt);

for _ in range(0, N) {
rx.recv();
}
}

#[test]
fn wait_timeout() {
static C: StaticCondvar = CONDVAR_INIT;
static M: StaticMutex = MUTEX_INIT;

let g = M.lock();
assert!(!C.wait_timeout(&g, Duration::nanoseconds(1000)));
spawn(proc() {
let _g = M.lock();
C.notify_one();
});
assert!(C.wait_timeout(&g, Duration::days(1)));
drop(g);
unsafe { C.destroy(); M.destroy(); }
}

#[test]
#[should_fail]
fn two_mutexes() {
static M1: StaticMutex = MUTEX_INIT;
static M2: StaticMutex = MUTEX_INIT;
static C: StaticCondvar = CONDVAR_INIT;

let g = M1.lock();
spawn(proc() {
let _g = M1.lock();
C.notify_one();
});
C.wait(&g);
drop(g);

C.wait(&M2.lock());

}
}

This file was deleted.

Oops, something went wrong.
@@ -148,7 +148,7 @@ mod test {
use prelude::*;
use sync::Future;
use task;
use comm::{channel, Sender};
use comm::channel;

#[test]
fn test_from_value() {

This file was deleted.

Oops, something went wrong.
@@ -17,41 +17,27 @@

#![experimental]

pub use self::one::{Once, ONCE_INIT};

pub use alloc::arc::{Arc, Weak};
pub use self::lock::{Mutex, MutexGuard, Condvar, Barrier,
RWLock, RWLockReadGuard, RWLockWriteGuard};

// The mutex/rwlock in this module are not meant for reexport
pub use self::raw::{Semaphore, SemaphoreGuard};
pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard, MUTEX_INIT};
pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT};
pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard};
pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard};
pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsMutexGuard};
pub use self::once::{Once, ONCE_INIT};
pub use self::semaphore::{Semaphore, SemaphoreGuard};
pub use self::barrier::Barrier;

pub use self::future::Future;
pub use self::task_pool::TaskPool;

// Core building blocks for all primitives in this crate

#[stable]
pub mod atomic;

// Concurrent data structures

pub mod spsc_queue;
pub mod mpsc_queue;
pub mod mpmc_bounded_queue;
pub mod deque;

// Low-level concurrency primitives

mod raw;
mod mutex;
mod one;

// Higher level primitives based on those above

mod lock;

// Task management

mod barrier;
mod condvar;
mod future;
mod mutex;
mod once;
mod poison;
mod rwlock;
mod semaphore;
mod task_pool;

This file was deleted.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -13,12 +13,10 @@
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.

use core::prelude::*;

use core::int;
use core::atomic;

use super::mutex::{StaticMutex, MUTEX_INIT};
use int;
use mem::drop;
use sync::atomic;
use sync::{StaticMutex, MUTEX_INIT};

/// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related
@@ -27,8 +25,8 @@ use super::mutex::{StaticMutex, MUTEX_INIT};
///
/// # Example
///
/// ```rust,ignore
/// use std::sync::one::{Once, ONCE_INIT};
/// ```rust
/// use std::sync::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
///
@@ -59,7 +57,7 @@ impl Once {
///
/// When this function returns, it is guaranteed that some initialization
/// has run and completed (it may not be the closure specified).
pub fn doit(&self, f: ||) {
pub fn doit(&'static self, f: ||) {
// Optimize common path: load is much cheaper than fetch_add.
if self.cnt.load(atomic::SeqCst) < 0 {
return
@@ -121,6 +119,7 @@ impl Once {
#[cfg(test)]
mod test {
use prelude::*;

use task;
use super::{ONCE_INIT, Once};

@@ -0,0 +1,48 @@
// Copyright 2014 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.

use option::None;
use rustrt::task::Task;
use rustrt::local::Local;

pub struct Flag { pub failed: bool }

impl Flag {
pub fn borrow(&mut self) -> Guard {
Guard { flag: &mut self.failed, failing: failing() }
}
}

pub struct Guard<'a> {
flag: &'a mut bool,
failing: bool,
}

impl<'a> Guard<'a> {
pub fn check(&self, name: &str) {
if *self.flag {
panic!("poisoned {} - another task failed inside", name);
}
}

pub fn done(&mut self) {
if !self.failing && failing() {
*self.flag = true;
}
}
}

fn failing() -> bool {
if Local::exists(None::<Task>) {
Local::borrow(None::<Task>).unwinder.unwinding()
} else {
false
}
}

This file was deleted.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,195 @@
// Copyright 2014 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.

use ops::Drop;
use sync::{Mutex, Condvar};

/// A counting, blocking, semaphore.
///
/// Semaphores are a form of atomic counter where access is only granted if the
/// counter is a positive value. Each acquisition will block the calling thread
/// until the counter is positive, and each release will increment the counter
/// and unblock any threads if necessary.
///
/// # Example
///
/// ```
/// use std::sync::Semaphore;
///
/// // Create a semaphore that represents 5 resources
/// let sem = Semaphore::new(5);
///
/// // Acquire one of the resources
/// sem.acquire();
///
/// // Acquire one of the resources for a limited period of time
/// {
/// let _guard = sem.access();
/// // ...
/// } // resources is released here
///
/// // Release our initially acquired resource
/// sem.release();
/// ```
pub struct Semaphore {
lock: Mutex<int>,
cvar: Condvar,
}

/// An RAII guard which will release a resource acquired from a semaphore when
/// dropped.
pub struct SemaphoreGuard<'a> {
sem: &'a Semaphore,
}

impl Semaphore {
/// Creates a new semaphore with the initial count specified.
///
/// The count specified can be thought of as a number of resources, and a
/// call to `acquire` or `access` will block until at least one resource is
/// available. It is valid to initialize a semaphore with a negative count.
pub fn new(count: int) -> Semaphore {
Semaphore {
lock: Mutex::new(count),
cvar: Condvar::new(),
}
}

/// Acquires a resource of this semaphore, blocking the current thread until
/// it can do so.
///
/// This method will block until the internal count of the semaphore is at
/// least 1.
pub fn acquire(&self) {
let mut count = self.lock.lock();
while *count <= 0 {
self.cvar.wait(&count);
}
*count -= 1;
}

/// Release a resource from this semaphore.
///
/// This will increment the number of resources in this semaphore by 1 and
/// will notify any pending waiters in `acquire` or `access` if necessary.
pub fn release(&self) {
*self.lock.lock() += 1;
self.cvar.notify_one();
}

/// Acquires a resource of this semaphore, returning an RAII guard to
/// release the semaphore when dropped.
///
/// This function is semantically equivalent to an `acquire` followed by a
/// `release` when the guard returned is dropped.
pub fn access(&self) -> SemaphoreGuard {
self.acquire();
SemaphoreGuard { sem: self }
}
}

#[unsafe_destructor]
impl<'a> Drop for SemaphoreGuard<'a> {
fn drop(&mut self) {
self.sem.release();
}
}

#[cfg(test)]
mod tests {
use prelude::*;

use sync::Arc;
use super::Semaphore;

#[test]
fn test_sem_acquire_release() {
let s = Semaphore::new(1);
s.acquire();
s.release();
s.acquire();
}

#[test]
fn test_sem_basic() {
let s = Semaphore::new(1);
let _g = s.access();
}

#[test]
fn test_sem_as_mutex() {
let s = Arc::new(Semaphore::new(1));
let s2 = s.clone();
spawn(proc() {
let _g = s2.access();
});
let _g = s.access();
}

#[test]
fn test_sem_as_cvar() {
/* Child waits and parent signals */
let (tx, rx) = channel();
let s = Arc::new(Semaphore::new(0));
let s2 = s.clone();
spawn(proc() {
s2.acquire();
tx.send(());
});
s.release();
let _ = rx.recv();

/* Parent waits and child signals */
let (tx, rx) = channel();
let s = Arc::new(Semaphore::new(0));
let s2 = s.clone();
spawn(proc() {
s2.release();
let _ = rx.recv();
});
s.acquire();
tx.send(());
}

#[test]
fn test_sem_multi_resource() {
// Parent and child both get in the critical section at the same
// time, and shake hands.
let s = Arc::new(Semaphore::new(2));
let s2 = s.clone();
let (tx1, rx1) = channel();
let (tx2, rx2) = channel();
spawn(proc() {
let _g = s2.access();
let _ = rx2.recv();
tx1.send(());
});
let _g = s.access();
tx2.send(());
let _ = rx1.recv();
}

#[test]
fn test_sem_runtime_friendly_blocking() {
let s = Arc::new(Semaphore::new(1));
let s2 = s.clone();
let (tx, rx) = channel();
{
let _g = s.access();
spawn(proc() {
tx.send(());
drop(s2.access());
tx.send(());
});
rx.recv(); // wait for child to come alive
}
rx.recv(); // wait for child to be done
}
}
@@ -0,0 +1,67 @@
// Copyright 2014 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.

use time::Duration;
use sys_common::mutex::{mod, Mutex};
use sys::condvar as imp;

/// An OS-based condition variable.
///
/// This structure is the lowest layer possible on top of the OS-provided
/// condition variables. It is consequently entirely unsafe to use. It is
/// recommended to use the safer types at the top level of this crate instead of
/// this type.
pub struct Condvar(imp::Condvar);

/// Static initializer for condition variables.
pub const CONDVAR_INIT: Condvar = Condvar(imp::CONDVAR_INIT);

impl Condvar {
/// Creates a new condition variable for use.
///
/// Behavior is undefined if the condition variable is moved after it is
/// first used with any of the functions below.
#[inline]
pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) }

/// Signal one waiter on this condition variable to wake up.
#[inline]
pub unsafe fn notify_one(&self) { self.0.notify_one() }

/// Awaken all current waiters on this condition variable.
#[inline]
pub unsafe fn notify_all(&self) { self.0.notify_all() }

/// Wait for a signal on the specified mutex.
///
/// Behavior is undefined if the mutex is not locked by the current thread.
/// Behavior is also undefined if more than one mutex is used concurrently
/// on this condition variable.
#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) }

/// Wait for a signal on the specified mutex with a timeout duration
/// specified by `dur` (a relative time into the future).
///
/// Behavior is undefined if the mutex is not locked by the current thread.
/// Behavior is also undefined if more than one mutex is used concurrently
/// on this condition variable.
#[inline]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
self.0.wait_timeout(mutex::raw(mutex), dur)
}

/// Deallocate all resources associated with this condition variable.
///
/// Behavior is undefined if there are current or will be future users of
/// this condition variable.
#[inline]
pub unsafe fn destroy(&self) { self.0.destroy() }
}
@@ -19,8 +19,11 @@ use num::Int;
use path::BytesContainer;
use collections;

pub mod net;
pub mod condvar;
pub mod helper_thread;
pub mod mutex;
pub mod net;
pub mod rwlock;
pub mod thread_local;

// common error constructors
@@ -0,0 +1,64 @@
// Copyright 2014 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.

pub use sys::mutex::raw;

use sys::mutex as imp;

/// An OS-based mutual exclusion lock.
///
/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
/// this mutex is unsafe and it is recommended to instead use the safe wrapper
/// at the top level of the crate instead of this type.
pub struct Mutex(imp::Mutex);

/// Constant initializer for statically allocated mutexes.
pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT);

impl Mutex {
/// Creates a newly initialized mutex.
///
/// Behavior is undefined if the mutex is moved after the first method is
/// called on the mutex.
#[inline]
pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) }

/// Lock the mutex blocking the current thread until it is available.
///
/// Behavior is undefined if the mutex has been moved between this and any
/// previous function call.
#[inline]
pub unsafe fn lock(&self) { self.0.lock() }

/// Attempt to lock the mutex without blocking, returning whether it was
/// successfully acquired or not.
///
/// Behavior is undefined if the mutex has been moved between this and any
/// previous function call.
#[inline]
pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() }

/// Unlock the mutex.
///
/// Behavior is undefined if the current thread does not actually hold the
/// mutex.
#[inline]
pub unsafe fn unlock(&self) { self.0.unlock() }

/// Deallocate all resources associated with this mutex.
///
/// Behavior is undefined if there are current or will be future users of
/// this mutex.
#[inline]
pub unsafe fn destroy(&self) { self.0.destroy() }
}

// not meant to be exported to the outside world, just the containing module
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }
@@ -0,0 +1,86 @@
// Copyright 2014 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.

use sys::rwlock as imp;

/// An OS-based reader-writer lock.
///
/// This structure is entirely unsafe and serves as the lowest layer of a
/// cross-platform binding of system rwlocks. It is recommended to use the
/// safer types at the top level of this crate instead of this type.
pub struct RWLock(imp::RWLock);

/// Constant initializer for static RWLocks.
pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT);

impl RWLock {
/// Creates a new instance of an RWLock.
///
/// Usage of an RWLock is undefined if it is moved after its first use (any
/// function calls below).
#[inline]
pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) }

/// Acquire shared access to the underlying lock, blocking the current
/// thread to do so.
///
/// Behavior is undefined if the rwlock has been moved between this and any
/// previous methodo call.
#[inline]
pub unsafe fn read(&self) { self.0.read() }

/// Attempt to acquire shared access to this lock, returning whether it
/// succeeded or not.
///
/// This function does not block the current thread.
///
/// Behavior is undefined if the rwlock has been moved between this and any
/// previous methodo call.
#[inline]
pub unsafe fn try_read(&self) -> bool { self.0.try_read() }

/// Acquire write access to the underlying lock, blocking the current thread
/// to do so.
///
/// Behavior is undefined if the rwlock has been moved between this and any
/// previous methodo call.
#[inline]
pub unsafe fn write(&self) { self.0.write() }

/// Attempt to acquire exclusive access to this lock, returning whether it
/// succeeded or not.
///
/// This function does not block the current thread.
///
/// Behavior is undefined if the rwlock has been moved between this and any
/// previous methodo call.
#[inline]
pub unsafe fn try_write(&self) -> bool { self.0.try_write() }

/// Unlock previously acquired shared access to this lock.
///
/// Behavior is undefined if the current thread does not have shared access.
#[inline]
pub unsafe fn read_unlock(&self) { self.0.read_unlock() }

/// Unlock previously acquired exclusive access to this lock.
///
/// Behavior is undefined if the current thread does not currently have
/// exclusive access.
#[inline]
pub unsafe fn write_unlock(&self) { self.0.write_unlock() }

/// Destroy OS-related resources with this RWLock.
///
/// Behavior is undefined if there are any currently active users of this
/// lock.
#[inline]
pub unsafe fn destroy(&self) { self.0.destroy() }
}
@@ -0,0 +1,83 @@
// Copyright 2014 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.

use cell::UnsafeCell;
use libc;
use sys::mutex::{mod, Mutex};
use sys::sync as ffi;
use time::Duration;

pub struct Condvar { inner: UnsafeCell<ffi::pthread_cond_t> }

pub const CONDVAR_INIT: Condvar = Condvar {
inner: UnsafeCell { value: ffi::PTHREAD_COND_INITIALIZER },
};

impl Condvar {
#[inline]
pub unsafe fn new() -> Condvar {
// Might be moved and address is changing it is better to avoid
// initialization of potentially opaque OS data before it landed
Condvar { inner: UnsafeCell::new(ffi::PTHREAD_COND_INITIALIZER) }
}

#[inline]
pub unsafe fn notify_one(&self) {
let r = ffi::pthread_cond_signal(self.inner.get());
debug_assert_eq!(r, 0);
}

#[inline]
pub unsafe fn notify_all(&self) {
let r = ffi::pthread_cond_broadcast(self.inner.get());
debug_assert_eq!(r, 0);
}

#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) {
let r = ffi::pthread_cond_wait(self.inner.get(), mutex::raw(mutex));
debug_assert_eq!(r, 0);
}

pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
assert!(dur >= Duration::nanoseconds(0));

// First, figure out what time it currently is
let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 };
let r = ffi::gettimeofday(&mut tv, 0 as *mut _);
debug_assert_eq!(r, 0);

// Offset that time with the specified duration
let abs = Duration::seconds(tv.tv_sec as i64) +
Duration::microseconds(tv.tv_usec as i64) +
dur;
let ns = abs.num_nanoseconds().unwrap() as u64;
let timeout = libc::timespec {
tv_sec: (ns / 1000000000) as libc::time_t,
tv_nsec: (ns % 1000000000) as libc::c_long,
};

// And wait!
let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
&timeout);
if r != 0 {
debug_assert_eq!(r as int, libc::ETIMEDOUT as int);
false
} else {
true
}
}

#[inline]
pub unsafe fn destroy(&self) {
let r = ffi::pthread_cond_destroy(self.inner.get());
debug_assert_eq!(r, 0);
}
}
@@ -34,14 +34,18 @@ macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (

pub mod c;
pub mod ext;
pub mod condvar;
pub mod fs;
pub mod helper_signal;
pub mod mutex;
pub mod os;
pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod sync;
pub mod tcp;
pub mod timer;
pub mod thread_local;
pub mod timer;
pub mod tty;
pub mod udp;

@@ -0,0 +1,52 @@
// Copyright 2014 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.

use cell::UnsafeCell;
use sys::sync as ffi;
use sys_common::mutex;

pub struct Mutex { inner: UnsafeCell<ffi::pthread_mutex_t> }

#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut ffi::pthread_mutex_t {
m.inner.get()
}

pub const MUTEX_INIT: Mutex = Mutex {
inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER },
};

impl Mutex {
#[inline]
pub unsafe fn new() -> Mutex {
// Might be moved and address is changing it is better to avoid
// initialization of potentially opaque OS data before it landed
MUTEX_INIT
}
#[inline]
pub unsafe fn lock(&self) {
let r = ffi::pthread_mutex_lock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn unlock(&self) {
let r = ffi::pthread_mutex_unlock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
ffi::pthread_mutex_trylock(self.inner.get()) == 0
}
#[inline]
pub unsafe fn destroy(&self) {
let r = ffi::pthread_mutex_destroy(self.inner.get());
debug_assert_eq!(r, 0);
}
}
@@ -0,0 +1,57 @@
// Copyright 2014 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.

use cell::UnsafeCell;
use sys::sync as ffi;

pub struct RWLock { inner: UnsafeCell<ffi::pthread_rwlock_t> }

pub const RWLOCK_INIT: RWLock = RWLock {
inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER },
};

impl RWLock {
#[inline]
pub unsafe fn new() -> RWLock {
// Might be moved and address is changing it is better to avoid
// initialization of potentially opaque OS data before it landed
RWLOCK_INIT
}
#[inline]
pub unsafe fn read(&self) {
let r = ffi::pthread_rwlock_rdlock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
ffi::pthread_rwlock_tryrdlock(self.inner.get()) == 0
}
#[inline]
pub unsafe fn write(&self) {
let r = ffi::pthread_rwlock_wrlock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
ffi::pthread_rwlock_trywrlock(self.inner.get()) == 0
}
#[inline]
pub unsafe fn read_unlock(&self) {
let r = ffi::pthread_rwlock_unlock(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
pub unsafe fn write_unlock(&self) { self.read_unlock() }
#[inline]
pub unsafe fn destroy(&self) {
let r = ffi::pthread_rwlock_destroy(self.inner.get());
debug_assert_eq!(r, 0);
}
}
@@ -0,0 +1,208 @@
// Copyright 2014 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.

#![allow(bad_style)]

use libc;

pub use self::os::{PTHREAD_MUTEX_INITIALIZER, pthread_mutex_t};
pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t};
pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t};

extern {
// mutexes
pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;

// cvars
pub fn pthread_cond_wait(cond: *mut pthread_cond_t,
lock: *mut pthread_mutex_t) -> libc::c_int;
pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t,
lock: *mut pthread_mutex_t,
abstime: *const libc::timespec) -> libc::c_int;
pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int;
pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
pub fn gettimeofday(tp: *mut libc::timeval,
tz: *mut libc::c_void) -> libc::c_int;

// rwlocks
pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> libc::c_int;
pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
mod os {
use libc;

pub type pthread_mutex_t = *mut libc::c_void;
pub type pthread_cond_t = *mut libc::c_void;
pub type pthread_rwlock_t = *mut libc::c_void;

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _;
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _;
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod os {
use libc;

#[cfg(target_arch = "x86_64")]
const __PTHREAD_MUTEX_SIZE__: uint = 56;
#[cfg(any(target_arch = "x86",
target_arch = "arm"))]
const __PTHREAD_MUTEX_SIZE__: uint = 40;

#[cfg(target_arch = "x86_64")]
const __PTHREAD_COND_SIZE__: uint = 40;
#[cfg(any(target_arch = "x86",
target_arch = "arm"))]
const __PTHREAD_COND_SIZE__: uint = 24;

#[cfg(target_arch = "x86_64")]
const __PTHREAD_RWLOCK_SIZE__: uint = 192;
#[cfg(any(target_arch = "x86",
target_arch = "arm"))]
const __PTHREAD_RWLOCK_SIZE__: uint = 124;

const _PTHREAD_MUTEX_SIG_INIT: libc::c_long = 0x32AAABA7;
const _PTHREAD_COND_SIG_INIT: libc::c_long = 0x3CB0B1BB;
const _PTHREAD_RWLOCK_SIG_INIT: libc::c_long = 0x2DA8B3B4;

#[repr(C)]
pub struct pthread_mutex_t {
__sig: libc::c_long,
__opaque: [u8, ..__PTHREAD_MUTEX_SIZE__],
}
#[repr(C)]
pub struct pthread_cond_t {
__sig: libc::c_long,
__opaque: [u8, ..__PTHREAD_COND_SIZE__],
}
#[repr(C)]
pub struct pthread_rwlock_t {
__sig: libc::c_long,
__opaque: [u8, ..__PTHREAD_RWLOCK_SIZE__],
}

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
__sig: _PTHREAD_MUTEX_SIG_INIT,
__opaque: [0, ..__PTHREAD_MUTEX_SIZE__],
};
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
__sig: _PTHREAD_COND_SIG_INIT,
__opaque: [0, ..__PTHREAD_COND_SIZE__],
};
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
__sig: _PTHREAD_RWLOCK_SIG_INIT,
__opaque: [0, ..__PTHREAD_RWLOCK_SIZE__],
};
}

#[cfg(target_os = "linux")]
mod os {
use libc;

// minus 8 because we have an 'align' field
#[cfg(target_arch = "x86_64")]
const __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8;
#[cfg(any(target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel"))]
const __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;

#[cfg(any(target_arch = "x86_64",
target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel"))]
const __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;

#[cfg(target_arch = "x86_64")]
const __SIZEOF_PTHREAD_RWLOCK_T: uint = 56 - 8;

#[cfg(any(target_arch = "x86",
target_arch = "arm",
target_arch = "mips",
target_arch = "mipsel"))]
const __SIZEOF_PTHREAD_RWLOCK_T: uint = 32 - 8;

#[repr(C)]
pub struct pthread_mutex_t {
__align: libc::c_longlong,
size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T],
}
#[repr(C)]
pub struct pthread_cond_t {
__align: libc::c_longlong,
size: [u8, ..__SIZEOF_PTHREAD_COND_T],
}
#[repr(C)]
pub struct pthread_rwlock_t {
__align: libc::c_longlong,
size: [u8, ..__SIZEOF_PTHREAD_RWLOCK_T],
}

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
__align: 0,
size: [0, ..__SIZEOF_PTHREAD_MUTEX_T],
};
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
__align: 0,
size: [0, ..__SIZEOF_PTHREAD_COND_T],
};
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
__align: 0,
size: [0, ..__SIZEOF_PTHREAD_RWLOCK_T],
};
}
#[cfg(target_os = "android")]
mod os {
use libc;

#[repr(C)]
pub struct pthread_mutex_t { value: libc::c_int }
#[repr(C)]
pub struct pthread_cond_t { value: libc::c_int }
#[repr(C)]
pub struct pthread_rwlock_t {
lock: pthread_mutex_t,
cond: pthread_cond_t,
numLocks: libc::c_int,
writerThreadId: libc::c_int,
pendingReaders: libc::c_int,
pendingWriters: libc::c_int,
reserved: [*mut libc::c_void, ..4],
}

pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
value: 0,
};
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
value: 0,
};
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
lock: PTHREAD_MUTEX_INITIALIZER,
cond: PTHREAD_COND_INITIALIZER,
numLocks: 0,
writerThreadId: 0,
pendingReaders: 0,
pendingWriters: 0,
reserved: [0 as *mut _, ..4],
};
}
@@ -0,0 +1,63 @@
// Copyright 2014 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.

use cell::UnsafeCell;
use libc::{mod, DWORD};
use libc;
use os;
use sys::mutex::{mod, Mutex};
use sys::sync as ffi;
use time::Duration;

pub struct Condvar { inner: UnsafeCell<ffi::CONDITION_VARIABLE> }

pub const CONDVAR_INIT: Condvar = Condvar {
inner: UnsafeCell { value: ffi::CONDITION_VARIABLE_INIT }
};

impl Condvar {
#[inline]
pub unsafe fn new() -> Condvar { CONDVAR_INIT }

#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) {
let r = ffi::SleepConditionVariableCS(self.inner.get(),
mutex::raw(mutex),
libc::INFINITE);
debug_assert!(r != 0);
}

pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let r = ffi::SleepConditionVariableCS(self.inner.get(),
mutex::raw(mutex),
dur.num_milliseconds() as DWORD);
if r == 0 {
const ERROR_TIMEOUT: DWORD = 0x5B4;
debug_assert_eq!(os::errno() as uint, ERROR_TIMEOUT as uint);
false
} else {
true
}
}

#[inline]
pub unsafe fn notify_one(&self) {
ffi::WakeConditionVariable(self.inner.get())
}

#[inline]
pub unsafe fn notify_all(&self) {
ffi::WakeAllConditionVariable(self.inner.get())
}

pub unsafe fn destroy(&self) {
// ...
}
}
@@ -35,11 +35,15 @@ macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (

pub mod c;
pub mod ext;
pub mod condvar;
pub mod fs;
pub mod helper_signal;
pub mod mutex;
pub mod os;
pub mod pipe;
pub mod process;
pub mod rwlock;
pub mod sync;
pub mod tcp;
pub mod thread_local;
pub mod timer;
@@ -0,0 +1,76 @@
// Copyright 2014 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.

use sync::atomic;
use alloc::{mod, heap};

use libc::DWORD;
use sys::sync as ffi;

const SPIN_COUNT: DWORD = 4000;

pub struct Mutex { inner: atomic::AtomicUint }

pub const MUTEX_INIT: Mutex = Mutex { inner: atomic::INIT_ATOMIC_UINT };

#[inline]
pub unsafe fn raw(m: &super::Mutex) -> ffi::LPCRITICAL_SECTION {
m.0.get()
}

impl Mutex {
#[inline]
pub unsafe fn new() -> Mutex {
Mutex { inner: atomic::AtomicUint::new(init_lock() as uint) }
}
#[inline]
pub unsafe fn lock(&self) {
ffi::EnterCriticalSection(self.get())
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
ffi::TryEnterCriticalSection(self.get()) != 0
}
#[inline]
pub unsafe fn unlock(&self) {
ffi::LeaveCriticalSection(self.get())
}
pub unsafe fn destroy(&self) {
let lock = self.inner.swap(0, atomic::SeqCst);
if lock != 0 { free_lock(lock as ffi::LPCRITICAL_SECTION) }
}

unsafe fn get(&self) -> ffi::LPCRITICAL_SECTION {
match self.inner.load(atomic::SeqCst) {
0 => {}
n => return n as ffi::LPCRITICAL_SECTION
}
let lock = init_lock();
match self.inner.compare_and_swap(0, lock as uint, atomic::SeqCst) {
0 => return lock as ffi::LPCRITICAL_SECTION,
_ => {}
}
free_lock(lock);
return self.inner.load(atomic::SeqCst) as ffi::LPCRITICAL_SECTION;
}
}

unsafe fn init_lock() -> ffi::LPCRITICAL_SECTION {
let block = heap::allocate(ffi::CRITICAL_SECTION_SIZE, 8)
as ffi::LPCRITICAL_SECTION;
if block.is_null() { alloc::oom() }
ffi::InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
return block;
}

unsafe fn free_lock(h: ffi::LPCRITICAL_SECTION) {
ffi::DeleteCriticalSection(h);
heap::deallocate(h as *mut _, ffi::CRITICAL_SECTION_SIZE, 8);
}
@@ -0,0 +1,53 @@
// Copyright 2014 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.

use cell::UnsafeCell;
use sys::sync as ffi;

pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> }

pub const RWLOCK_INIT: RWLock = RWLock {
inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
};

impl RWLock {
#[inline]
pub unsafe fn new() -> RWLock { RWLOCK_INIT }

#[inline]
pub unsafe fn read(&self) {
ffi::AcquireSRWLockShared(self.inner.get())
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
ffi::TryAcquireSRWLockShared(self.inner.get()) != 0
}
#[inline]
pub unsafe fn write(&self) {
ffi::AcquireSRWLockExclusive(self.inner.get())
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0
}
#[inline]
pub unsafe fn read_unlock(&self) {
ffi::ReleaseSRWLockShared(self.inner.get())
}
#[inline]
pub unsafe fn write_unlock(&self) {
ffi::ReleaseSRWLockExclusive(self.inner.get())
}

#[inline]
pub unsafe fn destroy(&self) {
// ...
}
}
@@ -0,0 +1,58 @@
// Copyright 2014 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.

use libc::{BOOL, DWORD, c_void, LPVOID};
use libc::types::os::arch::extra::BOOLEAN;

pub type LPCRITICAL_SECTION = *mut c_void;
pub type LPCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
pub type LPSRWLOCK = *mut SRWLOCK;

#[cfg(target_arch = "x86")]
pub const CRITICAL_SECTION_SIZE: uint = 24;
#[cfg(target_arch = "x86_64")]
pub const CRITICAL_SECTION_SIZE: uint = 40;

#[repr(C)]
pub struct CONDITION_VARIABLE { pub ptr: LPVOID }
#[repr(C)]
pub struct SRWLOCK { pub ptr: LPVOID }

pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE {
ptr: 0 as *mut _,
};
pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ };

extern "system" {
// critical sections
pub fn InitializeCriticalSectionAndSpinCount(
lpCriticalSection: LPCRITICAL_SECTION,
dwSpinCount: DWORD) -> BOOL;
pub fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
pub fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
pub fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
pub fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;

// condition variables
pub fn SleepConditionVariableCS(ConditionVariable: LPCONDITION_VARIABLE,
CriticalSection: LPCRITICAL_SECTION,
dwMilliseconds: DWORD) -> BOOL;
pub fn WakeConditionVariable(ConditionVariable: LPCONDITION_VARIABLE);
pub fn WakeAllConditionVariable(ConditionVariable: LPCONDITION_VARIABLE);

// slim rwlocks
pub fn AcquireSRWLockExclusive(SRWLock: LPSRWLOCK);
pub fn AcquireSRWLockShared(SRWLock: LPSRWLOCK);
pub fn ReleaseSRWLockExclusive(SRWLock: LPSRWLOCK);
pub fn ReleaseSRWLockShared(SRWLock: LPSRWLOCK);
pub fn TryAcquireSRWLockExclusive(SRWLock: LPSRWLOCK) -> BOOLEAN;
pub fn TryAcquireSRWLockShared(SRWLock: LPSRWLOCK) -> BOOLEAN;
}