MINOR: list: define a watcher type

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.
This commit is contained in:
Amaury Denoyelle 2024-10-23 11:31:44 +02:00
parent 2199179461
commit eafa8a32bb
2 changed files with 53 additions and 0 deletions

View 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;

View 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 */