diff mbox series

[ovs-dev,v3,07/17] hmap: use multi-variable helpers for hmap loops

Message ID 20220216142800.3295236-8-amorenoz@redhat.com
State Superseded
Headers show
Series Fix undefined behavior in loop macros | expand

Checks

Context Check Description
ovsrobot/apply-robot warning apply and check: warning
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Adrián Moreno Feb. 16, 2022, 2:27 p.m. UTC
Rewrite hmap's loops using multi-variable helpers.

For SAFE loops, use the LONG version of the multi-variable macros to
keep backwards compatibility.

Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
---
 include/openvswitch/hmap.h | 65 ++++++++++++++++++++------------------
 lib/ovs-numa.h             |  4 +--
 tests/test-hmap.c          |  9 ++++++
 3 files changed, 46 insertions(+), 32 deletions(-)

Comments

0-day Robot Feb. 16, 2022, 3:50 p.m. UTC | #1
Bleep bloop.  Greetings Adrian Moreno, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
ERROR: Inappropriate bracing around statement
#80 FILE: include/openvswitch/hmap.h:185:
    HMAP_FOR_EACH_SAFE_INIT (NODE, NEXT, MEMBER, HMAP, (void) NEXT)

ERROR: Inappropriate bracing around statement
#118 FILE: lib/ovs-numa.h:71:
    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)

ERROR: Inappropriate bracing around statement
#122 FILE: lib/ovs-numa.h:74:
    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)

ERROR: Use ovs_assert() in place of assert()
#133 FILE: tests/test-hmap.c:65:
    assert(e == NULL);

ERROR: Use ovs_assert() in place of assert()
#141 FILE: tests/test-hmap.c:86:
        assert(e == NULL);

ERROR: Use ovs_assert() in place of assert()
#150 FILE: tests/test-hmap.c:249:
                    assert(next == NULL);

ERROR: Use ovs_assert() in place of assert()
#152 FILE: tests/test-hmap.c:251:
                    assert(&next->node == hmap_next(&hmap, &e->node));

ERROR: Use ovs_assert() in place of assert()
#161 FILE: tests/test-hmap.c:269:
            assert(next == NULL);

ERROR: Use ovs_assert() in place of assert()
#162 FILE: tests/test-hmap.c:270:
            assert(e == NULL);

Lines checked: 169, Warnings: 0, Errors: 9


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Dumitru Ceara Feb. 25, 2022, 12:07 p.m. UTC | #2
On 2/16/22 15:27, Adrian Moreno wrote:
> Rewrite hmap's loops using multi-variable helpers.
> 
> For SAFE loops, use the LONG version of the multi-variable macros to
> keep backwards compatibility.
> 
> Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
> ---

A couple tiny nits, with those addressed:

Acked-by: Dumitru Ceara <dceara@redhat.com>

> diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h
> index ecc251a7f..83bd10cca 100644
> --- a/lib/ovs-numa.h
> +++ b/lib/ovs-numa.h
> @@ -68,9 +68,9 @@ void ovs_numa_dump_destroy(struct ovs_numa_dump *);
>  int ovs_numa_thread_setaffinity_core(unsigned core_id);
>  
>  #define FOR_EACH_CORE_ON_DUMP(ITER, DUMP)                    \
> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->cores)
> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)

Nit: kind of unrelated.

>  
>  #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP)                    \
> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas)
> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)

Nit: here too.
Adrián Moreno Feb. 28, 2022, 9:18 a.m. UTC | #3
On 2/25/22 13:07, Dumitru Ceara wrote:
> On 2/16/22 15:27, Adrian Moreno wrote:
>> Rewrite hmap's loops using multi-variable helpers.
>>
>> For SAFE loops, use the LONG version of the multi-variable macros to
>> keep backwards compatibility.
>>
>> Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
>> ---
> 
> A couple tiny nits, with those addressed:
> 
> Acked-by: Dumitru Ceara <dceara@redhat.com>
> 
>> diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h
>> index ecc251a7f..83bd10cca 100644
>> --- a/lib/ovs-numa.h
>> +++ b/lib/ovs-numa.h
>> @@ -68,9 +68,9 @@ void ovs_numa_dump_destroy(struct ovs_numa_dump *);
>>   int ovs_numa_thread_setaffinity_core(unsigned core_id);
>>   
>>   #define FOR_EACH_CORE_ON_DUMP(ITER, DUMP)                    \
>> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->cores)
>> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)
> 
> Nit: kind of unrelated.
> 

Well... yes and no :)

The internal iterator name is now determined by:

