-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Open
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.Relevant to the library API team, which will review and decide on the PR/issue.
Description
Feature gate: #![feature(rwlock_downgrade)]
This is a tracking issue for a downgrade
method for RwLock
as discussed in rust-lang/libs-team#392.
The downgrade
method on RwLockWriteGuard
will transform a write-locked RwLock
into a read-locked one.
Public API
impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> {
pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> {}
}
Steps / History
- Implementation: Rwlock downgrade #128219
downgrade
implementation forfutex.rs
downgrade
implementation forno_threads.rs
downgrade
implementation forqueue.rs
downgrade
implementation forsolid.rs
downgrade
implementation forteeos.rs
To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.Final comment period (FCP)1Stabilization PR: Stabilizerwlock_downgrade
library feature #143191To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Unresolved Questions
It is likely that the reader protocol for the futex implementation will need to change. See below.How to go about implementingdowngrade
for thequeue.rs
implementation?Does thesolid_asp3
platform already have adowngrade
method on theirRwLock
implementation?Does lock poisoning play into this at all?
Footnotes
Metadata
Metadata
Assignees
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.Relevant to the library API team, which will review and decide on the PR/issue.
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
Mutex
andCondvar
respect priorities? #128231connortsui20 commentedon Jul 26, 2024
For the
futex.rs
implementation, it is likely that the protocol for waiting readers will have to change slightly. You can read it in the code changes, but I'll give a quick summary here.When a call to
downgrade
occurs on the innerRwLock
, it is arguably incorrect for just the single thread that initially held the write-lock to be the only one who is allowed to hold the read-lock. With no changes to the current implementation, this is what would happen, as we don't let readers (either waiting or very recently entered into the protocol) take the read lock if there are any readers or writers waiting (see theis_read_lockable
function).So a solution that is arguably less wrong would be to allow readers who have just been waken up after a call to
futex_wait(&self.state)
to take the read lock, regardless of if there are other readers or writers waiting. This means that thefutex.rs
implementation no longer always prioritizes writers over readers, and I'm not sure if this is acceptable.It is hard to say if this is a good solution, if anyone would like to give their input that would be much appreciated!
connortsui20 commentedon Jul 26, 2024
@joboet Hi, I saw that you wrote the
queue.rs
implementation. Do you have an idea on how to go about implementingdowngrade
for the queue version? I believe it should be something along the lines of finding the tail of the queue and then changing the reader count from 0 to 1, but I am very unfamiliar with the code and I am probably missing something. I also assume thatadd_backlinks_and_find_tail
is probably going to be necessary here?joboet commentedon Jul 26, 2024
Sure! There are two cases to consider:
The fast path is pretty easy, you just need to CAS the write-locked state (
LOCKED
) with the read-locked state for one thread (LOCKED + SINGLE
).For the contended case, I'd first of all change this line:
rust/library/std/src/sys/sync/rwlock/queue.rs
Lines 340 to 344 in 2d5a628
so that the count is one if the lock is write-locked (try
cmp::max
ing the address). I'll get back to this later.If the fast path above fails, you need to try to acquire the queue lock so that you can make modifications to the queue (try a CAS that sets the
QUEUE_LOCKED
bit, fail if the bit is already set). If this is unsuccessful, then return, as there is no way to wake up new threads. Since the last node contains a lock-count of one (with the change above), theread_unlock
call will still work correctly.If you acquired the
QUEUE_LOCKED
bit, then you need to wake up new threads. I'd modifyunlock_queue
so that it takes adowngrade
argument, if that istrue
then skip theLOCKED
check, do not remove the last node if it is a writer (this and this line need to be skipped) and useLOCKED + SINGLE
as unlock value if the last node is a reader.connortsui20 commentedon Jul 26, 2024
I think I understand your algorithm, though I was wondering if there might be another way to do it. This algorithm basically is an atomic unlock and place a reader node at the end of the queue, right? Do you think it is possible to implementdowngrade
without adding a node to the queue at all, and instead just mutating the current state so that we go from0b0001
to0b1001
for the fast path and for the waiting path simply incrementing the last queue node from a reader count of 0 to 1?I'm not sure this is possible, but if it is, it would allow for more opportunities to potentially wake up readers as well.connortsui20 commentedon Jul 28, 2024
I see the problem now after playing around with the code and trying to implement what I said above. In the queue implementation, if there are any waiters in the queue (writer or readers), we do not allow readers to take the read lock. So my idea of waking up readers after a call to downgrade is not exactly compatible with the current implementation.However, that doesn't imply that this is completely impossible with the current implementation. I think what might work is forcing the writer who just downgraded to wake up the next readers in the queue AND remove them from the queue. Maybe the former writer thread can set a bit somewhere (probably stored in theNode
struct) to let the awakened readers know that they have been awaken by a call todowngrade
, and then there can be an extra case inlock_contended
to handle readers who just woke up and observed that bit. However, there might be something I am missing that makes this not able to work.@joboet Do you have any thoughts about this? (Sorry for all of the pings!)(EDIT: resolved! see PR)
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=<try>
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=tgr…
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=tgr…
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=tgr…
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=tgr…
Auto merge of rust-lang#128219 - connortsui20:rwlock-downgrade, r=tgr…
7 remaining items