-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
18 changed files
with
1,257 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use crate::alloc::{GlobalAlloc, Layout, System}; | ||
use crate::ptr; | ||
use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN}; | ||
|
||
#[stable(feature = "alloc_system_type", since = "1.28.0")] | ||
unsafe impl GlobalAlloc for System { | ||
#[inline] | ||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 { | ||
// jemalloc provides alignment less than MIN_ALIGN for small allocations. | ||
// So only rely on MIN_ALIGN if size >= align. | ||
// Also see <https://github.com/rust-lang/rust/issues/45955> and | ||
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>. | ||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { | ||
libc::malloc(layout.size()) as *mut u8 | ||
} else { | ||
aligned_malloc(&layout) | ||
} | ||
} | ||
|
||
#[inline] | ||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { | ||
// See the comment above in `alloc` for why this check looks the way it does. | ||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { | ||
libc::calloc(layout.size(), 1) as *mut u8 | ||
} else { | ||
let ptr = self.alloc(layout); | ||
if !ptr.is_null() { | ||
ptr::write_bytes(ptr, 0, layout.size()); | ||
} | ||
ptr | ||
} | ||
} | ||
|
||
#[inline] | ||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { | ||
libc::free(ptr as *mut libc::c_void) | ||
} | ||
|
||
#[inline] | ||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { | ||
if layout.align() <= MIN_ALIGN && layout.align() <= new_size { | ||
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 | ||
} else { | ||
realloc_fallback(self, ptr, layout, new_size) | ||
} | ||
} | ||
} | ||
|
||
#[inline] | ||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { | ||
let mut out = ptr::null_mut(); | ||
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. | ||
// Since these are all powers of 2, we can just use max. | ||
let align = layout.align().max(crate::mem::size_of::<usize>()); | ||
let ret = libc::posix_memalign(&mut out, align, layout.size()); | ||
if ret != 0 { ptr::null_mut() } else { out as *mut u8 } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use crate::cell::UnsafeCell; | ||
use crate::ptr; | ||
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed}; | ||
use crate::sys::locks::mutex::{self, Mutex}; | ||
use crate::sys::time::TIMESPEC_MAX; | ||
use crate::sys_common::lazy_box::{LazyBox, LazyInit}; | ||
use crate::time::Duration; | ||
|
||
extern "C" { | ||
pub fn pthread_cond_timedwait( | ||
cond: *mut libc::pthread_cond_t, | ||
lock: *mut libc::pthread_mutex_t, | ||
adstime: *const libc::timespec, | ||
) -> libc::c_int; | ||
} | ||
|
||
struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>); | ||
|
||
pub struct Condvar { | ||
inner: LazyBox<AllocatedCondvar>, | ||
mutex: AtomicPtr<libc::pthread_mutex_t>, | ||
} | ||
|
||
#[inline] | ||
fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { | ||
c.inner.0.get() | ||
} | ||
|
||
unsafe impl Send for AllocatedCondvar {} | ||
unsafe impl Sync for AllocatedCondvar {} | ||
|
||
impl LazyInit for AllocatedCondvar { | ||
fn init() -> Box<Self> { | ||
let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); | ||
|
||
let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) }; | ||
assert_eq!(r, 0); | ||
|
||
condvar | ||
} | ||
} | ||
|
||
impl Drop for AllocatedCondvar { | ||
#[inline] | ||
fn drop(&mut self) { | ||
let r = unsafe { libc::pthread_cond_destroy(self.0.get()) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
} | ||
|
||
impl Condvar { | ||
pub const fn new() -> Condvar { | ||
Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } | ||
} | ||
|
||
#[inline] | ||
fn verify(&self, mutex: *mut libc::pthread_mutex_t) { | ||
match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) { | ||
Ok(_) => {} // Stored the address | ||
Err(n) if n == mutex => {} // Lost a race to store the same address | ||
_ => panic!("attempted to use a condition variable with two mutexes"), | ||
} | ||
} | ||
|
||
#[inline] | ||
pub fn notify_one(&self) { | ||
let r = unsafe { libc::pthread_cond_signal(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
#[inline] | ||
pub fn notify_all(&self) { | ||
let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
#[inline] | ||
pub unsafe fn wait(&self, mutex: &Mutex) { | ||
let mutex = mutex::raw(mutex); | ||
self.verify(mutex); | ||
let r = libc::pthread_cond_wait(raw(self), mutex); | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { | ||
use crate::sys::time::Timespec; | ||
|
||
let mutex = mutex::raw(mutex); | ||
self.verify(mutex); | ||
|
||
let timeout = Timespec::now(libc::CLOCK_MONOTONIC) | ||
.checked_add_duration(&dur) | ||
.and_then(|t| t.to_timespec()) | ||
.unwrap_or(TIMESPEC_MAX); | ||
|
||
let r = pthread_cond_timedwait(raw(self), mutex, &timeout); | ||
assert!(r == libc::ETIMEDOUT || r == 0); | ||
r == 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pub mod condvar; | ||
#[path = "../../unix/locks/pthread_mutex.rs"] | ||
pub mod mutex; | ||
pub mod rwlock; | ||
|
||
pub(crate) use condvar::Condvar; | ||
pub(crate) use mutex::Mutex; | ||
pub(crate) use rwlock::RwLock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
use crate::cell::UnsafeCell; | ||
use crate::mem::{forget, MaybeUninit}; | ||
use crate::sys::cvt_nz; | ||
use crate::sys::locks::mutex::PthreadMutexAttr; | ||
use crate::sys_common::lazy_box::{LazyBox, LazyInit}; | ||
|
||
/// we do not supported rwlock, so use mutex to simulate rwlock. | ||
/// it's useful because so many code in std will use rwlock. | ||
struct AllocatedRwlock(UnsafeCell<libc::pthread_mutex_t>); | ||
|
||
/// also implemented by mutex | ||
pub struct RwLock { | ||
inner: LazyBox<AllocatedRwlock>, | ||
} | ||
|
||
#[inline] | ||
pub unsafe fn raw(m: &RwLock) -> *mut libc::pthread_mutex_t { | ||
m.inner.0.get() | ||
} | ||
|
||
unsafe impl Send for AllocatedRwlock {} | ||
unsafe impl Sync for AllocatedRwlock {} | ||
|
||
impl LazyInit for AllocatedRwlock { | ||
fn init() -> Box<Self> { | ||
let mutex = Box::new(AllocatedRwlock(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))); | ||
|
||
unsafe { | ||
let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); | ||
cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap(); | ||
let attr = PthreadMutexAttr(&mut attr); | ||
cvt_nz(libc::pthread_mutexattr_settype( | ||
attr.0.as_mut_ptr(), | ||
libc::PTHREAD_MUTEX_NORMAL, | ||
)) | ||
.unwrap(); | ||
cvt_nz(libc::pthread_mutex_init(mutex.0.get(), attr.0.as_ptr())).unwrap(); | ||
} | ||
|
||
mutex | ||
} | ||
|
||
fn destroy(mutex: Box<Self>) { | ||
// We're not allowed to pthread_mutex_destroy a locked mutex, | ||
// so check first if it's unlocked. | ||
if unsafe { libc::pthread_mutex_trylock(mutex.0.get()) == 0 } { | ||
unsafe { libc::pthread_mutex_unlock(mutex.0.get()) }; | ||
drop(mutex); | ||
} else { | ||
// The mutex is locked. This happens if a MutexGuard is leaked. | ||
// In this case, we just leak the Mutex too. | ||
forget(mutex); | ||
} | ||
} | ||
|
||
fn cancel_init(_: Box<Self>) { | ||
// In this case, we can just drop it without any checks, | ||
// since it cannot have been locked yet. | ||
} | ||
} | ||
|
||
impl Drop for AllocatedRwlock { | ||
#[inline] | ||
fn drop(&mut self) { | ||
let r = unsafe { libc::pthread_mutex_destroy(self.0.get()) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
} | ||
|
||
impl RwLock { | ||
#[inline] | ||
pub const fn new() -> RwLock { | ||
RwLock { inner: LazyBox::new() } | ||
} | ||
|
||
#[inline] | ||
pub fn read(&self) { | ||
let r = unsafe { libc::pthread_mutex_lock(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
#[inline] | ||
pub fn try_read(&self) -> bool { | ||
let r = unsafe { libc::pthread_mutex_lock(raw(self)) }; | ||
r == 0 | ||
} | ||
|
||
#[inline] | ||
pub fn write(&self) { | ||
let r = unsafe { libc::pthread_mutex_lock(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
#[inline] | ||
pub unsafe fn try_write(&self) -> bool { | ||
let r = unsafe { libc::pthread_mutex_lock(raw(self)) }; | ||
r == 0 | ||
} | ||
|
||
#[inline] | ||
pub unsafe fn read_unlock(&self) { | ||
let r = unsafe { libc::pthread_mutex_unlock(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
|
||
#[inline] | ||
pub unsafe fn write_unlock(&self) { | ||
let r = unsafe { libc::pthread_mutex_unlock(raw(self)) }; | ||
debug_assert_eq!(r, 0); | ||
} | ||
} |
Oops, something went wrong.