[ovs-dev] [PATCH v3 1/3] fat-rwlock: Make fat-rwlock upgradable.
Ilya Maximets
i.maximets at samsung.com
Mon Jul 11 15:15:29 UTC 2016
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>
---
lib/fat-rwlock.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
lib/fat-rwlock.h | 11 +++++++++++
2 files changed, 65 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..70d5e95 100644
--- a/lib/fat-rwlock.h
+++ b/lib/fat-rwlock.h
@@ -46,4 +46,15 @@ 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.
+ *
+ * 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 */
--
2.7.4
More information about the dev
mailing list