]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: list: define a watcher type
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 23 Oct 2024 09:31:44 +0000 (11:31 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 10 Dec 2024 15:04:11 +0000 (16:04 +0100)
Define a new watcher type into list module. This type is similar to bref
and can be used to register an element which is currently tracking a
dynamic target. Contrary to bref, if the target is freed, every watcher
element are updated to point to a next valid entry or NULL.

This type will simplify handling of dynamic servers deletion, in
particular while stats dump are performed.

This patch is not a bug-fix. However, it is mandatory to fix a race
condition in dynamic servers. Thus, it should be backported along the
next commit up to 2.6.

include/haproxy/list-t.h
include/haproxy/list.h

index dd8493eed827db6ad5c3899a3faafce12081ee26..914e5a17b2387195985ba57c27968835e8cecc0b 100644 (file)
@@ -57,6 +57,17 @@ struct bref {
        struct list *ref; /* pointer to the target's list entry */
 };
 
+/* Similar to bref. Used to reference an element which is tracking a dynamic
+ * target. The main advantage over bref is that when target is freed, each
+ * elements pointers are automatically updated to the next entry or NULL if
+ * target was the last one.
+ */
+struct watcher {
+       struct mt_list el; /* attach point into target list */
+       void **pptr;       /* pointer to element which points to target */
+       size_t off;        /* offset into target type for mtlist storage of watcher */
+};
+
 /* a word list is a generic list with a pointer to a string in each element. */
 struct wordlist {
        struct list list;
index 58414885979df3e03791ab2f59a3f12bb2403309..ff203147c1c9977cb0b5523903d0ba8dc6c54b43 100644 (file)
@@ -260,4 +260,46 @@ static __inline struct mt_list *list_to_mt_list(struct list *list)
 
 }
 
+/* Init a <w> watcher entry to track targets. <pptr> is the pointer to the
+ * target pointer which will be updated via watcher_attach/detach operations.
+ * <attach_off> is the offset to access the target mt_list attach point for the
+ * watcher entry.
+ */
+static __inline void watcher_init(struct watcher *w, void *pptr, size_t attach_off)
+{
+       MT_LIST_INIT(&w->el);
+       w->pptr = pptr;
+       w->off = attach_off;
+}
+
+/* Tracks <target> via <w> watcher. Invalid if <w> is already attached. */
+static __inline void watcher_attach(struct watcher *w, void *target)
+{
+       struct mt_list *list = target + w->off;
+
+       BUG_ON_HOT(MT_LIST_INLIST(&w->el));
+
+       *w->pptr = target;
+       if (target)
+               MT_LIST_APPEND(list, &w->el);
+}
+
+/* Untracks target via <w> watcher. Invalid if <w> is not attached first. */
+static __inline void watcher_detach(struct watcher *w)
+{
+       BUG_ON_HOT(!MT_LIST_INLIST(&w->el));
+       *w->pptr = NULL;
+       MT_LIST_DELETE(&w->el);
+}
+
+/* Equivalent to a detach then attach on <target> via <w> watcher. Returns
+ * <target> as a convenience to use this function as increment in a for-loop.
+ */
+static __inline void *watcher_next(struct watcher *w, void *target)
+{
+       watcher_detach(w);
+       watcher_attach(w, target);
+       return target;
+}
+
 #endif /* _HAPROXY_LIST_H */