]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: threads: Add HA_RWLOCK_TRYRDTOWR()
authorOlivier Houchard <ohouchard@haproxy.com>
Wed, 26 Mar 2025 12:11:30 +0000 (12:11 +0000)
committerOlivier Houchard <cognet@ci0.org>
Tue, 1 Apr 2025 16:05:30 +0000 (18:05 +0200)
Add HA_RWLOCK_TRYRDTOWR(), that tries to upgrade a lock
from reader to writer, and fails if any seeker or writer already
holds it.

include/haproxy/thread.h
src/thread.c

index d99146766acdbaa667c521b04fcfab6a5185d158..c71cd25ab36b3332fbdb147e5b97f9dac1e3080b 100644 (file)
@@ -87,6 +87,7 @@ enum { tgid = 1 };
 #define HA_RWLOCK_SKUNLOCK(lbl,l)       do { /* do nothing */ } while(0)
 #define HA_RWLOCK_TRYSKLOCK(lbl,l)      ({ 0; })
 #define HA_RWLOCK_TRYRDTOSK(lbl,l)      ({ 0; })
+#define HA_RWLOCK_TRYRDTOWR(lbl,l)      ({ 0; })
 
 #define ha_sigmask(how, set, oldset)  sigprocmask(how, set, oldset)
 
@@ -327,6 +328,7 @@ static inline unsigned long thread_isolated()
 #define HA_RWLOCK_SKUNLOCK(lbl,l)       pl_drop_s(l)      /* S --> N */
 #define HA_RWLOCK_TRYSKLOCK(lbl,l)      (!pl_try_s(l))    /* N -?> S */
 #define HA_RWLOCK_TRYRDTOSK(lbl,l)      (!pl_try_rtos(l)) /* R -?> S */
+#define HA_RWLOCK_TRYRDTOWR(lbl, l)     (!pl_try_rtow(l)) /* R -?> W */
 
 #else /* !defined(DEBUG_THREAD) && !defined(DEBUG_FULL) */
 
@@ -356,6 +358,7 @@ static inline unsigned long thread_isolated()
 #define __RWLOCK_SKUNLOCK(l)       pl_drop_s(l)      /* S --> N */
 #define __RWLOCK_TRYSKLOCK(l)      (!pl_try_s(l))    /* N -?> S */
 #define __RWLOCK_TRYRDTOSK(l)      (!pl_try_rtos(l)) /* R -?> S */
+#define __RWLOCK_TRYRDTOWR(l)      (!pl_try_rtow(l)) /* R -?> W */
 
 #define HA_SPIN_INIT(l)            __spin_init(l)
 #define HA_SPIN_DESTROY(l)         __spin_destroy(l)
@@ -381,6 +384,7 @@ static inline unsigned long thread_isolated()
 #define HA_RWLOCK_SKUNLOCK(lbl,l)  __ha_rwlock_skunlock(lbl, l, __func__, __FILE__, __LINE__)
 #define HA_RWLOCK_TRYSKLOCK(lbl,l) __ha_rwlock_trysklock(lbl, l, __func__, __FILE__, __LINE__)
 #define HA_RWLOCK_TRYRDTOSK(lbl,l) __ha_rwlock_tryrdtosk(lbl, l, __func__, __FILE__, __LINE__)
+#define HA_RWLOCK_TRYRDTOWR(lbl,l) __ha_rwlock_tryrdtowr(lbl, l, __func__, __FILE__, __LINE__)
 
 /* Following functions are used to collect some stats about locks. We wrap
  * pthread functions to known how much time we wait in a lock. */
@@ -413,6 +417,8 @@ int __ha_rwlock_trysklock(enum lock_label lbl, struct ha_rwlock *l,
                           const char *func, const char *file, int line);
 int __ha_rwlock_tryrdtosk(enum lock_label lbl, struct ha_rwlock *l,
                           const char *func, const char *file, int line);
+int __ha_rwlock_tryrdtowr(enum lock_label lbl, struct ha_rwlock *l,
+                          const char *func, const char *file, int line);
 void __spin_init(struct ha_spinlock *l);
 void __spin_destroy(struct ha_spinlock *l);
 void __spin_lock(enum lock_label lbl, struct ha_spinlock *l,
index 3ca0b5a4e51ef9964552d0a421d2c6ea80bd59e9..4b3e72b205b36a470fc78fb51cbef3d88c36484b 100644 (file)
@@ -998,6 +998,46 @@ int __ha_rwlock_tryrdtosk(enum lock_label lbl, struct ha_rwlock *l,
        return r;
 }
 
+int __ha_rwlock_tryrdtowr(enum lock_label lbl, struct ha_rwlock *l,
+                          const char *func, const char *file, int line)
+{
+       ulong tbit = (ti && ti->ltid_bit) ? ti->ltid_bit : 1;
+       struct ha_rwlock_state *st = &l->info.st[tgid-1];
+       uint64_t start_time;
+       uint bucket;
+       int r;
+
+       if ((st->cur_writer | st->cur_seeker) & tbit)
+               abort();
+
+       if (!(st->cur_readers & tbit))
+               abort();
+
+       HA_ATOMIC_OR(&st->wait_writers, tbit);
+
+       start_time = -now_mono_time();
+       r = __RWLOCK_TRYRDTOWR(&l->lock);
+       start_time += now_mono_time();
+
+       if (likely(!r)) {
+               /* got the lock ! */
+               HA_ATOMIC_ADD(&lock_stats_sk[lbl].nsec_wait, start_time);
+
+               start_time &= 0x3fffffff; // keep values below 1 billion only
+               bucket = flsnz((uint32_t)start_time ? (uint32_t)start_time : 1) - 1;
+               HA_ATOMIC_INC(&lock_stats_sk[lbl].buckets[bucket]);
+               HA_ATOMIC_OR(&st->cur_writer, tbit);
+               HA_ATOMIC_AND(&st->cur_readers, ~tbit);
+               l->info.last_location.function = func;
+               l->info.last_location.file     = file;
+               l->info.last_location.line     = line;
+       }
+
+       HA_ATOMIC_AND(&st->wait_writers, ~tbit);
+       return r;
+}
+
+
 void __spin_init(struct ha_spinlock *l)
 {
        memset(l, 0, sizeof(struct ha_spinlock));