[ovs-dev] [PATCH v4] fat-rwlock: Make fat-rwlock upgradable.

Ben Pfaff blp at ovn.org
Wed Oct 12 15:53:36 UTC 2016


Do you have a planned use for it?  I'm more interested in infrastructure
improvements when there's a use case.

On Wed, Oct 12, 2016 at 04:33:21PM +0300, Ilya Maximets wrote:
> Hi, Ben.
> 
> So, what about this patch? It's still not in mail-list, I guess,
> and still applicable.
> 
> Best regards, Ilya Maximets.
> 
> On 15.07.2016 15:44, Ilya Maximets wrote:
> > New functions 'fat_rwlock_{up,down}grade()' introduced to allow
> > upgrading read-lock to write-lock and downgrading it back.
> > 
> > Signed-off-by: Ilya Maximets <i.maximets at samsung.com>
> > ---
> > Version 4:
> > 	* Added detailed describtion of rwlock states and possible
> > 	  operations in each state.
> > 
> > Version 3:
> > 	* First version of this patch.
> > 
> >  lib/fat-rwlock.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> >  lib/fat-rwlock.h | 33 +++++++++++++++++++++++++++++++++
> >  2 files changed, 87 insertions(+), 2 deletions(-)
> > 
> > diff --git a/lib/fat-rwlock.c b/lib/fat-rwlock.c
> > index 2f42b05..86a4693 100644
> > --- a/lib/fat-rwlock.c
> > +++ b/lib/fat-rwlock.c
> > @@ -53,10 +53,13 @@ struct fat_rwlock_slot {
> >       *
> >       *     - UINT_MAX: This thread has the write-lock on 'rwlock' and holds
> >       *       'mutex' (plus the 'mutex' of all of 'rwlock''s other slots).
> > +     *       'upgrade_depth' means the depth of read-lock on which it was
> > +     *       upgraded to write-lock.
> >       *
> >       * Accessed only by the slot's own thread, so no synchronization is
> >       * needed. */
> >      unsigned int depth;
> > +    unsigned int upgrade_depth;
> >  };
> >  
> >  static void
> > @@ -127,6 +130,7 @@ fat_rwlock_get_slot__(struct fat_rwlock *rwlock)
> >      slot->rwlock = rwlock;
> >      ovs_mutex_init(&slot->mutex);
> >      slot->depth = 0;
> > +    slot->upgrade_depth = 0;
> >  
> >      ovs_mutex_lock(&rwlock->mutex);
> >      ovs_list_push_back(&rwlock->threads, &slot->list_node);
> > @@ -236,6 +240,7 @@ fat_rwlock_wrlock(const struct fat_rwlock *rwlock_)
> >  
> >      ovs_assert(!this->depth);
> >      this->depth = UINT_MAX;
> > +    this->upgrade_depth = 1;
> >  
> >      ovs_mutex_lock(&rwlock->mutex);
> >      LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
> > @@ -257,11 +262,13 @@ fat_rwlock_unlock(const struct fat_rwlock *rwlock_)
> >  
> >      switch (this->depth) {
> >      case UINT_MAX:
> > +        this->depth = this->upgrade_depth - 1;
> >          LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
> > -            ovs_mutex_unlock(&slot->mutex);
> > +            if (slot != this || this->depth == 0) {
> > +                ovs_mutex_unlock(&slot->mutex);
> > +            }
> >          }
> >          ovs_mutex_unlock(&rwlock->mutex);
> > -        this->depth = 0;
> >          break;
> >  
> >      case 0:
> > @@ -275,3 +282,48 @@ fat_rwlock_unlock(const struct fat_rwlock *rwlock_)
> >          break;
> >      }
> >  }
> > +
> > +/* Upgrades last taken read-lock to write-lock.
> > + * Not thread-safe with 'fat_rwlock_wrlock' and concurrent upgrades. */
> > +void
> > +fat_rwlock_upgrade(const struct fat_rwlock *rwlock_)
> > +    OVS_NO_THREAD_SAFETY_ANALYSIS
> > +{
> > +    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
> > +    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
> > +    struct fat_rwlock_slot *slot;
> > +
> > +    ovs_assert(this->depth && this->depth != UINT_MAX);
> > +
> > +    this->upgrade_depth = this->depth;
> > +    this->depth = UINT_MAX;
> > +
> > +    ovs_mutex_lock(&rwlock->mutex);
> > +    LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
> > +        if (slot != this) {
> > +            ovs_mutex_lock(&slot->mutex);
> > +        }
> > +    }
> > +}
> > +
> > +/* Downgrades write-lock to read-lock. */
> > +void
> > +fat_rwlock_downgrade(const struct fat_rwlock *rwlock_)
> > +    OVS_NO_THREAD_SAFETY_ANALYSIS
> > +{
> > +    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
> > +    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
> > +    struct fat_rwlock_slot *slot;
> > +
> > +    ovs_assert(this->depth == UINT_MAX);
> > +
> > +    this->depth = this->upgrade_depth;
> > +    this->upgrade_depth = 0;
> > +
> > +    LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
> > +        if (slot != this) {
> > +            ovs_mutex_unlock(&slot->mutex);
> > +        }
> > +    }
> > +    ovs_mutex_unlock(&rwlock->mutex);
> > +}
> > diff --git a/lib/fat-rwlock.h b/lib/fat-rwlock.h
> > index 181fa92..15514fc 100644
> > --- a/lib/fat-rwlock.h
> > +++ b/lib/fat-rwlock.h
> > @@ -46,4 +46,37 @@ int fat_rwlock_tryrdlock(const struct fat_rwlock *rwlock)
> >  void fat_rwlock_wrlock(const struct fat_rwlock *rwlock) OVS_ACQ_WRLOCK(rwlock);
> >  void fat_rwlock_unlock(const struct fat_rwlock *rwlock) OVS_RELEASES(rwlock);
> >  
> > +/*
> > + * Following functions used to upgrade last taken read-lock to write-lock and
> > + * downgrade it back to read-lock. Upgrading/downgrading doesn't change depth
> > + * of recursive locking.
> > + *
> > + * Detailed description:
> > + * -----------------------------------------------------------------------------
> > + *           STATE            | POSSIBLE OPERATION |     RESULTED STATE
> > + * -----------------------------------------------------------------------------
> > + * unlocked                    fat_rwlock_rdlock    read-locked with depth = 1
> > + *                             fat_rwlock_wrlock    write-locked with depth = 1
> > + *
> > + * read-locked with depth = 1  fat_rwlock_rdlock    read-locked with depth = 2
> > + *                             fat_rwlock_unlock    unlocked
> > + *                             fat_rwlock_upgrade   write-locked with depth = 1
> > + *
> > + * read-locked with depth = N  fat_rwlock_rdlock    read-locked with depth = N+1
> > + *                             fat_rwlock_unlock    read-locked with depth = N-1
> > + *                             fat_rwlock_upgrade   write-locked with depth = N
> > + *
> > + * write-locked with depth = 1 fat_rwlock_unlock    unlocked
> > + *                             fat_rwlock_downgrade read-locked with depth = 1
> > + *
> > + * write-locked with depth = N fat_rwlock_unlock    read-locked with depth = N-1
> > + *                             fat_rwlock_downgrade read-locked with depth = N
> > + * -----------------------------------------------------------------------------
> > + *
> > + * Upgrading is NOT thread-safe operation, so, the caller must be sure that
> > + * it is the only thread that wants to acquire write-lock.
> > + */
> > +void fat_rwlock_upgrade(const struct fat_rwlock *rwlock);
> > +void fat_rwlock_downgrade(const struct fat_rwlock *rwlock);
> > +
> >  #endif /* fat-rwlock.h */
> > 



More information about the dev mailing list