Skip to content

Commit 39c1ecd

Browse files
committed
auto merge of #14396 : vhbit/rust/opaque-mutex, r=alexcrichton
On some systems (iOS for example) mutex is represented by opaque data structure which doesn't play well with simple data copy. Therefore mutex should be initialized from magic static value and filled by OS only when it landed RC. Initially written for iOS but since landing iOS support might require quite a lot of time I think it is better to split parts which aren't directly related to iOS and merge them in
2 parents e72a21b + 41b65d3 commit 39c1ecd

File tree

3 files changed

+31
-23
lines changed

3 files changed

+31
-23
lines changed

src/libstd/comm/mod.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -600,20 +600,22 @@ impl<T: Send> Clone for Sender<T> {
600600
let (packet, sleeper) = match *unsafe { self.inner() } {
601601
Oneshot(ref p) => {
602602
let a = Arc::new(Unsafe::new(shared::Packet::new()));
603-
match unsafe {
604-
(*p.get()).upgrade(Receiver::new(Shared(a.clone())))
605-
} {
606-
oneshot::UpSuccess | oneshot::UpDisconnected => (a, None),
607-
oneshot::UpWoke(task) => (a, Some(task))
603+
unsafe {
604+
(*a.get()).postinit_lock();
605+
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
606+
oneshot::UpSuccess | oneshot::UpDisconnected => (a, None),
607+
oneshot::UpWoke(task) => (a, Some(task))
608+
}
608609
}
609610
}
610611
Stream(ref p) => {
611612
let a = Arc::new(Unsafe::new(shared::Packet::new()));
612-
match unsafe {
613-
(*p.get()).upgrade(Receiver::new(Shared(a.clone())))
614-
} {
615-
stream::UpSuccess | stream::UpDisconnected => (a, None),
616-
stream::UpWoke(task) => (a, Some(task)),
613+
unsafe {
614+
(*a.get()).postinit_lock();
615+
match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) {
616+
stream::UpSuccess | stream::UpDisconnected => (a, None),
617+
stream::UpWoke(task) => (a, Some(task)),
618+
}
617619
}
618620
}
619621
Shared(ref p) => {

src/libstd/comm/shared.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ pub enum Failure {
6666
}
6767

6868
impl<T: Send> Packet<T> {
69-
// Creation of a packet *must* be followed by a call to inherit_blocker
69+
// Creation of a packet *must* be followed by a call to postinit_lock
70+
// and later by inherit_blocker
7071
pub fn new() -> Packet<T> {
7172
let p = Packet {
7273
queue: mpsc::Queue::new(),
@@ -78,11 +79,18 @@ impl<T: Send> Packet<T> {
7879
sender_drain: atomics::AtomicInt::new(0),
7980
select_lock: unsafe { NativeMutex::new() },
8081
};
81-
// see comments in inherit_blocker about why we grab this lock
82-
unsafe { p.select_lock.lock_noguard() }
8382
return p;
8483
}
8584

85+
// This function should be used after newly created Packet
86+
// was wrapped with an Arc
87+
// In other case mutex data will be duplicated while clonning
88+
// and that could cause problems on platforms where it is
89+
// represented by opaque data structure
90+
pub fn postinit_lock(&mut self) {
91+
unsafe { self.select_lock.lock_noguard() }
92+
}
93+
8694
// This function is used at the creation of a shared packet to inherit a
8795
// previously blocked task. This is done to prevent spurious wakeups of
8896
// tasks in select().

src/libstd/unstable/mutex.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ impl StaticNativeMutex {
9898
///
9999
/// Note that a mutex created in this way needs to be explicit
100100
/// freed with a call to `destroy` or it will leak.
101+
/// Also it is important to avoid locking until mutex has stopped moving
101102
pub unsafe fn new() -> StaticNativeMutex {
102103
StaticNativeMutex { inner: imp::Mutex::new() }
103104
}
@@ -172,6 +173,7 @@ impl NativeMutex {
172173
///
173174
/// The user must be careful to ensure the mutex is not locked when its is
174175
/// being destroyed.
176+
/// Also it is important to avoid locking until mutex has stopped moving
175177
pub unsafe fn new() -> NativeMutex {
176178
NativeMutex { inner: StaticNativeMutex::new() }
177179
}
@@ -262,7 +264,6 @@ mod imp {
262264
use libc;
263265
use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
264266
pthread_mutex_t, pthread_cond_t};
265-
use mem;
266267
use ty::Unsafe;
267268
use kinds::marker;
268269

@@ -294,6 +295,7 @@ mod imp {
294295
static __PTHREAD_MUTEX_SIZE__: uint = 40;
295296
#[cfg(target_arch = "x86")]
296297
static __PTHREAD_COND_SIZE__: uint = 24;
298+
297299
static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7;
298300
static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB;
299301

@@ -389,14 +391,14 @@ mod imp {
389391

390392
impl Mutex {
391393
pub unsafe fn new() -> Mutex {
394+
// As mutex might be moved and address is changing it
395+
// is better to avoid initialization of potentially
396+
// opaque OS data before it landed
392397
let m = Mutex {
393-
lock: Unsafe::new(mem::zeroed()),
394-
cond: Unsafe::new(mem::zeroed()),
398+
lock: Unsafe::new(PTHREAD_MUTEX_INITIALIZER),
399+
cond: Unsafe::new(PTHREAD_COND_INITIALIZER),
395400
};
396401

397-
pthread_mutex_init(m.lock.get(), 0 as *libc::c_void);
398-
pthread_cond_init(m.cond.get(), 0 as *libc::c_void);
399-
400402
return m;
401403
}
402404

@@ -416,11 +418,7 @@ mod imp {
416418
}
417419

418420
extern {
419-
fn pthread_mutex_init(lock: *mut pthread_mutex_t,
420-
attr: *pthread_mutexattr_t) -> libc::c_int;
421421
fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
422-
fn pthread_cond_init(cond: *mut pthread_cond_t,
423-
attr: *pthread_condattr_t) -> libc::c_int;
424422
fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
425423
fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
426424
fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;

0 commit comments

Comments
 (0)