Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,22 @@ The exact Tokio 1.42.0 revision is:

https://github.com/tokio-rs/tokio/tree/bb9d57017e100985f86d8ca41ac105ee9140423e/tokio/src/sync

Asyncband adapted RwLock to its own semaphore and guard model. Acquisition has
no semaphore-close error, nonblocking methods return Option, and max_readers is
any NonZeroUsize instead of Tokio's restricted range. Mapped read guards use
separate borrowed and owned types rather than changing a type parameter on the
original read guard. All mapped guards use filter_map naming, and mutable mapped
guards carry explicit invariance. The local guard types release and downgrade
permits through Asyncband's usize-based semaphore implementation.
Asyncband retains semaphore-based fair scheduling and substantially rewrote
RwLock's guard lifecycle. The private asyncband/src/rwlock/access.rs
implementation owns acquired permits in RAII tokens that release them through
Asyncband's usize-based semaphore on drop. Guards carry no destructor of their
own and project data by moving their token. Downgrading establishes a read
token before releasing the other permits. The public documentation and
examples were rewritten around access, projection, and owned lifetimes. The
standard ASF source headers cover these substantial modifications contributed
to Apache Asyncband; the incorporated Tokio-derived portions remain under the
MIT License below.

Acquisition has no semaphore-close error, nonblocking methods return Option,
and max_readers is any NonZeroUsize instead of Tokio's restricted range. Mapped
read guards use separate borrowed and owned types rather than changing a type
parameter on the original read guard. All mapped guards use filter_map naming,
and mutable mapped guards carry explicit invariance.

Portions of the following files originated from Tokio 1.47.0's OnceCell. Each
local path is followed by its upstream source path:
Expand Down
131 changes: 131 additions & 0 deletions asyncband/src/rwlock/access.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//! Tokens that own acquired `RwLock` permits and release them on drop.
//!
//! Guards hold a token instead of implementing `Drop`, so projecting or downgrading a guard moves
//! the token into the new guard.

use std::sync::Arc;

use crate::internal::semaphore::Semaphore;
use crate::rwlock::RwLock;

/// Keeps the lock's semaphore alive while a token holds permits from it.
pub trait Owner: Clone {
/// Returns the semaphore that the token's permits belong to.
fn semaphore(&self) -> &Semaphore;
}

impl Owner for &Semaphore {
fn semaphore(&self) -> &Semaphore {
self
}
}

impl<T: ?Sized> Owner for &RwLock<T> {
fn semaphore(&self) -> &Semaphore {
&self.s
}
}

impl<T: ?Sized> Owner for Arc<RwLock<T>> {
fn semaphore(&self) -> &Semaphore {
&self.s
}
}

/// Owns one read permit.
pub struct ReadAccess<O: Owner> {
owner: O,
}

impl<O: Owner> ReadAccess<O> {
/// Takes over one permit already acquired from `owner`.
pub fn new(owner: O) -> Self {
Self { owner }
}

/// Returns the owner that the permit was acquired from.
pub fn owner(&self) -> &O {
&self.owner
}
}

impl<'a, T: ?Sized> ReadAccess<&'a RwLock<T>> {
/// Drops the value type so that mapped guards need not name it.
pub fn into_semaphore(self) -> ReadAccess<&'a Semaphore> {
let lock = self.owner;
// The token holds only a reference and no other resource, so
// skipping its drop leaks nothing.
std::mem::forget(self);
ReadAccess::new(&lock.s)
}
}

impl<O: Owner> Drop for ReadAccess<O> {
fn drop(&mut self) {
self.owner.semaphore().release(1);
}
}

/// Owns every permit of a lock, which together grant write access.
pub struct WriteAccess<O: Owner> {
owner: O,
permits_acquired: usize,
}

impl<O: Owner> WriteAccess<O> {
/// Takes over `permits_acquired` permits already acquired from `owner`.
pub fn new(owner: O, permits_acquired: usize) -> Self {
Self {
owner,
permits_acquired,
}
}

/// Returns the owner that the permits were acquired from.
pub fn owner(&self) -> &O {
&self.owner
}

/// Releases all permits but one, which the returned token keeps.
pub fn downgrade(mut self) -> ReadAccess<O> {
let read = ReadAccess::new(self.owner.clone());
self.permits_acquired -= 1;
drop(self);
read
}
}

impl<'a, T: ?Sized> WriteAccess<&'a RwLock<T>> {
/// Drops the value type so that mapped guards need not name it.
pub fn into_semaphore(self) -> WriteAccess<&'a Semaphore> {
let lock = self.owner;
let permits_acquired = self.permits_acquired;
// The token holds only a reference and no other resource, so
// skipping its drop leaks nothing.
std::mem::forget(self);
WriteAccess::new(&lock.s, permits_acquired)
}
}

impl<O: Owner> Drop for WriteAccess<O> {
fn drop(&mut self) {
self.owner.semaphore().release(self.permits_acquired);
}
}
Loading
Loading