On 2/16/22 15:27, 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 | 81 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 81 insertions(+)
> 
> diff --git a/include/openvswitch/util.h b/include/openvswitch/util.h
> index 9c09e8aea..b2b4f3051 100644
> --- a/include/openvswitch/util.h
> +++ b/include/openvswitch/util.h
> @@ -189,6 +189,87 @@ OVS_NO_RETURN void ovs_assert_failure(const char *, 
> const char *, const char *);
>  #define UPDATE_MULTIVAR(VAR, EXPR)                                           
>  \
>      ((EXPR), (VAR) = NULL)
>  
> +

Nit: No need for the extra line.

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

> +/* 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_VAR(VAR) = ITER_NEXT_VAR(VAR))
> +
> +/*_LONG versions of the macros*/
> +
> +#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)                             
>  \
> +    ((ITER_VAR(VAR) = ITER_VAR(NEXT_VAR)), (VAR) = NULL, (NEXT_VAR) = NULL)
> +
>  /* Returns the number of elements in ARRAY. */
>  #define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY)
>  

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to