On Fri, Jul 18, 2014 at 11:33:38PM -0700, Ben Pfaff wrote: > On Fri, Jul 18, 2014 at 09:05:49PM -0700, Jarno Rajahalme wrote: > > Older GCC (e.g. 4.1.2) did not like the pointer casts used for > > initializing the iteration cursors. This patch changes the code to > > avoid the void casts for GCC, and makes the classifier interface more > > similar to that of the cmap. These changes make the code work with > > GCC 4.1.2 strict aliasing rules. > > > > VMware-BZ: #1287651 > > > > Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> > > I see why GCC didn't like this code. > > There are lots of tricky constraints here. We don't want to violate ISO > aliasing rules, we have to stick to exactly one declaration in the first > clause of the for statement, and we don't want to have different code > for GCC and other compilers if we don't have to. The proposed solution > here compromises on the last one. > > I spent a bunch of time experimenting and came up with what I think is > the outline of another solution. How about adding a 'node' member to > cmap_cursor, like this: > > struct cmap_cursor { > const struct cmap_impl *impl; > uint32_t bucket_idx; > int entry_idx; > struct cmap_node *node; > }; > > struct cmap_cursor cmap_cursor_start(const struct cmap *); > void cmap_cursor_advance(struct cmap_cursor *); > > #define CMAP_FOR_EACH(NODE, MEMBER, CMAP) \ > for (struct cmap_cursor cursor__ = cmap_cursor_start(CMAP); \ > (cursor__.node \ > ? (ASSIGN_CONTAINER(NODE, cursor__.node, MEMBER), true) \ > : false); \ > cmap_cursor_advance(&cursor__)) > > #define CMAP_FOR_EACH_SAFE(NODE, MEMBER, CMAP) \ > for (struct cmap_cursor cursor__ = cmap_cursor_start(CMAP); \ > (cursor__.node \ > ? (ASSIGN_CONTAINER(NODE, cursor__.node, MEMBER), \ > cmap_cursor_advance(&cursor__), \ > true) \ > : false); \ > ) > > with corresponding support functions: > > struct cmap_cursor > cmap_cursor_start(const struct cmap *cmap) > { > struct cmap_cursor cursor; > > cursor.impl = cmap_get_impl(cmap); > cursor.bucket_idx = 0; > cursor.entry_idx = 0; > cursor.node = NULL; > cmap_cursor_advance(&cursor); > > return cursor; > } > > void > cmap_cursor_advance(struct cmap_cursor *cursor) > { > const struct cmap_impl *impl = cursor->impl; > > if (cursor->node) { > cursor->node = cmap_node_next(cursor->node); > if (cursor->node) { > return; > } > } > > while (cursor->bucket_idx <= impl->mask) { > const struct cmap_bucket *b = &impl->buckets[cursor->bucket_idx]; > > while (cursor->entry_idx < CMAP_K) { > cursor->node = cmap_node_next(&b->nodes[cursor->entry_idx++]); > if (cursor->node) { > return; > } > } > > cursor->bucket_idx++; > cursor->entry_idx = 0; > } > }
Here's a fully worked out version of this idea that compiles and passes all the tests (at least with GCC 4.7.2). With this, the _SAFE variants don't take an extra named variable or really have any extra cost, so one thinks about just getting making the normal variant the same as _SAFE: diff --git a/lib/classifier.c b/lib/classifier.c index 332e05a..9c23cd6 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -476,8 +476,8 @@ classifier_destroy(struct classifier *cls) OVS_EXCLUDED(cls->mutex) { if (cls) { - struct cls_partition *partition, *next_partition; - struct cls_subtable *subtable, *next_subtable; + struct cls_partition *partition; + struct cls_subtable *subtable; int i; ovs_mutex_lock(&cls->mutex); @@ -485,14 +485,12 @@ classifier_destroy(struct classifier *cls) trie_destroy(&cls->tries[i].root); } - CMAP_FOR_EACH_SAFE (subtable, next_subtable, cmap_node, - &cls->subtables_map) { + CMAP_FOR_EACH_SAFE (subtable, cmap_node, &cls->subtables_map) { destroy_subtable(cls, subtable); } cmap_destroy(&cls->subtables_map); - CMAP_FOR_EACH_SAFE (partition, next_partition, cmap_node, - &cls->partitions) { + CMAP_FOR_EACH_SAFE (partition, cmap_node, &cls->partitions) { ovsrcu_postpone(free, partition); } cmap_destroy(&cls->partitions); diff --git a/lib/cmap.c b/lib/cmap.c index 5d6dbcf..ba744cc 100644 --- a/lib/cmap.c +++ b/lib/cmap.c @@ -784,31 +784,29 @@ cmap_rehash(struct cmap *cmap, uint32_t mask) return new; } -/* Initializes 'cursor' for iterating through 'cmap'. - * - * Use via CMAP_FOR_EACH. */ -void -cmap_cursor_init(struct cmap_cursor *cursor, const struct cmap *cmap) +struct cmap_cursor +cmap_cursor_start(const struct cmap *cmap) { - cursor->impl = cmap_get_impl(cmap); - cursor->bucket_idx = 0; - cursor->entry_idx = 0; + struct cmap_cursor cursor; + + cursor.impl = cmap_get_impl(cmap); + cursor.bucket_idx = 0; + cursor.entry_idx = 0; + cursor.node = NULL; + cmap_cursor_advance(&cursor); + + return cursor; } -/* Returns the next node for 'cursor' to visit, following 'node', or NULL if - * the last node has been visited. - * - * Use via CMAP_FOR_EACH. */ -struct cmap_node * -cmap_cursor_next(struct cmap_cursor *cursor, const struct cmap_node *node) +void +cmap_cursor_advance(struct cmap_cursor *cursor) { const struct cmap_impl *impl = cursor->impl; - if (node) { - struct cmap_node *next = cmap_node_next(node); - - if (next) { - return next; + if (cursor->node) { + cursor->node = cmap_node_next(cursor->node); + if (cursor->node) { + return; } } @@ -816,18 +814,15 @@ cmap_cursor_next(struct cmap_cursor *cursor, const struct cmap_node *node) const struct cmap_bucket *b = &impl->buckets[cursor->bucket_idx]; while (cursor->entry_idx < CMAP_K) { - struct cmap_node *node = cmap_node_next(&b->nodes[cursor->entry_idx++]); - - if (node) { - return node; + cursor->node = cmap_node_next(&b->nodes[cursor->entry_idx++]); + if (cursor->node) { + return; } } cursor->bucket_idx++; cursor->entry_idx = 0; } - - return NULL; } /* Returns the next node in 'cmap' in hash order, or NULL if no nodes remain in diff --git a/lib/cmap.h b/lib/cmap.h index b7569f5..87a1d53 100644 --- a/lib/cmap.h +++ b/lib/cmap.h @@ -168,70 +168,54 @@ struct cmap_node *cmap_find_protected(const struct cmap *, uint32_t hash); * has already expired. */ -#define CMAP_CURSOR_FOR_EACH(NODE, MEMBER, CURSOR, CMAP) \ - for ((cmap_cursor_init(CURSOR, CMAP), \ - ASSIGN_CONTAINER(NODE, cmap_cursor_next(CURSOR, NULL), MEMBER)); \ - NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER); \ - ASSIGN_CONTAINER(NODE, cmap_cursor_next(CURSOR, &(NODE)->MEMBER), \ - MEMBER)) - -#define CMAP_CURSOR_FOR_EACH_SAFE(NODE, NEXT, MEMBER, CURSOR, CMAP) \ - for ((cmap_cursor_init(CURSOR, CMAP), \ - ASSIGN_CONTAINER(NODE, cmap_cursor_next(CURSOR, NULL), MEMBER)); \ - (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER) \ - ? ASSIGN_CONTAINER(NEXT, cmap_cursor_next(CURSOR, &(NODE)->MEMBER), \ - MEMBER), true \ - : false); \ - (NODE) = (NEXT)) - -#define CMAP_CURSOR_FOR_EACH_CONTINUE(NODE, MEMBER, CURSOR) \ - for (ASSIGN_CONTAINER(NODE, cmap_cursor_next(CURSOR, &(NODE)->MEMBER), \ - MEMBER); \ - NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER); \ - ASSIGN_CONTAINER(NODE, cmap_cursor_next(CURSOR, &(NODE)->MEMBER), \ - MEMBER)) +#define CMAP_CURSOR_FOR_EACH(NODE, MEMBER, CURSOR, CMAP) \ + for (*(CURSOR) = cmap_cursor_start(CMAP); \ + ((CURSOR)->node \ + ? (ASSIGN_CONTAINER(NODE, (CURSOR)->node, MEMBER), true) \ + : false); \ + cmap_cursor_advance(CURSOR)) + +#define CMAP_CURSOR_FOR_EACH_SAFE(NODE, MEMBER, CURSOR, CMAP) \ + for (*(CURSOR) = cmap_cursor_start(CMAP); \ + ((CURSOR)->node \ + ? (ASSIGN_CONTAINER(NODE, (CURSOR)->node, MEMBER), \ + cmap_cursor_advance(CURSOR), \ + true) \ + : false); \ + ) + +#define CMAP_CURSOR_FOR_EACH_CONTINUE(NODE, MEMBER, CURSOR) \ + for (cmap_cursor_advance(CURSOR); \ + ((CURSOR)->node \ + ? (ASSIGN_CONTAINER(NODE, (CURSOR)->node, MEMBER), true) \ + : false); \ + cmap_cursor_advance(CURSOR)) struct cmap_cursor { const struct cmap_impl *impl; uint32_t bucket_idx; int entry_idx; + struct cmap_node *node; }; -void cmap_cursor_init(struct cmap_cursor *, const struct cmap *); -struct cmap_node *cmap_cursor_next(struct cmap_cursor *, - const struct cmap_node *); - - -static inline struct cmap_cursor cmap_cursor_start(const struct cmap *cmap, - void **pnode, - const void *offset) -{ - struct cmap_cursor cursor; - - cmap_cursor_init(&cursor, cmap); - *pnode = (char *)cmap_cursor_next(&cursor, NULL) + (ptrdiff_t)offset; - - return cursor; -} - -#define CMAP_CURSOR_START(NODE, MEMBER, CMAP) \ - cmap_cursor_start(CMAP, (void **)&(NODE), \ - OBJECT_CONTAINING(NULL, NODE, MEMBER)) +struct cmap_cursor cmap_cursor_start(const struct cmap *); +void cmap_cursor_advance(struct cmap_cursor *); #define CMAP_FOR_EACH(NODE, MEMBER, CMAP) \ - for (struct cmap_cursor cursor__ = CMAP_CURSOR_START(NODE, MEMBER, CMAP); \ - NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER); \ - ASSIGN_CONTAINER(NODE, cmap_cursor_next(&cursor__, &(NODE)->MEMBER), \ - MEMBER)) - -#define CMAP_FOR_EACH_SAFE(NODE, NEXT, MEMBER, CMAP) \ - for (struct cmap_cursor cursor__ = CMAP_CURSOR_START(NODE, MEMBER, CMAP); \ - (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER) \ - ? ASSIGN_CONTAINER(NEXT, \ - cmap_cursor_next(&cursor__, &(NODE)->MEMBER), \ - MEMBER), true \ + for (struct cmap_cursor cursor__ = cmap_cursor_start(CMAP); \ + (cursor__.node \ + ? (ASSIGN_CONTAINER(NODE, cursor__.node, MEMBER), true) \ + : false); \ + cmap_cursor_advance(&cursor__)) + +#define CMAP_FOR_EACH_SAFE(NODE, MEMBER, CMAP) \ + for (struct cmap_cursor cursor__ = cmap_cursor_start(CMAP); \ + (cursor__.node \ + ? (ASSIGN_CONTAINER(NODE, cursor__.node, MEMBER), \ + cmap_cursor_advance(&cursor__), \ + true) \ : false); \ - (NODE) = (NEXT)) + ) static inline struct cmap_node *cmap_first(const struct cmap *); diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 90445d1..9fbe4da 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -963,10 +963,10 @@ dp_netdev_remove_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow) static void dp_netdev_flow_flush(struct dp_netdev *dp) { - struct dp_netdev_flow *netdev_flow, *next; + struct dp_netdev_flow *netdev_flow; ovs_mutex_lock(&dp->flow_mutex); - CMAP_FOR_EACH_SAFE (netdev_flow, next, node, &dp->flow_table) { + CMAP_FOR_EACH_SAFE (netdev_flow, node, &dp->flow_table) { dp_netdev_remove_flow(dp, netdev_flow); } ovs_mutex_unlock(&dp->flow_mutex); Thanks, Ben. _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev