chiark / gitweb /
resolved: fix notification iteration logic when transactions are completed
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Feb 2016 19:39:45 +0000 (20:39 +0100)
committerSven Eden <yamakuzure@gmx.net>
Fri, 16 Jun 2017 08:12:57 +0000 (10:12 +0200)
When a transaction is complete, and we notify its owners, make sure we deal
correctly with the requesters removing themselves from the list of owners while
we continue iterating.

This was previously already dealt with with transactions that require other
transactions for DNSSEC purposes, fix this for other possibly transaction
owners too now.

Since iterating through "Set" objects is not safe regarding removal of entries
from it, rework the logic to use two Sets, and move each entry we notified from
one set to the other set before we dispatch the notification. This move operation
requires no additional memory, and enables us to ensure that we don't notify
any object twice.

Fixes: #2676
src/basic/macro.h
src/basic/set.h

index 2695d0edb75ba436e645fc1f32786dde78e22bbd..ab5cc97e17ac386a9031c0f61053e699fd2f5a1e 100644 (file)
@@ -361,6 +361,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
                 _found;                         \
         })
 
+#define SWAP_TWO(x, y) do {                        \
+                typeof(x) _t = (x);                \
+                (x) = (y);                         \
+                (y) = (_t);                        \
+        } while (false)
+
 /* Define C11 thread_local attribute even on older gcc compiler
  * version */
 #ifndef thread_local
index f8e86478cb83b905b8e26f4bd744114c95c325b7..170f0c44692296bb22d5b90fce9c9744d8c1b0cd 100644 (file)
@@ -130,6 +130,9 @@ int set_put_strdupv(Set *s, char **l);
 #define SET_FOREACH(e, s, i) \
         for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); )
 
+#define SET_FOREACH_MOVE(e, d, s)                                       \
+        for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); )
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);