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.
This commit is contained in:
Aurelien DARRAGON 2023-03-10 10:45:58 +01:00 committed by Christopher Faulet
parent b4b7320a6a
commit f751a97a11
3 changed files with 111 additions and 2 deletions

View 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

View 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

View 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