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.
diff --git a/include/haproxy/event_hdl-t.h b/include/haproxy/event_hdl-t.h
index eb5d057..308f670 100644
--- a/include/haproxy/event_hdl-t.h
+++ b/include/haproxy/event_hdl-t.h
@@ -206,12 +206,16 @@
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 41dc446..7cadb55 100644
--- a/include/haproxy/event_hdl.h
+++ b/include/haproxy/event_hdl.h
@@ -301,6 +301,35 @@
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
diff --git a/src/event_hdl.c b/src/event_hdl.c
index aecca87..14aed7a 100644
--- a/src/event_hdl.c
+++ b/src/event_hdl.c
@@ -444,6 +444,7 @@
/* 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 @@
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 @@
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 @@
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