#define ITER_VAR(NAME) NAME ## __iterator__

if we pass (myvar), the variable declaration will fail because 
(myvar)__iterator__ is not a valid variable name. Parenthesis would be required 
if we supported arbitrary expressions as the first argument but macros won't 
really work in that case.

I can add a comment explaining this limitation to the macros in 
include/openvswitch/util.h. Or maybe you can think of a way to overcome this 
limitation?


>>   
>>   #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP)                    \
>> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas)
>> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)
> 
> Nit: here too.
> 


Thanks
Dumitru Ceara Feb. 28, 2022, 9:44 a.m. UTC | #4
On 2/28/22 10:18, Adrian Moreno wrote:
> 
> 
> On 2/25/22 13:07, Dumitru Ceara wrote:
>> On 2/16/22 15:27, Adrian Moreno wrote:
>>> Rewrite hmap's loops using multi-variable helpers.
>>>
>>> For SAFE loops, use the LONG version of the multi-variable macros to
>>> keep backwards compatibility.
>>>
>>> Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
>>> ---
>>
>> A couple tiny nits, with those addressed:
>>
>> Acked-by: Dumitru Ceara <dceara@redhat.com>
>>
>>> diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h
>>> index ecc251a7f..83bd10cca 100644
>>> --- a/lib/ovs-numa.h
>>> +++ b/lib/ovs-numa.h
>>> @@ -68,9 +68,9 @@ void ovs_numa_dump_destroy(struct ovs_numa_dump *);
>>>   int ovs_numa_thread_setaffinity_core(unsigned core_id);
>>>     #define FOR_EACH_CORE_ON_DUMP(ITER, DUMP)                    \
>>> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->cores)
>>> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)
>>
>> Nit: kind of unrelated.
>>
> 
> Well... yes and no :)
> 
> The internal iterator name is now determined by:
> 
> #define ITER_VAR(NAME) NAME ## __iterator__
> 
> if we pass (myvar), the variable declaration will fail because
> (myvar)__iterator__ is not a valid variable name. Parenthesis would be
> required if we supported arbitrary expressions as the first argument but
> macros won't really work in that case.
> 

Thanks, I had missed that.

> I can add a comment explaining this limitation to the macros in
> include/openvswitch/util.h. Or maybe you can think of a way to overcome
> this limitation?
> 

Looking at hmap.h, it seems to me that we had this limitation from the
beginning.  We might as well leave it as-is.

Please ignore my original comment.

> 
>>>     #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP)                    \
>>> -    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas)
>>> +    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)
>>
>> Nit: here too.
>>
> 
> 
> Thanks

Regards,
Dumitru
diff mbox series

Patch

diff --git a/include/openvswitch/hmap.h b/include/openvswitch/hmap.h
index 4e001cc69..9827e993d 100644
--- a/include/openvswitch/hmap.h
+++ b/include/openvswitch/hmap.h
@@ -134,17 +134,19 @@  struct hmap_node *hmap_random_node(const struct hmap *);
  * without using 'break', NODE will be NULL.  This is true for all of the
  * HMAP_FOR_EACH_*() macros.
  */
-#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP)               \
-    for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \
-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
-         || ((NODE = NULL), false);                                     \
-         ASSIGN_CONTAINER(NODE, hmap_next_with_hash(&(NODE)->MEMBER),   \
-                          MEMBER))
-#define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP)               \
-    for (INIT_CONTAINER(NODE, hmap_first_in_bucket(HMAP, HASH), MEMBER); \
-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
-         || ((NODE = NULL), false);                                     \
-         ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER))
+#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP)                     \
+    for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_with_hash(HMAP, HASH),        \
+                       struct hmap_node);                                     \
+         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
+         UPDATE_MULTIVAR(NODE,                                                \
+                         ITER_VAR(NODE) = hmap_next_with_hash(ITER_VAR(NODE))))
+
+#define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP)                     \
+    for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_in_bucket(HMAP, HASH),        \
+                       struct hmap_node);                                     \
+         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
+         UPDATE_MULTIVAR(NODE,                                                \
+                         ITER_VAR(NODE) = hmap_next_in_bucket(ITER_VAR(NODE))))
 
 static inline struct hmap_node *hmap_first_with_hash(const struct hmap *,
                                                      size_t hash);
@@ -170,33 +172,36 @@  bool hmap_contains(const struct hmap *, const struct hmap_node *);
 /* Iterates through every node in HMAP. */
 #define HMAP_FOR_EACH(NODE, MEMBER, HMAP) \
     HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, (void) 0)
