aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2020-03-18 15:45:27 +0100
committerDenis Kenzior <denkenz@gmail.com>2020-03-18 13:49:22 -0500
commit9e18552fe762b209a46c279598ed87315c23a65c (patch)
tree415c020b338d938f2e09af08ab53bbe2affd2145
parenta2006a3d29f9620bb329e1a2111512686fb728c9 (diff)
downloadiwd-9e18552fe762b209a46c279598ed87315c23a65c.tar.gz
watchlist: Allow watch CBs to call watchlist_destroy
If during WATCHLIST_NOTIFY{,_MATCHES,_NO_ARGS} one of the watch notify callback triggers a call to watchlist_destroy, give up calling remaining watches and destroy the watchlist without crashing. This is useful in frame-xchg.c (P2P use case) where a frame watch may trigger a move to a new state after receiving a specific frame, and remove one group of frame watches (including its watchlist) to create a different group.
-rw-r--r--src/watchlist.c5
-rw-r--r--src/watchlist.h22
2 files changed, 23 insertions, 4 deletions
diff --git a/src/watchlist.c b/src/watchlist.c
index 4f4d8259b..a14476bd2 100644
--- a/src/watchlist.c
+++ b/src/watchlist.c
@@ -127,6 +127,11 @@ static void __watchlist_clear(struct watchlist *watchlist)
void watchlist_destroy(struct watchlist *watchlist)
{
+ if (watchlist->in_notify) {
+ watchlist->pending_destroy = true;
+ return;
+ }
+
__watchlist_clear(watchlist);
l_queue_destroy(watchlist->items, NULL);
watchlist->items = NULL;
diff --git a/src/watchlist.h b/src/watchlist.h
index cd408ac89..c3632859c 100644
--- a/src/watchlist.h
+++ b/src/watchlist.h
@@ -38,6 +38,7 @@ struct watchlist {
struct l_queue *items;
bool in_notify : 1;
bool stale_items : 1;
+ bool pending_destroy : 1;
const struct watchlist_ops *ops;
};
@@ -69,9 +70,13 @@ void __watchlist_prune_stale(struct watchlist *watchlist);
if (item->id == 0) \
continue; \
t(args, item->notify_data); \
+ if ((watchlist)->pending_destroy) \
+ break; \
} \
(watchlist)->in_notify = false; \
- if ((watchlist)->stale_items) \
+ if ((watchlist)->pending_destroy) \
+ watchlist_destroy(watchlist); \
+ else if ((watchlist)->stale_items) \
__watchlist_prune_stale(watchlist); \
} while (false) \
@@ -91,9 +96,14 @@ void __watchlist_prune_stale(struct watchlist *watchlist);
continue; \
\
t(args, item->notify_data); \
+ \
+ if ((watchlist)->pending_destroy) \
+ break; \
} \
(watchlist)->in_notify = false; \
- if ((watchlist)->stale_items) \
+ if ((watchlist)->pending_destroy) \
+ watchlist_destroy(watchlist); \
+ else if ((watchlist)->stale_items) \
__watchlist_prune_stale(watchlist); \
} while (false)
@@ -108,9 +118,13 @@ void __watchlist_prune_stale(struct watchlist *watchlist);
type t = item->notify; \
if (item->id == 0) \
continue; \
- t(item->notify_data); \
+ t(item->notify_data); \
+ if ((watchlist)->pending_destroy) \
+ break; \
} \
(watchlist)->in_notify = false; \
- if ((watchlist)->stale_items) \
+ if ((watchlist)->pending_destroy) \
+ watchlist_destroy(watchlist); \
+ else if ((watchlist)->stale_items) \
__watchlist_prune_stale(watchlist); \
} while (false)