Skip to content

Commit a55c572

Browse files
committed
std: Introduce std::sync
For now, this moves the following modules to std::sync * UnsafeArc (also removed unwrap method) * mpsc_queue * spsc_queue * atomics * mpmc_bounded_queue * deque We may want to remove some of the queues, but for now this moves things out of std::rt into std::sync
1 parent dafb310 commit a55c572

File tree

15 files changed

+288
-578
lines changed

15 files changed

+288
-578
lines changed

src/libextra/arc.rs

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use sync;
4545
use sync::{Mutex, RWLock};
4646

4747
use std::cast;
48-
use std::unstable::sync::UnsafeArc;
48+
use std::sync::arc::UnsafeArc;
4949
use std::task;
5050
use std::borrow;
5151

@@ -127,20 +127,6 @@ impl<T:Freeze+Send> Arc<T> {
127127
pub fn get<'a>(&'a self) -> &'a T {
128128
unsafe { &*self.x.get_immut() }
129129
}
130-
131-
/**
132-
* Retrieve the data back out of the Arc. This function blocks until the
133-
* reference given to it is the last existing one, and then unwrap the data
134-
* instead of destroying it.
135-
*
136-
* If multiple tasks call unwrap, all but the first will fail. Do not call
137-
* unwrap from a task that holds another reference to the same Arc; it is
138-
* guaranteed to deadlock.
139-
*/
140-
pub fn unwrap(self) -> T {
141-
let Arc { x: x } = self;
142-
x.unwrap()
143-
}
144130
}
145131

146132
impl<T:Freeze + Send> Clone for Arc<T> {
@@ -247,22 +233,6 @@ impl<T:Send> MutexArc<T> {
247233
cond: cond })
248234
})
249235
}
250-
251-
/**
252-
* Retrieves the data, blocking until all other references are dropped,
253-
* exactly as arc::unwrap.
254-
*
255-
* Will additionally fail if another task has failed while accessing the arc.
256-
*/
257-
pub fn unwrap(self) -> T {
258-
let MutexArc { x: x } = self;
259-
let inner = x.unwrap();
260-
let MutexArcInner { failed: failed, data: data, .. } = inner;
261-
if failed {
262-
fail!("Can't unwrap poisoned MutexArc - another task failed inside!");
263-
}
264-
data
265-
}
266236
}
267237

268238
impl<T:Freeze + Send> MutexArc<T> {
@@ -503,23 +473,6 @@ impl<T:Freeze + Send> RWArc<T> {
503473
}
504474
}
505475
}
506-
507-
/**
508-
* Retrieves the data, blocking until all other references are dropped,
509-
* exactly as arc::unwrap.
510-
*
511-
* Will additionally fail if another task has failed while accessing the arc
512-
* in write mode.
513-
*/
514-
pub fn unwrap(self) -> T {
515-
let RWArc { x: x, .. } = self;
516-
let inner = x.unwrap();
517-
let RWArcInner { failed: failed, data: data, .. } = inner;
518-
if failed {
519-
fail!("Can't unwrap poisoned RWArc - another task failed inside!")
520-
}
521-
data
522-
}
523476
}
524477

525478
// Borrowck rightly complains about immutably aliasing the rwlock in order to
@@ -689,22 +642,6 @@ mod tests {
689642
})
690643
}
691644

