Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do upgradable reads block plain reads? #101

Closed
matklad opened this issue Oct 30, 2018 · 13 comments · Fixed by #112
Closed

Do upgradable reads block plain reads? #101

matklad opened this issue Oct 30, 2018 · 13 comments · Fixed by #112

Comments

@matklad
Copy link
Contributor

matklad commented Oct 30, 2018

Hi! I see a behavior which I think does not match the docs, so either the docs are unclear, or there's a bug.

Here's the code that shows the behavior:

https://github.com/matklad/parking-lot-deadlock/blob/95989b3da40ed42e1ed7acba829d20b8b4319845/src/main.rs

If I run the code on my machine (linux, x86_64), I get a deadlock after a couple of hundred iterations.

I would expect that this program never deadlocks though, because, from my reading of the upgradable_read docs it follows that a read can never be blocked by a not-upgraded upgradable_read.

@matklad
Copy link
Contributor Author

matklad commented Oct 30, 2018

Downstream issue: salsa-rs/salsa#74.

@Amanieu
Copy link
Owner

Amanieu commented Oct 30, 2018

I reproduced it with 2 threads upgrading. So what seems to have happened is this:

  1. Thread A acquires and upgradable lock.
  2. Thread B tries to acquire an upgradable lock, and blocks. This is normal since you can only have 1 upgradable lock at any time.
  3. Thread C tries to acquire a read lock, and blocks because there is already another thread blocked waiting for a lock.

@matklad
Copy link
Contributor Author

matklad commented Oct 30, 2018

@Amanieu and 3 is a bug, right?

@Amanieu
Copy link
Owner

Amanieu commented Oct 30, 2018

... probably. The rwlock was originally written as a task-fair rwlock, where a reader will block if there is an existing writer blocked on it. This helps prevent writer starvation. The problem is that this code was not revisited when upgradable locks were implemented.

@nikomatsakis
Copy link

Just for the record, I think I sidestepped the problem by not using upgradable reads in this particular path -- though this sounds like a pretty general flaw for upgradable reads, so maybe we should just not be using them?

@nikomatsakis
Copy link

There is one other path that still does but I could easily remove it

@nikomatsakis
Copy link

Well I suppose that there is no problem so long as Thread 1 doesn't wind up blocked on Thread 3, right @Amanieu ?

@nikomatsakis
Copy link

I opened salsa-rs/salsa#75 but maybe it is not necessary

matklad added a commit to rust-lang/rust-analyzer that referenced this issue Dec 22, 2018
bors bot added a commit to rust-lang/rust-analyzer that referenced this issue Dec 22, 2018
323: workaround salsa/parking-log bug r=matklad a=matklad

salsa-rs/salsa#99
Amanieu/parking_lot#101

Co-authored-by: Aleksey Kladov <[email protected]>
@matklad
Copy link
Contributor Author

matklad commented Dec 27, 2018

Here's a slight variation of the deadlock:

matklad/parking-lot-deadlock@12945a9

Here, threads repeatedly upgrade_read/write/read the lock. What is interesting is that writers and upgraders deadlock against each other, without busy-waiting which was used in the first example.

@matklad
Copy link
Contributor Author

matklad commented Dec 27, 2018

Note that samples use parking-lot 0.6.*. I've checked the last one with 0.7.0, and it still deadlocks.

@Amanieu
Copy link
Owner

Amanieu commented Jan 1, 2019

Ugh, upgradable locks are a pain to get right...

Your new deadlock is an actual bug, which should be fixed by 5977113.

The first one is more of a design flaw in the current rwlock implementation, where an upgradable read can in some cases block a normal read.

@Amanieu
Copy link
Owner

Amanieu commented Jan 1, 2019

Also, fun fact, the bug is in the unlock path for normal reads. If you remove the assert from your example then the bug doesn't trigger.

@matklad
Copy link
Contributor Author

matklad commented Jan 1, 2019

Also, fun fact, the bug is in the unlock path for normal reads. If you remove the assert from your example then the bug doesn't trigger.

Yeah, I've noticed that, that's why assert is in there! Should have added this bit of info to the original comment.

Looks like salsa + rust-analyzer combo is a good stress test for parking lot! :)

bors bot added a commit that referenced this issue Jan 31, 2019
112: [WIP] New RwLock implementation r=Amanieu a=Amanieu

The new implementation is inspired by boost's [`upgrade_mutex`](https://github.com/boostorg/thread/blob/fc08c1fe2840baeeee143440fba31ef9e9a813c8/include/boost/thread/v2/shared_mutex.hpp#L432) rwlock implementation.

The main benefit is that it fixes #101: upgradable reads no longer block normal reads. The code has also been refactored and is now much simpler than before.

cc @matklad @nikomatsakis

Co-authored-by: Amanieu d'Antras <[email protected]>
@bors bors bot closed this as completed in #112 Jan 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants