You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

175 lines
8.6 KiB

commit d66183efc6ee57c86400afba3b9b3f8635d3245e
Author: Olivier Houchard <ohouchard@haproxy.com>
Date: Fri Jan 18 17:26:26 2019 +0100
MINOR: lists: Implement locked variations.
Implement LIST_ADD_LOCKED(), LIST_ADDQ_LOCKED(), LIST_DEL_LOCKED() and
LIST_POP_LOCKED().
LIST_ADD_LOCKED, LIST_ADDQ_LOCKED and LIST_DEL_LOCKED work the same as
LIST_ADD, LIST_ADDQ and LIST_DEL, except before any manipulation it locks
the relevant elements of the list, so it's safe to manipulate the list
with multiple threads.
LIST_POP_LOCKED() removes the first element from the list, and returns its
data.
(cherry picked from commit a8434ec14612d9a04e50e1c51e58f663dad46e96)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 15a9450b508a3c9fc2ad2463931e89157c4331f1)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/include/common/mini-clist.h b/include/common/mini-clist.h
index 2988d2c2..b3f396ef 100644
--- a/include/common/mini-clist.h
+++ b/include/common/mini-clist.h
@@ -163,5 +163,149 @@ struct cond_wordlist {
&item->member != (list_head); \
item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
+#include <common/hathreads.h>
+#define LLIST_BUSY ((struct list *)1)
+
+/*
+ * Locked version of list manipulation macros.
+ * It is OK to use those concurrently from multiple threads, as long as the
+ * list is only used with the locked variants. The only "unlocked" macro you
+ * can use with a locked list is LIST_INIT.
+ */
+#define LIST_ADD_LOCKED(lh, el) \
+ do { \
+ while (1) { \
+ struct list *n; \
+ struct list *p; \
+ n = HA_ATOMIC_XCHG(&(lh)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ __ha_barrier_store(); \
+ p = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (el)->n = n; \
+ (el)->p = p; \
+ n->p = (el); \
+ __ha_barrier_store(); \
+ p->n = (el); \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+#define LIST_ADDQ_LOCKED(lh, el) \
+ do { \
+ while (1) { \
+ struct list *n; \
+ struct list *p; \
+ p = HA_ATOMIC_XCHG(&(lh)->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) \
+ continue; \
+ __ha_barrier_store(); \
+ n = HA_ATOMIC_XCHG(&p->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) { \
+ (lh)->n = p; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (el)->n = n; \
+ (el)->p = p; \
+ n->p = (el); \
+ __ha_barrier_store(); \
+ p->n = (el); \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+#define LIST_DEL_LOCKED(el) \
+ do { \
+ while (1) { \
+ struct list *n, *n2; \
+ struct list *p, *p2; \
+ n = HA_ATOMIC_XCHG(&(el)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ p = HA_ATOMIC_XCHG(&(el)->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ if (p != (el)) { \
+ p2 = HA_ATOMIC_XCHG(&p->n, LLIST_BUSY); \
+ if (p2 == LLIST_BUSY) { \
+ (el)->p = p; \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ } \
+ if (n != (el)) { \
+ n2 = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (n2 == LLIST_BUSY) { \
+ p2->n = (el); \
+ (el)->p = p; \
+ (el)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ } \
+ n->p = p; \
+ p->n = n; \
+ __ha_barrier_store(); \
+ break; \
+ } \
+ } while (0)
+
+
+/* Remove the first element from the list, and return it */
+#define LIST_POP_LOCKED(lh, pt, el) \
+ ({ \
+ void *_ret; \
+ while (1) { \
+ struct list *n, *n2; \
+ struct list *p, *p2; \
+ n = HA_ATOMIC_XCHG(&(lh)->n, LLIST_BUSY); \
+ if (n == LLIST_BUSY) \
+ continue; \
+ if (n == (lh)) { \
+ (lh)->n = lh; \
+ _ret = NULL; \
+ break; \
+ } \
+ p = HA_ATOMIC_XCHG(&n->p, LLIST_BUSY); \
+ if (p == LLIST_BUSY) { \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ n2 = HA_ATOMIC_XCHG(&n->n, LLIST_BUSY); \
+ if (n2 == LLIST_BUSY) { \
+ n->p = p; \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ p2 = HA_ATOMIC_XCHG(&n2->p, LLIST_BUSY); \
+ if (p2 == LLIST_BUSY) { \
+ n->n = n2; \
+ n->p = p; \
+ (lh)->n = n; \
+ __ha_barrier_store(); \
+ continue; \
+ } \
+ (lh)->n = n2; \
+ (n2)->p = (lh); \
+ __ha_barrier_store(); \
+ _ret = LIST_ELEM(n, pt, el); \
+ break; \
+ } \
+ (_ret); \
+ })
#endif /* _COMMON_MINI_CLIST_H */