From f751a97a11fbb5c5c652ee5dd913eb0cc1113e28 Mon Sep 17 00:00:00 2001 From: Aurelien DARRAGON Date: Fri, 10 Mar 2023 10:45:58 +0100 Subject: [PATCH] MINOR: event_hdl: pause/resume for subscriptions While working on event handling from lua, the need for a pause/resume function to temporarily disable a subscription was raised. We solve this by introducing the EHDL_SUB_F_PAUSED flag for subscriptions. The flag is set via _pause() and cleared via _resume(), and it is checked prior to notifying the subscription in publish function. Pause and Resume functions are also available for via lookups for identified subscriptions. If 68e692da0 ("MINOR: event_hdl: add event handler base api") is being backported, then this commit should be backported with it. --- include/haproxy/event_hdl-t.h | 4 ++ include/haproxy/event_hdl.h | 29 +++++++++++++ src/event_hdl.c | 80 ++++++++++++++++++++++++++++++++++- 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/include/haproxy/event_hdl-t.h b/include/haproxy/event_hdl-t.h index eb5d05737..308f67016 100644 --- a/include/haproxy/event_hdl-t.h +++ b/include/haproxy/event_hdl-t.h @@ -206,12 +206,16 @@ struct event_hdl { void *private; }; +/* flags for event_hdl_sub struct (32 bits) */ +#define EHDL_SUB_F_PAUSED 0x0001 /* subscription will temporarily ignore events */ + /* list elem: subscription (handler subscribed to specific events) */ struct event_hdl_sub { struct mt_list mt_list; /* event type subscription */ struct event_hdl_sub_type sub; + uint32_t flags; /* event handler */ struct event_hdl hdl; /* used to guarantee that END event will be delivered diff --git a/include/haproxy/event_hdl.h b/include/haproxy/event_hdl.h index 41dc44674..7cadb55df 100644 --- a/include/haproxy/event_hdl.h +++ b/include/haproxy/event_hdl.h @@ -301,6 +301,35 @@ int event_hdl_lookup_resubscribe(event_hdl_sub_list *sub_list, struct event_hdl_sub *event_hdl_lookup_take(event_hdl_sub_list *sub_list, uint64_t lookup_id); +/* pause an existing subscription + * the subscription will no longer receive events (reversible) + * This can be reverted thanks to _resume() function + */ +void event_hdl_pause(struct event_hdl_sub *sub); + +/* resume an existing subscription + * that was previously paused using _pause() function + */ +void event_hdl_resume(struct event_hdl_sub *sub); + +/* Same as event_hdl_pause() for identified subscriptions: + * use this function to pause the subscription + * within list. + * If is NULL, global subscription list will be used. + * Returns 1 for SUCCESS and 0 if not found + */ +int event_hdl_lookup_pause(event_hdl_sub_list *sub_list, + uint64_t lookup_id); + +/* Same as event_hdl_resume() for identified subscriptions: + * use this function to resume the subscription + * within list. + * If is NULL, global subscription list will be used. + * Returns 1 for SUCCESS and 0 if not found + */ +int event_hdl_lookup_resume(event_hdl_sub_list *sub_list, + uint64_t lookup_id); + /* ------ PUBLISHING FUNCTIONS ------ */ /* this macro is provided as an internal helper for EVENT_HDL_TRIGGER to automatically diff --git a/src/event_hdl.c b/src/event_hdl.c index aecca8706..14aed7a2f 100644 --- a/src/event_hdl.c +++ b/src/event_hdl.c @@ -444,6 +444,7 @@ struct event_hdl_sub *event_hdl_subscribe_ptr(event_hdl_sub_list *sub_list, /* assignments */ new_sub->sub.family = e_type.family; new_sub->sub.subtype = e_type.subtype; + new_sub->flags = 0; new_sub->hdl = hdl; if (hdl.async) { @@ -596,6 +597,38 @@ int event_hdl_resubscribe(struct event_hdl_sub *cur_sub, struct event_hdl_sub_ty return _event_hdl_resub_async(cur_sub, type); } +void _event_hdl_pause(struct event_hdl_sub *cur_sub) +{ + cur_sub->flags |= EHDL_SUB_F_PAUSED; +} + +void event_hdl_pause(struct event_hdl_sub *cur_sub) +{ + struct mt_list lock; + + lock = MT_LIST_LOCK_ELT(&cur_sub->mt_list); + if (lock.next != &cur_sub->mt_list) + _event_hdl_pause(cur_sub); + // else already removed + MT_LIST_UNLOCK_ELT(&cur_sub->mt_list, lock); +} + +void _event_hdl_resume(struct event_hdl_sub *cur_sub) +{ + cur_sub->flags &= ~EHDL_SUB_F_PAUSED; +} + +void event_hdl_resume(struct event_hdl_sub *cur_sub) +{ + struct mt_list lock; + + lock = MT_LIST_LOCK_ELT(&cur_sub->mt_list); + if (lock.next != &cur_sub->mt_list) + _event_hdl_resume(cur_sub); + // else already removed + MT_LIST_UNLOCK_ELT(&cur_sub->mt_list, lock); +} + void event_hdl_unsubscribe(struct event_hdl_sub *del_sub) { _event_hdl_unsubscribe_async(del_sub); @@ -660,6 +693,48 @@ int event_hdl_lookup_resubscribe(event_hdl_sub_list *sub_list, return status; } +int event_hdl_lookup_pause(event_hdl_sub_list *sub_list, + uint64_t lookup_id) +{ + struct event_hdl_sub *cur_sub = NULL; + struct mt_list *elt1, elt2; + int found = 0; + + if (!sub_list) + sub_list = &global_event_hdl_sub_list; /* fall back to global list */ + + mt_list_for_each_entry_safe(cur_sub, &sub_list->head, mt_list, elt1, elt2) { + if (lookup_id == cur_sub->hdl.id) { + /* we found matching registered hdl */ + _event_hdl_pause(cur_sub); + found = 1; + break; /* id is unique, stop searching */ + } + } + return found; +} + +int event_hdl_lookup_resume(event_hdl_sub_list *sub_list, + uint64_t lookup_id) +{ + struct event_hdl_sub *cur_sub = NULL; + struct mt_list *elt1, elt2; + int found = 0; + + if (!sub_list) + sub_list = &global_event_hdl_sub_list; /* fall back to global list */ + + mt_list_for_each_entry_safe(cur_sub, &sub_list->head, mt_list, elt1, elt2) { + if (lookup_id == cur_sub->hdl.id) { + /* we found matching registered hdl */ + _event_hdl_resume(cur_sub); + found = 1; + break; /* id is unique, stop searching */ + } + } + return found; +} + struct event_hdl_sub *event_hdl_lookup_take(event_hdl_sub_list *sub_list, uint64_t lookup_id) { @@ -694,9 +769,10 @@ static int _event_hdl_publish(event_hdl_sub_list *sub_list, struct event_hdl_sub int error = 0; mt_list_for_each_entry_safe(cur_sub, &sub_list->head, mt_list, elt1, elt2) { - /* notify each function that has subscribed to sub_family.type */ + /* notify each function that has subscribed to sub_family.type, unless paused */ if ((cur_sub->sub.family == e_type.family) && - ((cur_sub->sub.subtype & e_type.subtype) == e_type.subtype)) { + ((cur_sub->sub.subtype & e_type.subtype) == e_type.subtype) && + !(cur_sub->flags & EHDL_SUB_F_PAUSED)) { /* hdl should be notified */ if (!cur_sub->hdl.async) { /* sync mode: simply call cb pointer