extern crate alloc;
use crate::{
alloc::{SyncVec, SyncVecError},
sync_types::{self, Lock as _, WeakSyncRcPtr as _},
};
use core::sync::atomic;
use core::{cell, convert, future, marker, num, ops, pin, task};
#[derive(Clone, Copy, Debug)]
pub enum AsyncSemaphoreError {
RequestExceedsSemaphoreCapacity,
StaleSemaphore,
MemoryAllocationFailure,
Internal,
}
enum AsyncSemaphoreLeaseGrantCount {
TrivialLease,
Leases { count: num::NonZeroUsize },
ExclusiveAll,
}
impl convert::From<usize> for AsyncSemaphoreLeaseGrantCount {
fn from(value: usize) -> Self {
if value == 0 {
AsyncSemaphoreLeaseGrantCount::TrivialLease
} else {
AsyncSemaphoreLeaseGrantCount::Leases {
count: num::NonZeroUsize::new(value).unwrap(),
}
}
}
}
struct AsyncSemaphoreQueueEntry {
leases_requested: AsyncSemaphoreLeaseGrantCount,
waker: Option<task::Waker>,
waiter_id: num::NonZeroU64,
}
struct AsyncSemaphoreQueue {
queue: SyncVec<AsyncSemaphoreQueueEntry>,
max_leases: usize,
last_waiter_id: u64,
enqueued_trivial_lease_waiters: usize,
enqueued_exclusive_all_waiters: usize,
}
impl AsyncSemaphoreQueue {
fn new(max_leases: usize) -> Self {
Self {
queue: SyncVec::new(),
max_leases,
last_waiter_id: 0,
enqueued_trivial_lease_waiters: 0,
enqueued_exclusive_all_waiters: 0,
}
}
fn waiter_position(&self, waiter_id: num::NonZeroU64) -> Option<usize> {
self.queue.iter().position(|entry| entry.waiter_id == waiter_id)
}
fn poll_waiter(&mut self, waiter_id: num::NonZeroU64, waker: task::Waker) -> bool {
if let Some(index) = self.waiter_position(waiter_id) {
self.queue[index].waker = Some(waker);
false
} else {
true
}
}
fn remove_entry(&mut self, index: usize) {
match self.queue[index].leases_requested {
AsyncSemaphoreLeaseGrantCount::TrivialLease => {
debug_assert!(self.enqueued_trivial_lease_waiters != 0);
self.enqueued_trivial_lease_waiters -= 1;
}
AsyncSemaphoreLeaseGrantCount::ExclusiveAll => {
debug_assert!(self.enqueued_exclusive_all_waiters != 0);
self.enqueued_exclusive_all_waiters -= 1;
}
AsyncSemaphoreLeaseGrantCount::Leases { .. } => (),
}
self.queue.remove(index);
}
fn remove_waiter(&mut self, waiter_id: num::NonZeroU64) {
let index = self.waiter_position(waiter_id).unwrap();
self.remove_entry(index);
}
fn enqueue_waiter<'a, QL: sync_types::Lock<Self>>(
queue_lock: &'a sync_types::LockForInner<'a, Self, QL, AsyncSemaphoreQueueDerefInnerQueueTag>,
this_guard: QL::Guard<'a>,
leases_requested: AsyncSemaphoreLeaseGrantCount,
) -> (QL::Guard<'a>, Result<num::NonZeroU64, AsyncSemaphoreError>) {
let queue_guard =
sync_types::LockForInnerGuard::<'_, _, _, AsyncSemaphoreQueueDerefInnerQueueTag>::from_outer(this_guard);
let (queue_guard, r) = SyncVec::try_reserve(queue_lock, queue_guard, 1);
if let Err(e) = r {
return (
queue_guard.into_outer(),
Err(match e {
SyncVecError::MemoryAllocationFailure => AsyncSemaphoreError::MemoryAllocationFailure,
}),
);
}
let mut this_guard = queue_guard.into_outer();
this_guard.last_waiter_id += 1;
let waiter_id = num::NonZeroU64::new(this_guard.last_waiter_id).unwrap();
this_guard.queue.push(AsyncSemaphoreQueueEntry {
leases_requested,
waker: None,
waiter_id,
});
(this_guard, Ok(waiter_id))
}
fn has_uncancelled_waiters(&self) -> bool {
self.queue.iter().any(|entry| match entry.leases_requested {
AsyncSemaphoreLeaseGrantCount::TrivialLease => true,
AsyncSemaphoreLeaseGrantCount::Leases { count } => count.get() <= self.max_leases,
AsyncSemaphoreLeaseGrantCount::ExclusiveAll => true,
})
}
fn has_trivial_lease_waiters(&self) -> bool {
let has_trivial_lease_waiters = self.enqueued_trivial_lease_waiters != 0;
debug_assert_eq!(
has_trivial_lease_waiters,
self.queue
.iter()
.any(|entry| { matches!(entry.leases_requested, AsyncSemaphoreLeaseGrantCount::TrivialLease) })
);
has_trivial_lease_waiters
}
fn has_exclusive_all_waiters(&self) -> bool {
let has_exclusive_all_waiters = self.enqueued_exclusive_all_waiters != 0;
debug_assert_eq!(
has_exclusive_all_waiters,
self.queue
.iter()
.any(|entry| { matches!(entry.leases_requested, AsyncSemaphoreLeaseGrantCount::ExclusiveAll) })
);
has_exclusive_all_waiters
}
}
struct AsyncSemaphoreQueueDerefInnerQueueTag;
impl sync_types::DerefInnerByTag<AsyncSemaphoreQueueDerefInnerQueueTag> for AsyncSemaphoreQueue {
crate::impl_deref_inner_by_tag!(queue, SyncVec<AsyncSemaphoreQueueEntry>);
}
impl sync_types::DerefMutInnerByTag<AsyncSemaphoreQueueDerefInnerQueueTag> for AsyncSemaphoreQueue {
crate::impl_deref_mut_inner_by_tag!(queue);
}
struct AsyncSemaphoreState<ST: sync_types::SyncTypes> {
queue: ST::Lock<AsyncSemaphoreQueue>,
leases_granted: atomic::AtomicUsize,
trivial_leases_granted: atomic::AtomicUsize,
}
impl<ST: sync_types::SyncTypes> AsyncSemaphoreState<ST> {
const TRIVIAL_LEASES_GRANTED_NO_EXCLUSIVE_ALL_WAITERS_OFFSET: usize = 1;
fn new(max_leases: usize) -> Self {
debug_assert!(max_leases < usize::MAX);
Self {
queue: ST::Lock::from(AsyncSemaphoreQueue::new(max_leases)),
leases_granted: atomic::AtomicUsize::new(0),
trivial_leases_granted: atomic::AtomicUsize::new(
Self::TRIVIAL_LEASES_GRANTED_NO_EXCLUSIVE_ALL_WAITERS_OFFSET,
),
}
}
fn max_leases(&self) -> usize {
self.queue.lock().max_leases
}
fn prepare_acquire_leases(&self, leases_requested: usize) -> Result<Option<num::NonZeroU64>, AsyncSemaphoreError> {
let locked_queue = self.queue.lock();
if self._try_acquire_leases(&locked_queue, leases_requested)? {
Ok(None)
} else {
let queue_lock_for_inner_queue =
sync_types::LockForInner::<'_, _, _, AsyncSemaphoreQueueDerefInnerQueueTag>::from_outer(&self.queue);
match AsyncSemaphoreQueue::enqueue_waiter(
&queue_lock_for_inner_queue,
locked_queue,
AsyncSemaphoreLeaseGrantCount::from(leases_requested),
) {
(mut locked_queue, Ok(waiter_id)) => {
if leases_requested == 0 {
locked_queue.enqueued_trivial_lease_waiters += 1;
}
Ok(Some(waiter_id))
}
(_, Err(e)) => Err(e),
}
}
}
fn prepare_acquire_exclusive_all(&self) -> Result<Option<num::NonZeroU64>, AsyncSemaphoreError> {
let mut locked_queue = self.queue.lock();
self.acquire_exclusive_all_begin(&locked_queue);
if self._try_acquire_exclusive_all(&locked_queue) {
self.acquire_exclusive_all_end(&locked_queue);
Ok(None)
} else {
locked_queue.enqueued_exclusive_all_waiters += 1;
let queue_lock_for_inner_queue =
sync_types::LockForInner::<'_, _, _, AsyncSemaphoreQueueDerefInnerQueueTag>::from_outer(&self.queue);
match AsyncSemaphoreQueue::enqueue_waiter(
&queue_lock_for_inner_queue,
locked_queue,
AsyncSemaphoreLeaseGrantCount::ExclusiveAll,
) {
(_, Ok(waiter_id)) => Ok(Some(waiter_id)),
(mut locked_queue, Err(e)) => {
locked_queue.enqueued_exclusive_all_waiters -= 1;
self.acquire_exclusive_all_end(&locked_queue);
Err(e)
}
}
}
}
fn try_acquire_leases(&self, leases_requested: usize) -> Result<bool, AsyncSemaphoreError> {
let locked_queue = self.queue.lock();
self._try_acquire_leases(&locked_queue, leases_requested)
}
fn try_acquire_exclusive_all(&self) -> bool {
let locked_queue = self.queue.lock();
self.acquire_exclusive_all_begin(&locked_queue);
let granted = self._try_acquire_exclusive_all(&locked_queue);
self.acquire_exclusive_all_end(&locked_queue);
granted
}
fn _try_acquire_trivial_lease(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) -> bool {
!locked_queue.has_exclusive_all_waiters()
&& self.try_grant_one(locked_queue, &AsyncSemaphoreLeaseGrantCount::TrivialLease)
}
fn _try_acquire_leases(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
leases_requested: usize,
) -> Result<bool, AsyncSemaphoreError> {
if leases_requested == 0 {
Ok(self._try_acquire_trivial_lease(locked_queue))
} else if locked_queue.max_leases < leases_requested {
Err(AsyncSemaphoreError::RequestExceedsSemaphoreCapacity)
} else if !locked_queue.has_uncancelled_waiters()
&& self.try_grant_one(locked_queue, &AsyncSemaphoreLeaseGrantCount::from(leases_requested))
{
Ok(true)
} else {
Ok(false)
}
}
fn _try_acquire_exclusive_all(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) -> bool {
!locked_queue.has_uncancelled_waiters()
&& self.try_grant_one(locked_queue, &AsyncSemaphoreLeaseGrantCount::ExclusiveAll)
}
fn try_grant_one(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
leases_requested: &AsyncSemaphoreLeaseGrantCount,
) -> bool {
match leases_requested {
AsyncSemaphoreLeaseGrantCount::TrivialLease => {
if !self.is_exclusive_all_granted(locked_queue) {
self.trivial_leases_granted.fetch_add(1, atomic::Ordering::Relaxed);
true
} else {
false
}
}
AsyncSemaphoreLeaseGrantCount::Leases { count } => {
let leases_granted = self.leases_granted.load(atomic::Ordering::Relaxed);
debug_assert!(count.get() <= locked_queue.max_leases);
if locked_queue.max_leases >= leases_granted + count.get() {
self.leases_granted
.store(leases_granted + count.get(), atomic::Ordering::Relaxed);
true
} else {
false
}
}
AsyncSemaphoreLeaseGrantCount::ExclusiveAll => {
let leases_granted = self.leases_granted.load(atomic::Ordering::Acquire);
if leases_granted == 0 {
atomic::fence(atomic::Ordering::SeqCst);
let trivial_leases_granted = self.trivial_leases_granted.load(atomic::Ordering::Acquire);
if trivial_leases_granted == 0 {
self.leases_granted
.store(locked_queue.max_leases + 1, atomic::Ordering::Relaxed);
true
} else {
false
}
} else {
false
}
}
}
}
fn acquire_exclusive_all_begin(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) {
if !locked_queue.has_exclusive_all_waiters() {
debug_assert_ne!(self.trivial_leases_granted.load(atomic::Ordering::Relaxed), 0);
self.trivial_leases_granted.fetch_sub(
Self::TRIVIAL_LEASES_GRANTED_NO_EXCLUSIVE_ALL_WAITERS_OFFSET,
atomic::Ordering::Relaxed,
);
}
}
fn acquire_exclusive_all_end(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) {
if !locked_queue.has_exclusive_all_waiters() {
self.trivial_leases_granted.fetch_add(
Self::TRIVIAL_LEASES_GRANTED_NO_EXCLUSIVE_ALL_WAITERS_OFFSET,
atomic::Ordering::Relaxed,
);
}
}
fn return_trivial_lease_grant(&self) -> bool {
if self.trivial_leases_granted.fetch_sub(1, atomic::Ordering::Release) == 1 {
if self.leases_granted.load(atomic::Ordering::Relaxed) == 0 {
true
} else {
atomic::fence(atomic::Ordering::SeqCst);
self.leases_granted.load(atomic::Ordering::Relaxed) == 0
}
} else {
false
}
}
fn return_grant(
&self,
locked_queue: &mut <ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
leases: AsyncSemaphoreLeaseGrantCount,
) {
let leases_granted = self.leases_granted.load(atomic::Ordering::Relaxed);
let mut wake = true;
match leases {
AsyncSemaphoreLeaseGrantCount::TrivialLease => {
wake = self.return_trivial_lease_grant();
}
AsyncSemaphoreLeaseGrantCount::Leases { count } => {
debug_assert!(count.get() <= leases_granted);
let leases_granted = leases_granted - count.get();
self.leases_granted.store(leases_granted, atomic::Ordering::Release);
}
AsyncSemaphoreLeaseGrantCount::ExclusiveAll => {
debug_assert!(self.is_exclusive_all_granted(locked_queue));
self.leases_granted.store(0, atomic::Ordering::Relaxed);
}
}
if wake {
self.wake_completed_waiters(locked_queue);
}
}
fn wake_completed_waiters(
&self,
locked_queue: &mut <ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) {
let mut i = 0;
while i < locked_queue.queue.len() {
let entry = &locked_queue.queue[i];
if let AsyncSemaphoreLeaseGrantCount::Leases { count } = &entry.leases_requested {
if count.get() > locked_queue.max_leases {
i += 1;
continue;
}
}
let is_exclusive_all_waiter =
matches!(&entry.leases_requested, AsyncSemaphoreLeaseGrantCount::ExclusiveAll);
if self.try_grant_one(locked_queue, &entry.leases_requested) {
let entry = &mut locked_queue.queue[i];
if let Some(waker) = entry.waker.take() {
waker.wake();
}
locked_queue.remove_entry(i);
if is_exclusive_all_waiter {
self.acquire_exclusive_all_end(locked_queue);
}
} else if !is_exclusive_all_waiter
&& !self.is_exclusive_all_granted(locked_queue)
&& locked_queue.has_trivial_lease_waiters()
{
i += 1;
} else {
break;
}
}
}
fn wake_failed_waiters(
&self,
locked_queue: &mut <ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) {
let mut failed_some = false;
let max_leases = locked_queue.max_leases;
for entry in locked_queue.queue.iter_mut() {
match entry.leases_requested {
AsyncSemaphoreLeaseGrantCount::Leases { count } if max_leases < count.get() => {
failed_some = true;
if let Some(waker) = entry.waker.take() {
waker.wake();
}
}
_ => (),
}
}
if failed_some {
self.wake_completed_waiters(locked_queue);
}
}
fn cancel_waiter(
&self,
locked_queue: &mut <ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
waiter_id: num::NonZeroU64,
leases_requested: AsyncSemaphoreLeaseGrantCount,
) {
match locked_queue.waiter_position(waiter_id) {
Some(index) => {
locked_queue.remove_entry(index);
match leases_requested {
AsyncSemaphoreLeaseGrantCount::TrivialLease => {
debug_assert!(
self.is_exclusive_all_granted(locked_queue) || locked_queue.has_exclusive_all_waiters()
);
}
AsyncSemaphoreLeaseGrantCount::Leases { count } => {
if count.get() > 1 {
self.wake_completed_waiters(locked_queue);
}
}
AsyncSemaphoreLeaseGrantCount::ExclusiveAll => {
self.acquire_exclusive_all_end(locked_queue);
self.wake_completed_waiters(locked_queue);
}
}
}
None => {
self.return_grant(locked_queue, leases_requested);
}
}
}
fn is_exclusive_all_granted(
&self,
locked_queue: &<ST::Lock<AsyncSemaphoreQueue> as sync_types::Lock<AsyncSemaphoreQueue>>::Guard<'_>,
) -> bool {
self.leases_granted.load(atomic::Ordering::Relaxed) == locked_queue.max_leases + 1
}
}
pub struct AsyncSemaphore<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> {
state: AsyncSemaphoreState<ST>,
data: cell::UnsafeCell<T>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> AsyncSemaphore<ST, T> {
pub fn new(max_leases: usize, data: T) -> Self {
debug_assert!(max_leases < usize::MAX);
Self {
state: AsyncSemaphoreState::new(max_leases),
data: cell::UnsafeCell::new(data),
}
}
pub fn max_leases(&self) -> usize {
self.state.max_leases()
}
pub fn acquire_leases<'a, SP: 'a + sync_types::SyncRcPtr<Self>, SR: sync_types::SyncRcPtrRef<'a, Self, SP>>(
this: &SR,
leases_requested: usize,
) -> Result<AsyncSemaphoreLeasesFuture<ST, T, SP>, AsyncSemaphoreError> {
match this.state.prepare_acquire_leases(leases_requested)? {
Some(waiter_id) => Ok(AsyncSemaphoreLeasesFuture {
private: AsyncSemaphoreLeasesFuturePriv::Enqueued {
sem: this.make_weak_clone(),
waiter_id,
leases_requested,
},
}),
None => Ok(AsyncSemaphoreLeasesFuture {
private: AsyncSemaphoreLeasesFuturePriv::LeasesGranted {
sem: this.make_weak_clone(),
leases_granted: leases_requested,
},
}),
}
}
pub fn acquire_exclusive_all<
'a,
SP: 'a + sync_types::SyncRcPtr<Self>,
SR: sync_types::SyncRcPtrRef<'a, Self, SP>,
>(
this: &SR,
) -> Result<AsyncSemaphoreExclusiveAllFuture<ST, T, SP>, AsyncSemaphoreError> {
match this.state.prepare_acquire_exclusive_all()? {
Some(waiter_id) => Ok(AsyncSemaphoreExclusiveAllFuture {
private: AsyncSemaphoreExclusiveAllFuturePriv::Enqueued {
sem: this.make_weak_clone(),
waiter_id,
},
}),
None => Ok(AsyncSemaphoreExclusiveAllFuture {
private: AsyncSemaphoreExclusiveAllFuturePriv::Granted {
sem: this.make_weak_clone(),
},
}),
}
}
pub fn try_acquire_leases<'a, SP: 'a + sync_types::SyncRcPtr<Self>, SR: sync_types::SyncRcPtrRef<'a, Self, SP>>(
this: &SR,
leases_requested: usize,
) -> Result<Option<AsyncSemaphoreLeasesGuard<ST, T, SP>>, AsyncSemaphoreError> {
if this.state.try_acquire_leases(leases_requested)? {
Ok(Some(AsyncSemaphoreLeasesGuard::new(
this.make_clone(),
leases_requested,
)))
} else {
Ok(None)
}
}
pub fn try_acquire_exclusive_all<
'a,
SP: 'a + sync_types::SyncRcPtr<Self>,
SR: sync_types::SyncRcPtrRef<'a, Self, SP>,
>(
this: &SR,
) -> Option<AsyncSemaphoreExclusiveAllGuard<ST, T, SP>> {
if this.state.try_acquire_exclusive_all() {
Some(AsyncSemaphoreExclusiveAllGuard::new(this.make_clone()))
} else {
None
}
}
}
unsafe impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> marker::Send for AsyncSemaphore<ST, T> {}
unsafe impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync> marker::Sync for AsyncSemaphore<ST, T> {}
struct AsyncSemaphoreDerefInnerDataTag;
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync>
sync_types::DerefInnerByTag<AsyncSemaphoreDerefInnerDataTag> for AsyncSemaphore<ST, T>
{
crate::impl_deref_inner_by_tag!(data, cell::UnsafeCell<T>);
}
enum AsyncSemaphoreLeasesFuturePriv<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
Enqueued {
sem: SP::WeakSyncRcPtr,
waiter_id: num::NonZeroU64,
leases_requested: usize,
},
LeasesGranted {
sem: SP::WeakSyncRcPtr,
leases_granted: usize,
},
Done,
}
pub struct AsyncSemaphoreLeasesFuture<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
private: AsyncSemaphoreLeasesFuturePriv<ST, T, SP>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreLeasesFuture<ST, T, SP>
{
pub fn get_semaphore(&self) -> Option<SP> {
let weak_sem = match &self.private {
AsyncSemaphoreLeasesFuturePriv::Enqueued {
sem,
waiter_id: _,
leases_requested: _,
} => sem,
AsyncSemaphoreLeasesFuturePriv::LeasesGranted { sem, leases_granted: _ } => sem,
AsyncSemaphoreLeasesFuturePriv::Done => return None,
};
weak_sem.upgrade()
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
marker::Unpin for AsyncSemaphoreLeasesFuture<ST, T, SP>
{
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
future::Future for AsyncSemaphoreLeasesFuture<ST, T, SP>
{
type Output = Result<AsyncSemaphoreLeasesGuard<ST, T, SP>, AsyncSemaphoreError>;
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = self.get_mut();
match &this.private {
AsyncSemaphoreLeasesFuturePriv::Enqueued {
sem,
waiter_id,
leases_requested,
} => {
let sem = match sem.upgrade() {
Some(sem) => sem,
None => {
return task::Poll::Ready(Err(AsyncSemaphoreError::StaleSemaphore));
}
};
let mut locked_queue = sem.state.queue.lock();
if locked_queue.poll_waiter(*waiter_id, cx.waker().clone()) {
drop(locked_queue);
let leases_granted = *leases_requested;
this.private = AsyncSemaphoreLeasesFuturePriv::Done;
task::Poll::Ready(Ok(AsyncSemaphoreLeasesGuard::new(sem, leases_granted)))
} else if locked_queue.max_leases < *leases_requested {
locked_queue.remove_waiter(*waiter_id);
this.private = AsyncSemaphoreLeasesFuturePriv::Done;
task::Poll::Ready(Err(AsyncSemaphoreError::RequestExceedsSemaphoreCapacity))
} else {
task::Poll::Pending
}
}
AsyncSemaphoreLeasesFuturePriv::LeasesGranted { sem, leases_granted } => {
let sem = match sem.upgrade() {
Some(sem) => sem,
None => {
return task::Poll::Ready(Err(AsyncSemaphoreError::StaleSemaphore));
}
};
let leases_granted = *leases_granted;
this.private = AsyncSemaphoreLeasesFuturePriv::Done;
task::Poll::Ready(Ok(AsyncSemaphoreLeasesGuard::new(sem, leases_granted)))
}
AsyncSemaphoreLeasesFuturePriv::Done => {
task::Poll::Ready(Err(AsyncSemaphoreError::Internal))
}
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreLeasesFuture<ST, T, SP>
{
fn drop(&mut self) {
match &self.private {
AsyncSemaphoreLeasesFuturePriv::Enqueued {
sem,
waiter_id,
leases_requested,
} => {
if let Some(sem) = sem.upgrade() {
sem.state.cancel_waiter(
&mut sem.state.queue.lock(),
*waiter_id,
AsyncSemaphoreLeaseGrantCount::from(*leases_requested),
);
}
}
AsyncSemaphoreLeasesFuturePriv::LeasesGranted { sem, leases_granted } => {
if let Some(sem) = sem.upgrade() {
sem.state.return_grant(
&mut sem.state.queue.lock(),
AsyncSemaphoreLeaseGrantCount::from(*leases_granted),
);
}
}
AsyncSemaphoreLeasesFuturePriv::Done => (),
}
}
}
pub struct AsyncSemaphoreLeasesGuard<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
sem: Option<SP>,
leases_granted: usize,
_phantom: marker::PhantomData<fn() -> (ST, T)>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreLeasesGuard<ST, T, SP>
{
fn new(sem: SP, leases_granted: usize) -> Self {
Self {
sem: Some(sem),
leases_granted,
_phantom: marker::PhantomData,
}
}
pub fn get_semaphore(&self) -> SP::SyncRcPtrRef<'_> {
self.sem.as_ref().unwrap().as_ref()
}
pub fn into_semaphore(mut self) -> SP {
let sem = self.sem.take().unwrap();
Self::_drop(&sem, self.leases_granted);
sem
}
pub fn leases(&self) -> usize {
self.leases_granted
}
pub fn split_leases(&mut self, leases: usize) -> Result<Self, AsyncSemaphoreError> {
if leases > self.leases_granted {
Err(AsyncSemaphoreError::Internal)
} else {
if leases == 0 || leases == self.leases_granted {
self.sem
.as_ref()
.unwrap()
.state
.trivial_leases_granted
.fetch_add(1, atomic::Ordering::Relaxed);
}
self.leases_granted -= leases;
Ok(Self {
sem: self.sem.clone(),
leases_granted: leases,
_phantom: marker::PhantomData,
})
}
}
pub fn spawn_trivial_lease(&self) -> Self {
self.sem
.as_ref()
.unwrap()
.state
.trivial_leases_granted
.fetch_add(1, atomic::Ordering::Relaxed);
Self {
sem: self.sem.clone(),
leases_granted: 0,
_phantom: marker::PhantomData,
}
}
pub fn leak(mut self) {
if self.leases_granted == 0 {
drop(self);
return;
}
let sem = self.sem.take().unwrap();
let mut locked_queue = sem.state.queue.lock();
debug_assert!(locked_queue.max_leases >= self.leases_granted);
locked_queue.max_leases -= self.leases_granted;
debug_assert!(sem.state.leases_granted.load(atomic::Ordering::Relaxed) >= self.leases_granted);
sem.state.leases_granted.store(
sem.state.leases_granted.load(atomic::Ordering::Relaxed) - self.leases_granted,
atomic::Ordering::Relaxed,
);
sem.state.wake_failed_waiters(&mut locked_queue);
if locked_queue.has_exclusive_all_waiters() {
sem.state.wake_completed_waiters(&mut locked_queue);
}
}
pub fn into_weak(mut self) -> AsyncSemaphoreLeasesWeakGuard<ST, T, SP> {
let sem = self.sem.take().unwrap();
AsyncSemaphoreLeasesWeakGuard {
sem: Some(sem.downgrade()),
leases_granted: self.leases_granted,
_phantom: marker::PhantomData,
}
}
pub(super) fn into_raw(mut self) -> (*const T, usize) {
let sem_ptr = SP::into_raw(self.sem.take().unwrap());
let data_ptr =
<AsyncSemaphore<ST, T> as sync_types::DerefInnerByTag<AsyncSemaphoreDerefInnerDataTag>>::to_inner_ptr(
sem_ptr,
);
(cell::UnsafeCell::raw_get(data_ptr), self.leases_granted)
}
pub(super) unsafe fn from_raw(data_ptr: *const T, leases_granted: usize) -> Self {
let data_ptr = data_ptr as *const cell::UnsafeCell<T>;
let sem_ptr = unsafe {
<AsyncSemaphore<ST, T> as sync_types::DerefInnerByTag<AsyncSemaphoreDerefInnerDataTag>>::container_of(
data_ptr,
)
};
let sem = unsafe { SP::from_raw(sem_ptr) };
Self {
sem: Some(sem),
leases_granted,
_phantom: marker::PhantomData,
}
}
fn _drop(sem: &AsyncSemaphore<ST, T>, leases_granted: usize) {
if leases_granted == 0 {
let wake = sem.state.return_trivial_lease_grant();
if wake {
let mut locked_queue = sem.state.queue.lock();
sem.state.wake_completed_waiters(&mut locked_queue);
}
} else {
sem.state.return_grant(
&mut sem.state.queue.lock(),
AsyncSemaphoreLeaseGrantCount::from(leases_granted),
);
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreLeasesGuard<ST, T, SP>
{
fn drop(&mut self) {
if let Some(sem) = self.sem.as_ref() {
Self::_drop(sem, self.leases_granted);
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
ops::Deref for AsyncSemaphoreLeasesGuard<ST, T, SP>
{
type Target = T;
fn deref(&self) -> &Self::Target {
let p = self.sem.as_ref().unwrap().data.get() as *const T;
unsafe { &*p }
}
}
pub struct AsyncSemaphoreLeasesWeakGuard<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
sem: Option<SP::WeakSyncRcPtr>,
leases_granted: usize,
_phantom: marker::PhantomData<fn() -> (ST, T)>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreLeasesWeakGuard<ST, T, SP>
{
pub fn upgrade(mut self) -> Option<AsyncSemaphoreLeasesGuard<ST, T, SP>> {
self.sem.take().unwrap().upgrade().map(|sem| AsyncSemaphoreLeasesGuard {
sem: Some(sem),
leases_granted: self.leases_granted,
_phantom: marker::PhantomData,
})
}
pub fn try_spawn_trivial_lease(&self) -> Option<AsyncSemaphoreLeasesGuard<ST, T, SP>> {
match self.sem.as_ref().unwrap().upgrade() {
Some(sem) => {
sem.state.trivial_leases_granted.fetch_add(1, atomic::Ordering::Relaxed);
Some(AsyncSemaphoreLeasesGuard {
sem: Some(sem),
leases_granted: 0,
_phantom: marker::PhantomData,
})
}
None => None,
}
}
pub(super) fn into_raw(mut self) -> (*const T, usize) {
let sem_ptr = SP::WeakSyncRcPtr::into_raw(self.sem.take().unwrap());
let data_ptr =
<AsyncSemaphore<ST, T> as sync_types::DerefInnerByTag<AsyncSemaphoreDerefInnerDataTag>>::to_inner_ptr(
sem_ptr,
);
(cell::UnsafeCell::raw_get(data_ptr), self.leases_granted)
}
pub(super) unsafe fn from_raw(data_ptr: *const T, leases_granted: usize) -> Self {
let data_ptr = data_ptr as *const cell::UnsafeCell<T>;
let sem_ptr = unsafe {
<AsyncSemaphore<ST, T> as sync_types::DerefInnerByTag<AsyncSemaphoreDerefInnerDataTag>>::container_of(
data_ptr,
)
};
let sem = unsafe { SP::WeakSyncRcPtr::from_raw(sem_ptr) };
Self {
sem: Some(sem),
leases_granted,
_phantom: marker::PhantomData,
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreLeasesWeakGuard<ST, T, SP>
{
fn drop(&mut self) {
if let Some(sem) = self.sem.take() {
if let Some(sem) = sem.upgrade() {
drop(AsyncSemaphoreLeasesGuard {
sem: Some(sem),
leases_granted: self.leases_granted,
_phantom: marker::PhantomData,
});
}
}
}
}
enum AsyncSemaphoreExclusiveAllFuturePriv<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
Enqueued {
sem: SP::WeakSyncRcPtr,
waiter_id: num::NonZeroU64,
},
Granted { sem: SP::WeakSyncRcPtr },
Done,
}
pub struct AsyncSemaphoreExclusiveAllFuture<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
private: AsyncSemaphoreExclusiveAllFuturePriv<ST, T, SP>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreExclusiveAllFuture<ST, T, SP>
{
pub fn get_semaphore(&self) -> Option<SP> {
let weak_sem = match &self.private {
AsyncSemaphoreExclusiveAllFuturePriv::Enqueued { sem, waiter_id: _ } => sem,
AsyncSemaphoreExclusiveAllFuturePriv::Granted { sem } => sem,
AsyncSemaphoreExclusiveAllFuturePriv::Done => return None,
};
weak_sem.upgrade()
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
marker::Unpin for AsyncSemaphoreExclusiveAllFuture<ST, T, SP>
{
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
future::Future for AsyncSemaphoreExclusiveAllFuture<ST, T, SP>
{
type Output = Result<AsyncSemaphoreExclusiveAllGuard<ST, T, SP>, AsyncSemaphoreError>;
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = self.get_mut();
match &this.private {
AsyncSemaphoreExclusiveAllFuturePriv::Enqueued { sem, waiter_id } => {
let sem = match sem.upgrade() {
Some(sem) => sem,
None => {
return task::Poll::Ready(Err(AsyncSemaphoreError::StaleSemaphore));
}
};
let mut locked_queue = sem.state.queue.lock();
if locked_queue.poll_waiter(*waiter_id, cx.waker().clone()) {
drop(locked_queue);
this.private = AsyncSemaphoreExclusiveAllFuturePriv::Done;
task::Poll::Ready(Ok(AsyncSemaphoreExclusiveAllGuard::new(sem)))
} else {
task::Poll::Pending
}
}
AsyncSemaphoreExclusiveAllFuturePriv::Granted { sem } => {
let sem = match sem.upgrade() {
Some(sem) => sem,
None => {
return task::Poll::Ready(Err(AsyncSemaphoreError::StaleSemaphore));
}
};
this.private = AsyncSemaphoreExclusiveAllFuturePriv::Done;
task::Poll::Ready(Ok(AsyncSemaphoreExclusiveAllGuard::new(sem)))
}
AsyncSemaphoreExclusiveAllFuturePriv::Done => {
task::Poll::Ready(Err(AsyncSemaphoreError::Internal))
}
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreExclusiveAllFuture<ST, T, SP>
{
fn drop(&mut self) {
match &self.private {
AsyncSemaphoreExclusiveAllFuturePriv::Enqueued { sem, waiter_id } => {
if let Some(sem) = sem.upgrade() {
sem.state.cancel_waiter(
&mut sem.state.queue.lock(),
*waiter_id,
AsyncSemaphoreLeaseGrantCount::ExclusiveAll,
);
}
}
AsyncSemaphoreExclusiveAllFuturePriv::Granted { sem } => {
if let Some(sem) = sem.upgrade() {
sem.state
.return_grant(&mut sem.state.queue.lock(), AsyncSemaphoreLeaseGrantCount::ExclusiveAll);
}
}
AsyncSemaphoreExclusiveAllFuturePriv::Done => (),
}
}
}
pub struct AsyncSemaphoreExclusiveAllGuard<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
sem: Option<SP>,
_phantom: marker::PhantomData<fn() -> (ST, T)>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreExclusiveAllGuard<ST, T, SP>
{
fn new(sem: SP) -> Self {
Self {
sem: Some(sem),
_phantom: marker::PhantomData,
}
}
pub fn get_semaphore(&self) -> SP::SyncRcPtrRef<'_> {
self.sem.as_ref().unwrap().as_ref()
}
pub fn into_semaphore(mut self) -> SP {
let sem = self.sem.take().unwrap();
Self::_drop(&sem);
sem
}
pub fn semaphore(&self) -> &AsyncSemaphore<ST, T> {
self.sem.as_ref().unwrap()
}
pub fn resize_future(&mut self, max_leases: usize) {
debug_assert!(max_leases < usize::MAX);
let sem = self.sem.as_ref().unwrap();
let mut locked_queue = sem.state.queue.lock();
let capacity_shrunken = max_leases < locked_queue.max_leases;
locked_queue.max_leases = max_leases;
sem.state
.leases_granted
.store(max_leases + 1, atomic::Ordering::Relaxed);
if capacity_shrunken {
sem.state.wake_failed_waiters(&mut locked_queue);
}
}
pub fn downgrade(mut self) -> AsyncSemaphoreLeasesGuard<ST, T, SP> {
let sem = self.sem.take().unwrap();
let mut locked_queue = sem.state.queue.lock();
let leases_granted = locked_queue.max_leases;
sem.state
.leases_granted
.store(leases_granted, atomic::Ordering::Relaxed);
if locked_queue.max_leases == 0 {
sem.state.trivial_leases_granted.fetch_add(1, atomic::Ordering::Release);
}
if locked_queue.has_trivial_lease_waiters() {
sem.state.wake_completed_waiters(&mut locked_queue);
}
drop(locked_queue);
AsyncSemaphoreLeasesGuard::new(sem, leases_granted)
}
pub fn into_weak(mut self) -> AsyncSemaphoreExclusiveAllWeakGuard<ST, T, SP> {
let sem = self.sem.take().unwrap();
AsyncSemaphoreExclusiveAllWeakGuard {
sem: Some(sem.downgrade()),
_phantom: marker::PhantomData,
}
}
pub fn borrow_outer_inner_mut<'a>(&'a mut self) -> (SP::SyncRcPtrRef<'a>, &'a mut T) {
let p = self.sem.as_ref().unwrap().as_ref();
let pdata = p.data.get();
(p, unsafe { &mut *pdata })
}
fn _drop(sem: &AsyncSemaphore<ST, T>) {
sem.state
.return_grant(&mut sem.state.queue.lock(), AsyncSemaphoreLeaseGrantCount::ExclusiveAll);
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreExclusiveAllGuard<ST, T, SP>
{
fn drop(&mut self) {
if let Some(sem) = self.sem.as_ref() {
Self::_drop(sem);
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
ops::Deref for AsyncSemaphoreExclusiveAllGuard<ST, T, SP>
{
type Target = T;
fn deref(&self) -> &Self::Target {
let p = self.sem.as_ref().unwrap().data.get() as *const T;
unsafe { &*p }
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
ops::DerefMut for AsyncSemaphoreExclusiveAllGuard<ST, T, SP>
{
fn deref_mut(&mut self) -> &mut Self::Target {
let p = self.sem.as_ref().unwrap().data.get();
unsafe { &mut *p }
}
}
pub struct AsyncSemaphoreExclusiveAllWeakGuard<
ST: sync_types::SyncTypes,
T: marker::Send + marker::Sync,
SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>,
> {
sem: Option<SP::WeakSyncRcPtr>,
_phantom: marker::PhantomData<fn() -> (ST, T)>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>>
AsyncSemaphoreExclusiveAllWeakGuard<ST, T, SP>
{
pub fn upgrade(mut self) -> Option<AsyncSemaphoreExclusiveAllGuard<ST, T, SP>> {
self.sem
.take()
.unwrap()
.upgrade()
.map(|sem| AsyncSemaphoreExclusiveAllGuard {
sem: Some(sem),
_phantom: marker::PhantomData,
})
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send + marker::Sync, SP: sync_types::SyncRcPtr<AsyncSemaphore<ST, T>>> Drop
for AsyncSemaphoreExclusiveAllWeakGuard<ST, T, SP>
{
fn drop(&mut self) {
if let Some(sem) = self.sem.take() {
if let Some(sem) = sem.upgrade() {
drop(AsyncSemaphoreExclusiveAllGuard {
sem: Some(sem),
_phantom: marker::PhantomData,
});
}
}
}
}
#[test]
fn test_async_semaphore_lease_vs_lease() {
use crate::sync_types::SyncRcPtr as _;
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::mem;
use ops::DerefMut as _;
type TestAsyncSemaphore = AsyncSemaphore<TestNopSyncTypes, ()>;
type TestAsyncSemaporeSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestAsyncSemaphore,
>;
enum TestFuture {
ExpectLease0Ready {
sem: TestAsyncSemaporeSyncRcPtr,
lease_fut0: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectLease1Ready {
sem: TestAsyncSemaporeSyncRcPtr,
lease_fut1: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectLeases23Ready {
sem: TestAsyncSemaporeSyncRcPtr,
lease_fut2: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
lease_fut3: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
Done,
}
impl future::Future for TestFuture {
type Output = ();
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = mem::replace(self.deref_mut(), Self::Done);
match this {
Self::ExpectLease0Ready { sem, mut lease_fut0 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let mut lease_fut1 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 2).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut1).poll(cx), task::Poll::Pending));
let _lease0 = match pin::Pin::new(&mut lease_fut0).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
assert!(matches!(pin::Pin::new(&mut lease_fut1).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectLease1Ready { sem, lease_fut1 };
task::Poll::Pending
}
Self::ExpectLease1Ready { sem, mut lease_fut1 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let _lease1 = match pin::Pin::new(&mut lease_fut1).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let mut lease_fut2 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut2).poll(cx), task::Poll::Pending));
let mut lease_fut3 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut3).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectLeases23Ready {
sem,
lease_fut2,
lease_fut3,
};
task::Poll::Pending
}
Self::ExpectLeases23Ready {
sem,
mut lease_fut2,
mut lease_fut3,
} => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let lease2 = match pin::Pin::new(&mut lease_fut2).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
let lease3 = match pin::Pin::new(&mut lease_fut3).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
drop(lease2);
let lease4 = AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1).unwrap().unwrap();
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
drop(lease3);
let lease5 = AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1).unwrap().unwrap();
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 2), Ok(None)));
drop(lease4);
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 2), Ok(None)));
drop(lease5);
assert!(matches!(
AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 2),
Ok(Some(..))
));
let _lease6 = AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1).unwrap().unwrap();
let mut lease_fut7 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 2).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut7).poll(cx), task::Poll::Pending));
let mut lease_fut8 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut8).poll(cx), task::Poll::Pending));
drop(lease_fut7);
let _lease8 = match pin::Pin::new(&mut lease_fut8).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
task::Poll::Ready(())
}
Self::Done => unreachable!(),
}
}
}
impl Unpin for TestFuture {}
let e = TestAsyncExecutor::new();
let sem = <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
TestAsyncSemaphore::new(2, ()),
)
.unwrap();
let lease_fut0 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 2).unwrap();
let w = TestAsyncExecutor::spawn(&e, TestFuture::ExpectLease0Ready { sem, lease_fut0 });
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}
#[test]
fn test_async_semaphore_lease_vs_trivial() {
use crate::sync_types::SyncRcPtr as _;
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::mem;
use ops::DerefMut as _;
type TestAsyncSemaphore = AsyncSemaphore<TestNopSyncTypes, ()>;
type TestAsyncSemaporeSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestAsyncSemaphore,
>;
enum TestFuture {
ExpectLease0Ready {
sem: TestAsyncSemaporeSyncRcPtr,
lease_fut0: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectLease1Ready {
sem: TestAsyncSemaporeSyncRcPtr,
trivial_lease: AsyncSemaphoreLeasesGuard<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
lease_fut1: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
Done,
}
impl future::Future for TestFuture {
type Output = ();
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = mem::replace(self.deref_mut(), Self::Done);
match this {
Self::ExpectLease0Ready { sem, mut lease_fut0 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(..)));
let mut trivial_fut = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
match pin::Pin::new(&mut trivial_fut).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
let _lease0 = match pin::Pin::new(&mut lease_fut0).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(..)));
let mut trivial_fut = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
let trivial_lease = match pin::Pin::new(&mut trivial_fut).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(..)));
let mut trivial_fut = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
match pin::Pin::new(&mut trivial_fut).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
let mut lease_fut1 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut1).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectLease1Ready {
sem,
trivial_lease,
lease_fut1,
};
task::Poll::Pending
}
Self::ExpectLease1Ready {
sem,
trivial_lease: _trivial_lease,
mut lease_fut1,
} => {
let lease1 = match pin::Pin::new(&mut lease_fut1).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
drop(lease1);
assert!(matches!(
AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1),
Ok(Some(..))
));
task::Poll::Ready(())
}
Self::Done => unreachable!(),
}
}
}
impl Unpin for TestFuture {}
let e = TestAsyncExecutor::new();
let sem = <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
TestAsyncSemaphore::new(1, ()),
)
.unwrap();
let lease_fut0 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
let w = TestAsyncExecutor::spawn(&e, TestFuture::ExpectLease0Ready { sem, lease_fut0 });
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}
#[test]
fn test_async_semaphore_exclusive_vs_exclusive() {
use crate::sync_types::SyncRcPtr as _;
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::mem;
use ops::DerefMut as _;
type TestAsyncSemaphore = AsyncSemaphore<TestNopSyncTypes, ()>;
type TestAsyncSemaporeSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestAsyncSemaphore,
>;
enum TestFuture {
ExpectExclusiveAll0Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut0: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectExclusiveAll1Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut1: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
Done,
}
impl future::Future for TestFuture {
type Output = ();
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = mem::replace(self.deref_mut(), Self::Done);
match this {
Self::ExpectExclusiveAll0Ready { sem, mut excl_fut0 } => {
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
let mut excl_fut1 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
assert!(matches!(pin::Pin::new(&mut excl_fut1).poll(cx), task::Poll::Pending));
let _excl0 = match pin::Pin::new(&mut excl_fut0).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(pin::Pin::new(&mut excl_fut1).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectExclusiveAll1Ready { sem, excl_fut1 };
task::Poll::Pending
}
Self::ExpectExclusiveAll1Ready { sem, mut excl_fut1 } => {
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
let excl1 = match pin::Pin::new(&mut excl_fut1).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
drop(excl1);
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_some());
task::Poll::Ready(())
}
Self::Done => unreachable!(),
}
}
}
impl Unpin for TestFuture {}
let e = TestAsyncExecutor::new();
let sem = <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
TestAsyncSemaphore::new(0, ()),
)
.unwrap();
let excl_fut0 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
let w = TestAsyncExecutor::spawn(&e, TestFuture::ExpectExclusiveAll0Ready { sem, excl_fut0 });
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}
#[test]
fn test_async_semaphore_exclusive_vs_lease() {
use crate::sync_types::SyncRcPtr as _;
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::mem;
use ops::DerefMut as _;
type TestAsyncSemaphore = AsyncSemaphore<TestNopSyncTypes, ()>;
type TestAsyncSemaporeSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestAsyncSemaphore,
>;
enum TestFuture {
ExpectExclusiveAll0Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut0: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectLease1Ready {
sem: TestAsyncSemaporeSyncRcPtr,
lease_fut1: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectExclusiveAll2Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut2: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
Done,
}
impl future::Future for TestFuture {
type Output = ();
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = mem::replace(self.deref_mut(), Self::Done);
match this {
Self::ExpectExclusiveAll0Ready { sem, mut excl_fut0 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let mut lease_fut1 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
assert!(matches!(pin::Pin::new(&mut lease_fut1).poll(cx), task::Poll::Pending));
let _excl0 = match pin::Pin::new(&mut excl_fut0).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
assert!(matches!(pin::Pin::new(&mut lease_fut1).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectLease1Ready { sem, lease_fut1 };
task::Poll::Pending
}
Self::ExpectLease1Ready { sem, mut lease_fut1 } => {
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
let mut excl_fut2 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
assert!(matches!(pin::Pin::new(&mut excl_fut2).poll(cx), task::Poll::Pending));
let _lease1 = match pin::Pin::new(&mut lease_fut1).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
assert!(matches!(pin::Pin::new(&mut excl_fut2).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectExclusiveAll2Ready { sem, excl_fut2 };
task::Poll::Pending
}
Self::ExpectExclusiveAll2Ready { sem, mut excl_fut2 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
let excl2 = match pin::Pin::new(&mut excl_fut2).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1), Ok(None)));
drop(excl2);
assert!(matches!(
AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 1),
Ok(Some(..))
));
task::Poll::Ready(())
}
Self::Done => unreachable!(),
}
}
}
impl Unpin for TestFuture {}
let e = TestAsyncExecutor::new();
let sem = <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
TestAsyncSemaphore::new(1, ()),
)
.unwrap();
let excl_fut0 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
let w = TestAsyncExecutor::spawn(&e, TestFuture::ExpectExclusiveAll0Ready { sem, excl_fut0 });
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}
#[test]
fn test_async_semaphore_exclusive_vs_trivial() {
use crate::sync_types::SyncRcPtr as _;
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::mem;
use ops::DerefMut as _;
type TestAsyncSemaphore = AsyncSemaphore<TestNopSyncTypes, ()>;
type TestAsyncSemaporeSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestAsyncSemaphore,
>;
enum TestFuture {
ExpectExclusiveAll0Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut0: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectTrivial1Ready {
sem: TestAsyncSemaporeSyncRcPtr,
trivial_fut1: AsyncSemaphoreLeasesFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
ExpectExclusiveAll2Ready {
sem: TestAsyncSemaporeSyncRcPtr,
excl_fut2: AsyncSemaphoreExclusiveAllFuture<TestNopSyncTypes, (), TestAsyncSemaporeSyncRcPtr>,
},
Done,
}
impl future::Future for TestFuture {
type Output = ();
fn poll(mut self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = mem::replace(self.deref_mut(), Self::Done);
match this {
Self::ExpectExclusiveAll0Ready { sem, mut excl_fut0 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(None)));
let mut trivial_fut1 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
assert!(matches!(pin::Pin::new(&mut trivial_fut1).poll(cx), task::Poll::Pending));
let _excl0 = match pin::Pin::new(&mut excl_fut0).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(None)));
assert!(matches!(pin::Pin::new(&mut trivial_fut1).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectTrivial1Ready { sem, trivial_fut1 };
task::Poll::Pending
}
Self::ExpectTrivial1Ready { sem, mut trivial_fut1 } => {
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
let mut excl_fut2 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
assert!(matches!(pin::Pin::new(&mut excl_fut2).poll(cx), task::Poll::Pending));
let mut trivial1 = match pin::Pin::new(&mut trivial_fut1).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
let _trivial = trivial1.split_leases(0).unwrap();
drop(trivial1);
assert!(AsyncSemaphore::try_acquire_exclusive_all(&sem.as_ref()).is_none());
assert!(matches!(pin::Pin::new(&mut excl_fut2).poll(cx), task::Poll::Pending));
*self.deref_mut() = Self::ExpectExclusiveAll2Ready { sem, excl_fut2 };
task::Poll::Pending
}
Self::ExpectExclusiveAll2Ready { sem, mut excl_fut2 } => {
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(None)));
let excl2 = match pin::Pin::new(&mut excl_fut2).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0), Ok(None)));
drop(excl2);
assert!(matches!(
AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0),
Ok(Some(..))
));
let _trivial3 = AsyncSemaphore::try_acquire_leases(&sem.as_ref(), 0).unwrap().unwrap();
let mut excl_fut4 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
assert!(matches!(pin::Pin::new(&mut excl_fut4).poll(cx), task::Poll::Pending));
let mut trivial_fut5 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
let mut lease_fut6 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
let mut lease_fut7 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 1).unwrap();
let mut trivial_fut8 = AsyncSemaphore::acquire_leases(&sem.as_ref(), 0).unwrap();
assert!(matches!(pin::Pin::new(&mut trivial_fut5).poll(cx), task::Poll::Pending));
assert!(matches!(pin::Pin::new(&mut lease_fut6).poll(cx), task::Poll::Pending));
assert!(matches!(pin::Pin::new(&mut lease_fut7).poll(cx), task::Poll::Pending));
assert!(matches!(pin::Pin::new(&mut trivial_fut8).poll(cx), task::Poll::Pending));
drop(excl_fut4);
assert!(matches!(
pin::Pin::new(&mut trivial_fut5).poll(cx),
task::Poll::Ready(Ok(..))
));
let lease6 = match pin::Pin::new(&mut lease_fut6).poll(cx) {
task::Poll::Ready(guard) => guard.unwrap(),
task::Poll::Pending => unreachable!(),
};
assert!(matches!(pin::Pin::new(&mut lease_fut7).poll(cx), task::Poll::Pending));
assert!(matches!(
pin::Pin::new(&mut trivial_fut8).poll(cx),
task::Poll::Ready(Ok(..))
));
drop(lease6);
assert!(matches!(
pin::Pin::new(&mut lease_fut7).poll(cx),
task::Poll::Ready(Ok(..))
));
task::Poll::Ready(())
}
Self::Done => unreachable!(),
}
}
}
impl Unpin for TestFuture {}
let e = TestAsyncExecutor::new();
let sem = <<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
TestAsyncSemaphore::new(1, ()),
)
.unwrap();
let excl_fut0 = AsyncSemaphore::acquire_exclusive_all(&sem.as_ref()).unwrap();
let w = TestAsyncExecutor::spawn(&e, TestFuture::ExpectExclusiveAll0Ready { sem, excl_fut0 });
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}