On Wed, Aug 21, 2019 at 10:21 PM Rick Payne <ri...@rossfell.co.uk> wrote:

> On Wed, 2019-08-21 at 12:22 +0300, Nadav Har'El wrote:
> > I am guessing (need to verify...) that our rwlock implementation is
> > not recursive - a thread already holding the write lock needs to wait
> > (forever) for the read lock. If this is true, this is an rwlock bug.
>
> So I was puzzled a bit by the rwlock code. It handles recursive write
> lock acquisitions by incrementing a counter:
>
>     // recursive write lock
>     if (_wowner == sched::thread::current()) {
>         _wrecurse++;
>     }
>

Indeed - it appears that although write lock is recursive (the same thread
can get the write lock again), a thread holding the write lock cannot get a
read lock.
It's not completely obvious whether this is a feature, or a bug, though.
It's a bug in the sense it (a thread holding a write lock asking for a read
lock) causes a certain deadlock, which is always bad - it would have been
even better to assert() than just silently hang. But it's "feature" in the
sense that if the reader is expecting to see stable data, not in the middle
of someone reading it, he is bound to be disappointed because we are in the
middle of writing (even if on this thread).

I think it's clear here that we don't need to fix rwlock now: the problem
we have is why we got the page fault in the first place - not why it
deadlocked while handling it.


>
> On the unlock side though, it does decrement the counter but then goes
> on to wake a write_waiter - which seems wrong. Probably I am missing
> something - but why is the second part not inside the else clause where
> _wowner is set to nullptr?
>

You're right, it seems there's should be a "return" in the recursive case!
That being said, I think the spurious wakeup doesn't cause any harm,
because the wait code rwlock::writer_wait_lockable() loops, and if a thread
is woken while the lock is still taken, it just goes to sleep again. It
will just lose it's good spot on the queue :-(

>
> void rwlock::wunlock()
> {
>     WITH_LOCK(_mtx) {
>         assert(_wowner == sched::thread::current());
>
>         if (_wrecurse > 0) {
>             _wrecurse--;
>         } else {
>             _wowner = nullptr;
>         }
>
>         if (!_write_waiters.empty()) {
>             _write_waiters.wake_one(_mtx);
>         } else {
>             _read_waiters.wake_all(_mtx);
>         }
>     }
> }
>
> I think you're right that if you hold the write lock and then try and
> readlock it will fail:
>
> bool rwlock::read_lockable()
> {
>     return ((!_wowner) && (_write_waiters.empty()));
> }
>
> Rick
>
> --
> You received this message because you are subscribed to the Google Groups
> "OSv Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to osv-dev+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/osv-dev/d75b970c54f9fe25cda79f2cc0aa0e7eaee3ec2f.camel%40rossfell.co.uk
> .
>

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/CANEVyjttzni5VrgmFd08gVGfd-hDHANzgcB8dOK%2BZgCEcKJTmg%40mail.gmail.com.

Reply via email to