]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: event_hdl: pause/resume for subscriptions
authorAurelien DARRAGON <adarragon@haproxy.com>
Fri, 10 Mar 2023 09:45:58 +0000 (10:45 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 5 Apr 2023 06:58:17 +0000 (08:58 +0200)
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
include/haproxy/event_hdl.h
src/event_hdl.c

index eb5d05737d0b29d247f9d7b3c20d4d544fce921b..308f67016e9ee60c34169014224b3af50013c6ef 100644 (file)
@@ -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
index 41dc44674fbf6e5c1dfc0cd3942d10599a8bbb3c..7cadb55df3c620e48f3c7be1129190e76f575f6c 100644 (file)
@@ -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 <sub>
+ * 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 <sub>
+ * 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 <lookup_ip>
+ * within <sub_list> list.
+ * If <sub_list> 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 <lookup_ip>
+ * within <sub_list> list.
+ * If <sub_list> 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
index aecca8706727f4927e23d780ca97f5b6b296146c..14aed7a2f5136d1b5aeca58ca76fa3044e79ecad 100644 (file)
@@ -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