diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-02-10 19:14:35 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2013-02-10 19:14:35 +0100 |
commit | cf90523881521fe8396a728230169b6b8ea7e8da (patch) | |
tree | 3beba4f9b618f8db6637982fea5a5ae31ded8d12 /device.c | |
parent | bc1902d31fe5d751a50981d668cc1356b4796639 (diff) |
device: protect device event broadcast against simultaneous deletions of multiple receivers in the callback (can happen with aliases)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Diffstat (limited to 'device.c')
-rw-r--r-- | device.c | 25 |
1 files changed, 19 insertions, 6 deletions
@@ -183,14 +183,27 @@ static void __init dev_init(void) static void __device_broadcast_event(struct list_head *head, enum device_event ev) { - struct device_user *dep, *tmp; + struct device_user *dep; + static uint8_t idx[__DEV_EVENT_MAX]; + bool found; - list_for_each_entry_safe(dep, tmp, head, list) { - if (!dep->cb) - continue; + idx[ev]++; + do { + found = false; - dep->cb(dep, ev); - } + list_for_each_entry(dep, head, list) { + if (!dep->cb) + continue; + + if (dep->ev_idx[ev] == idx[ev]) + continue; + + dep->cb(dep, ev); + dep->ev_idx[ev] = idx[ev]; + found = true; + break; + } + } while (found); } void device_broadcast_event(struct device *dev, enum device_event ev) |