-#define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...)                     \
-    for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__;   \
-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
-         || ((NODE = NULL), false);                                     \
-         ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
+#define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...)                           \
+    for (INIT_MULTIVAR_EXP(NODE, MEMBER, hmap_first(HMAP), struct hmap_node,  \
+                           __VA_ARGS__);                                      \
+         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
+         UPDATE_MULTIVAR(NODE,                                                \
+                         ITER_VAR(NODE) = hmap_next(HMAP, ITER_VAR(NODE))))   \
 
 /* Safe when NODE may be freed (not needed when NODE may be removed from the
  * hash map but its members remain accessible and intact). */
 #define HMAP_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HMAP) \
-    HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, (void) 0)
-#define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...)          \
-    for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__;   \
-         ((NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))               \
-          || ((NODE = NULL), false)                                     \
-          ? INIT_CONTAINER(NEXT, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), 1 \
-          : 0);                                                         \
-         (NODE) = (NEXT))
+    HMAP_FOR_EACH_SAFE_INIT (NODE, NEXT, MEMBER, HMAP, (void) NEXT)
+
+#define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...)                \
+    for (INIT_MULTIVAR_SAFE_LONG_EXP(NODE, NEXT, MEMBER, hmap_first(HMAP),    \
+                                      struct hmap_node, __VA_ARGS__);         \
+         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                     \
+                                      ITER_VAR(NODE) != NULL,                 \
+                            ITER_VAR(NEXT) = hmap_next(HMAP, ITER_VAR(NODE)), \
+                                      ITER_VAR(NEXT) != NULL);                \
+         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
 
 /* Continues an iteration from just after NODE. */
 #define HMAP_FOR_EACH_CONTINUE(NODE, MEMBER, HMAP) \
     HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, (void) 0)
-#define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...)            \
-    for (ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), \
-         __VA_ARGS__;                                                   \
-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
-         || ((NODE = NULL), false);                                     \
-         ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
+#define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...)                  \
+    for (INIT_MULTIVAR_EXP(NODE, MEMBER, hmap_next(HMAP, &(NODE)->MEMBER),    \
+                           struct hmap_node, __VA_ARGS__);                    \
+         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
+         UPDATE_MULTIVAR(NODE,                                                \
+                         ITER_VAR(NODE) = hmap_next(HMAP, ITER_VAR(NODE))))   \
 
 static inline struct hmap_node *
 hmap_pop_helper__(struct hmap *hmap, size_t *bucket) {
diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h
index ecc251a7f..83bd10cca 100644
--- a/lib/ovs-numa.h
+++ b/lib/ovs-numa.h
@@ -68,9 +68,9 @@  void ovs_numa_dump_destroy(struct ovs_numa_dump *);
 int ovs_numa_thread_setaffinity_core(unsigned core_id);
 
 #define FOR_EACH_CORE_ON_DUMP(ITER, DUMP)                    \
-    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->cores)
+    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)
 
 #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP)                    \
-    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas)
+    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)
 
 #endif /* ovs-numa.h */
diff --git a/tests/test-hmap.c b/tests/test-hmap.c
index 9259b0b3f..a40ac8953 100644
--- a/tests/test-hmap.c
+++ b/tests/test-hmap.c
@@ -62,6 +62,7 @@  check_hmap(struct hmap *hmap, const int values[], size_t n,
         hmap_values[i++] = e->value;
     }
     assert(i == n);
+    assert(e == NULL);
 
     memcpy(sort_values, values, sizeof *sort_values * n);
     qsort(sort_values, n, sizeof *sort_values, compare_ints);
@@ -82,6 +83,7 @@  check_hmap(struct hmap *hmap, const int values[], size_t n,
             count += e->value == values[i];
         }
         assert(count == 1);
+        assert(e == NULL);
     }
 
     /* Check counters. */
@@ -243,6 +245,11 @@  test_hmap_for_each_safe(hash_func *hash)
             i = 0;
             n_remaining = n;
             HMAP_FOR_EACH_SAFE (e, next, node, &hmap) {
+                if (hmap_next(&hmap, &e->node) == NULL) {
+                    assert(next == NULL);
+                } else {
+                    assert(&next->node == hmap_next(&hmap, &e->node));
+                }
                 assert(i < n);
                 if (pattern & (1ul << e->value)) {
                     size_t j;
@@ -259,6 +266,8 @@  test_hmap_for_each_safe(hash_func *hash)
                 i++;
             }
             assert(i == n);
+            assert(next == NULL);
+            assert(e == NULL);
 
             for (i = 0; i < n; i++) {
                 if (pattern & (1ul << i)) {