692-
#[test] #[should_fail]
693-
pub fn test_mutex_arc_unwrap_poison() {
694-
let arc = MutexArc::new(1);
695-
let arc2 = ~(&arc).clone();
696-
let (p, c) = Chan::new();
697-
do task::spawn {
698-
arc2.access(|one| {
699-
c.send(());
700-
assert!(*one == 2);
701-
})
702-
}
703-
let _ = p.recv();
704-
let one = arc.unwrap();
705-
assert!(one == 1);
706-
}
707-
708645
#[test]
709646
fn test_unsafe_mutex_arc_nested() {
710647
unsafe {

src/libextra/sync.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919

2020

2121
use std::borrow;
22-
use std::unstable::sync::{Exclusive, UnsafeArc};
23-
use std::unstable::atomics;
22+
use std::unstable::sync::Exclusive;
23+
use std::sync::arc::UnsafeArc;
24+
use std::sync::atomics;
2425
use std::unstable::finally::Finally;
2526
use std::util;
2627
use std::util::NonCopyable;

src/librustc/middle/trans/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ use std::hashmap::HashMap;
146146
use std::hashmap::HashSet;
147147
use std::libc::{c_uint, c_ulonglong, c_longlong};
148148
use std::ptr;
149-
use std::unstable::atomics;
149+
use std::sync::atomics;
150150
use std::vec;
151151
use syntax::codemap::{Span, Pos};
152152
use syntax::{ast, codemap, ast_util, ast_map, opt_vec};

src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ pub mod trie;
159159
pub mod task;
160160
pub mod comm;
161161
pub mod local_data;
162+
pub mod sync;
162163

163164

164165
/* Runtime and platform support */

src/libstd/sync/arc.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Atomically reference counted data
12+
//!
13+
//! This modules contains the implementation of an atomically reference counted
14+
//! pointer for the purpose of sharing data between tasks. This is obviously a
15+
//! very unsafe primitive to use, but it has its use cases when implementing
16+
//! concurrent data structures and similar tasks.
17+
//!
18+
//! Great care must be taken to ensure that data races do not arise through the
19+
//! usage of `UnsafeArc`, and this often requires some form of external
20+
//! synchronization. The only guarantee provided to you by this class is that
21+
//! the underlying data will remain valid (not free'd) so long as the reference
22+
//! count is greater than one.
23+
24+
use cast;
25+
use clone::Clone;
26+
use kinds::Send;
27+
use ops::Drop;
28+
use ptr::RawPtr;
29+
use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire};
30+
use vec;
31+
32+
/// An atomically reference counted pointer.
33+
///
34+
/// Enforces no shared-memory safety.
35+
#[unsafe_no_drop_flag]
36+
pub struct UnsafeArc<T> {
37+
priv data: *mut ArcData<T>,
38+
}
39+
40+
struct ArcData<T> {
41+
count: AtomicUint,
42+
data: T,
43+
}
44+
45+
unsafe fn new_inner<T: Send>(data: T, refcount: uint) -> *mut ArcData<T> {
46+
let data = ~ArcData { count: AtomicUint::new(refcount), data: data };
47+
cast::transmute(data)
48+
}
49+
50+
impl<T: Send> UnsafeArc<T> {
51+
/// Creates a new `UnsafeArc` which wraps the given data.
52+
pub fn new(data: T) -> UnsafeArc<T> {
53+
unsafe { UnsafeArc { data: new_inner(data, 1) } }
54+
}
55+
56+
/// As new(), but returns an extra pre-cloned handle.
57+
pub fn new2(data: T) -> (UnsafeArc<T>, UnsafeArc<T>) {
58+
unsafe {
59+
let ptr = new_inner(data, 2);
60+
(UnsafeArc { data: ptr }, UnsafeArc { data: ptr })
61+
}
62+
}
63+
64+
/// As new(), but returns a vector of as many pre-cloned handles as
65+
/// requested.
66+
pub fn newN(data: T, num_handles: uint) -> ~[UnsafeArc<T>] {
67+
unsafe {
68+
if num_handles == 0 {
69+
~[] // need to free data here
70+
} else {
71+
let ptr = new_inner(data, num_handles);
72+
vec::from_fn(num_handles, |_| UnsafeArc { data: ptr })
73+
}
74+
}
75+
}
76+
77+
/// Gets a pointer to the inner shared data. Note that care must be taken to
78+
/// ensure that the outer `UnsafeArc` does not fall out of scope while this
79+
/// pointer is in use, otherwise it could possibly contain a use-after-free.
80+
#[inline]
81+
pub fn get(&self) -> *mut T {
82+
unsafe {
83+
assert!((*self.data).count.load(Relaxed) > 0);
84+
return &mut (*self.data).data as *mut T;
85+
}
86+
}
87+
88+
/// Gets an immutable pointer to the inner shared data. This has the same
89+
/// caveats as the `get` method.
90+
#[inline]
91+
pub fn get_immut(&self) -> *T {
92+
unsafe {
93+
assert!((*self.data).count.load(Relaxed) > 0);
94+
return &(*self.data).data as *T;
95+
}
96+
}
97+
}
98+
99+
impl<T: Send> Clone for UnsafeArc<T> {
100+
fn clone(&self) -> UnsafeArc<T> {
101+
unsafe {
102+
// This barrier might be unnecessary, but I'm not sure...
103+
let old_count = (*self.data).count.fetch_add(1, Acquire);
104+
assert!(old_count >= 1);
105+
return UnsafeArc { data: self.data };
106+
}
107+
}
108+
}
109+
110+
#[unsafe_destructor]
111+
impl<T> Drop for UnsafeArc<T>{
112+
fn drop(&mut self) {
113+
unsafe {
114+
// Happens when destructing an unwrapper's handle and from
115+
// `#[unsafe_no_drop_flag]`
116+
if self.data.is_null() {
117+
return
118+
}
119+
// Must be acquire+release, not just release, to make sure this
120+
// doesn't get reordered to after the unwrapper pointer load.
121+
let old_count = (*self.data).count.fetch_sub(1, SeqCst);
122+
assert!(old_count >= 1);
123+
if old_count == 1 {
124+
let _: ~ArcData<T> = cast::transmute(self.data);
125+
}
126+
}
127+
}
128+
}
129+
130+
#[cfg(test)]
131+
mod tests {
132+
use prelude::*;
133+
use super::UnsafeArc;
134+
use task;
135+
use mem::size_of;
136+
137+
#[test]
138+
fn test_size() {
139+
assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
140+
}
141+
142+
#[test]
143+
fn arclike_newN() {
144+
// Tests that the many-refcounts-at-once constructors don't leak.
145+
let _ = UnsafeArc::new2(~~"hello");
146+
let x = UnsafeArc::newN(~~"hello", 0);
147+
assert_eq!(x.len(), 0)
148+
let x = UnsafeArc::newN(~~"hello", 1);
149+
assert_eq!(x.len(), 1)
150+
let x = UnsafeArc::newN(~~"hello", 10);
151+
assert_eq!(x.len(), 10)
152+
}
153+
}

src/libstd/unstable/atomics.rs renamed to src/libstd/sync/atomics.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
/*!
1212
* Atomic types
1313
*
14-
* Basic atomic types supporting atomic operations. Each method takes an `Ordering` which
15-
* represents the strength of the memory barrier for that operation. These orderings are the same
16-
* as C++11 atomic orderings [http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync]
14+
* Basic atomic types supporting atomic operations. Each method takes an
15+
* `Ordering` which represents the strength of the memory barrier for that
16+
* operation. These orderings are the same as C++11 atomic orderings
17+
* [http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync]
1718
*
1819
* All atomic types are a single word in size.
1920
*/
2021

22+
#[allow(missing_doc)];
23+
2124
use unstable::intrinsics;
2225
use cast;
2326
use option::{Option,Some,None};

src/libstd/rt/deque.rs renamed to src/libstd/sync/deque.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,18 @@
5050

5151
use cast;
5252
use clone::Clone;
53-
use iter::range;
53+
use iter::{range, Iterator};
5454
use kinds::Send;
5555
use libc;
5656
use mem;
5757
use ops::Drop;
5858
use option::{Option, Some, None};
5959
use ptr;
60-
use unstable::atomics::{AtomicInt, AtomicPtr, SeqCst};
61-
use unstable::sync::{UnsafeArc, Exclusive};
60+
use ptr::RawPtr;
61+
use sync::arc::UnsafeArc;
62+
use sync::atomics::{AtomicInt, AtomicPtr, SeqCst};
63+
use unstable::sync::Exclusive;
64+
use vec::{OwnedVector, ImmutableVector};
6265

6366
// Once the queue is less than 1/K full, then it will be downsized. Note that
6467
// the deque requires that this number be less than 2.
@@ -399,8 +402,8 @@ mod tests {
399402
use rt::thread::Thread;
400403
use rand;
401404
use rand::Rng;
402-
use unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, SeqCst,
403-
AtomicUint, INIT_ATOMIC_UINT};
405+
use sync::atomics::{AtomicBool, INIT_ATOMIC_BOOL, SeqCst,
406+
AtomicUint, INIT_ATOMIC_UINT};
404407
use vec;
405408

406409
#[test]

src/libstd/sync/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Useful synchronization primitives
12+
//!
13+
//! This modules contains useful safe and unsafe synchronization primitives.
14+
//! Most of the primitives in this module do not provide any sort of locking
15+
//! and/or blocking at all, but rather provide the necessary tools to build
16+
//! other types of concurrent primitives.
17+
18+
pub mod arc;
19+
pub mod atomics;
20+
pub mod deque;
21+
pub mod mpmc_bounded_queue;
22+
pub mod mpsc_queue;
23+
pub mod spsc_queue;

src/libstd/rt/mpmc_bounded_queue.rs renamed to src/libstd/sync/mpmc_bounded_queue.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,17 @@
2525
* policies, either expressed or implied, of Dmitry Vyukov.
2626
*/
2727

28+
#[allow(missing_doc, dead_code)];
29+
2830
// http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
2931

30-
use unstable::sync::UnsafeArc;
31-
use unstable::atomics::{AtomicUint,Relaxed,Release,Acquire};
32-
use option::*;
33-
use vec;
3432
use clone::Clone;
3533
use kinds::Send;
3634
use num::{Exponential,Algebraic,Round};
35+
use option::{Option, Some, None};
36+
use sync::arc::UnsafeArc;
37+
use sync::atomics::{AtomicUint,Relaxed,Release,Acquire};
38+
use vec;
3739

3840
struct Node<T> {
3941
sequence: AtomicUint,

0 commit comments

Comments
 (0)