On 9 Mar 2022, at 17:10, Adrian Moreno wrote:
> Safe version of multi-variable iterator helpers declare an internal
> variable to store the next value of the iterator temporarily.
>
> Two versions of the macro are provided, one that still uses the NEXT
> variable for backwards compatibility and a shorter version that does not
> require the use of an additional variable provided by the user.
>
> Signed-off-by: Adrian Moreno <amore...@redhat.com>
> ---
> include/openvswitch/util.h | 80 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 80 insertions(+)
>
> diff --git a/include/openvswitch/util.h b/include/openvswitch/util.h
> index 2d81e3574..157f8cecd 100644
> --- a/include/openvswitch/util.h
> +++ b/include/openvswitch/util.h
> @@ -188,6 +188,86 @@ OVS_NO_RETURN void ovs_assert_failure(const char *,
> const char *, const char *);
> #define UPDATE_MULTIVAR(VAR, NEXT_ITER)
> \
> (ITER_VAR(VAR) = NEXT_ITER)
>
> +/* In the safe version of the multi-variable container iteration, the next
> + * value of the iterator is precalculated on the condition expression.
> + * This allows for the iterator to be freed inside the loop.
> + *
> + * Two versions of the macros are provided:
> + *
> + * * In the _SHORT version, the user does not have to provide a variable to
> + * store the next value of the iterator. Instead, a second iterator variable
> + * is declared in the INIT_ macro and its name is determined by
> + * ITER_NEXT_VAR(OBJECT).
> + *
> + * * In the _LONG version, the user provides another variable of the same
> type
> + * as the iterator object variable to store the next containing object.
> + * We still declare an iterator variable inside the loop but in this case
> it's
> + * name is derived from the name of the next containing variable.
> + * The value of the next containing object will only be set
> + * (via OBJECT_CONTAINING) if an additional condition is statisfied. This
> + * second condition must ensure it is safe to call OBJECT_CONTAINING on the
> + * next iterator variable.
> + * With respect to the value of the next containing object:
> + * - Inside of the loop: the variable is either NULL or safe to use.
> + * - Outside of the loop: the variable is NULL if the loop ends normally.
> + * If the loop ends with a "break;" statement, rules of Inside the loop
> + * apply.
> + */
> +#define ITER_NEXT_VAR(NAME) NAME ## __iterator__next__
> +
> +/* Safe initialization declares both iterators. */
> +#define INIT_MULTIVAR_SAFE_SHORT(VAR, MEMBER, POINTER, ITER_TYPE)
> \
> + INIT_MULTIVAR_SAFE_SHORT_EXP(VAR, MEMBER, POINTER, ITER_TYPE, (void) 0)
> +
> +#define INIT_MULTIVAR_SAFE_SHORT_EXP(VAR, MEMBER, POINTER, ITER_TYPE, ...)
> \
> + ITER_TYPE *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER),
> \
> + *ITER_NEXT_VAR(VAR) = NULL
> +
> +/* Evaluate the condition expression and, if satisfied, update the _next_
> + * iterator with the NEXT_EXPR.
> + * Both EXPR and NEXT_EXPR should only use ITER_VAR(VAR) and
> + * ITER_NEXT_VAR(VAR).
> + */
> +#define CONDITION_MULTIVAR_SAFE_SHORT(VAR, MEMBER, EXPR, NEXT_EXPR)
> \
> + ((EXPR) ?
> \
> + (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)),
> \
> + (NEXT_EXPR), 1) :
> \
> + (((VAR) = NULL), 0))
> +
> +#define UPDATE_MULTIVAR_SAFE_SHORT(VAR)
> \
> + UPDATE_MULTIVAR(VAR, ITER_NEXT_VAR(VAR))
> +
> +/*_LONG versions of the macros*/
Other than the small nit of adding a space and a dot. It looks fine, i.e.
+/* _LONG versions of the macros. */
Acked-by: Eelco Chaudron <echau...@redhat.com>
> +
> +#define INIT_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR, MEMBER, POINTER, ITER_TYPE)
> \
> + INIT_MULTIVAR_SAFE_LONG_EXP(VAR, NEXT_VAR, MEMBER, POINTER, ITER_TYPE,
> \
> + (void) 0)
> \
> +
> +#define INIT_MULTIVAR_SAFE_LONG_EXP(VAR, NEXT_VAR, MEMBER, POINTER,
> \
> + ITER_TYPE, ...)
> \
> + ITER_TYPE *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER),
> \
> + *ITER_VAR(NEXT_VAR) = NULL
> +
> +/* Evaluate the condition expression and, if satisfied, update the _next_
> + * iterator with the NEXT_EXPR. After, evaluate the NEXT_COND and, if
> + * satisfied, set the value to NEXT_VAR. NEXT_COND must use
> ITER_VAR(NEXT_VAR).
> + *
> + * Both EXPR and NEXT_EXPR should only use ITER_VAR(VAR) and
> + * ITER_VAR(NEXT_VAR).
> + */
> +#define CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR, MEMBER, EXPR, NEXT_EXPR,
> \
> + NEXT_COND)
> \
> + ((EXPR) ?
> \
> + (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)),
> \
> + (NEXT_EXPR), ((NEXT_COND) ?
> \
> + ((NEXT_VAR) =
> \
> + OBJECT_CONTAINING(ITER_VAR(NEXT_VAR), NEXT_VAR, MEMBER)) :
> \
> + ((NEXT_VAR) = NULL)), 1) :
> \
> + (((VAR) = NULL), ((NEXT_VAR) = NULL), 0))
> +
> +#define UPDATE_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR)
> \
> + UPDATE_MULTIVAR(VAR, ITER_VAR(NEXT_VAR))
> +
> /* Returns the number of elements in ARRAY. */
> #define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY)
>
> --
> 2.34.1
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev