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.maxim...@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 */
> 
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to