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