mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
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.
This commit is contained in:
parent
36839dc39f
commit
a8434ec146
@ -163,5 +163,149 @@ struct cond_wordlist {
|
|||||||
&item->member != (list_head); \
|
&item->member != (list_head); \
|
||||||
item = back, back = LIST_ELEM(back->member.n, typeof(back), member))
|
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 */
|
#endif /* _COMMON_MINI_CLIST_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user