Makes popping each member of the hmap a bit easier.
Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
Acked-by: Ben Pfaff <blp@ovn.org>
void
cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex)
{
- struct remote_mp *rmp, *rmp_next;
+ struct remote_mp *rmp;
if (!cfm) {
return;
hmap_remove(all_cfms, &cfm->hmap_node);
ovs_mutex_unlock(&mutex);
- HMAP_FOR_EACH_SAFE (rmp, rmp_next, node, &cfm->remote_mps) {
- hmap_remove(&cfm->remote_mps, &rmp->node);
+ HMAP_FOR_EACH_POP (rmp, node, &cfm->remote_mps) {
free(rmp);
}
(NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \
ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
+static inline struct hmap_node *
+hmap_pop_helper__(struct hmap *hmap, size_t *bucket) {
+
+ for (; *bucket <= hmap->mask; (*bucket)++) {
+ struct hmap_node *node = hmap->buckets[*bucket];
+
+ if (node) {
+ hmap_remove(hmap, node);
+ return node;
+ }
+ }
+
+ return NULL;
+}
+
+#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP) \
+ for (size_t bucket__ = 0; \
+ INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \
+ (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL);)
+
static inline struct hmap_node *hmap_first(const struct hmap *);
static inline struct hmap_node *hmap_next(const struct hmap *,
const struct hmap_node *);
static void
id_pool_uninit(struct id_pool *pool)
{
- struct id_node *id_node, *next;
+ struct id_node *id_node;
- HMAP_FOR_EACH_SAFE(id_node, next, node, &pool->map) {
- hmap_remove(&pool->map, &id_node->node);
+ HMAP_FOR_EACH_POP(id_node, node, &pool->map) {
free(id_node);
}
lswitch_destroy(struct lswitch *sw)
{
if (sw) {
- struct lswitch_port *node, *next;
+ struct lswitch_port *node;
rconn_destroy(sw->rconn);
- HMAP_FOR_EACH_SAFE (node, next, hmap_node, &sw->queue_numbers) {
- hmap_remove(&sw->queue_numbers, &node->hmap_node);
+ HMAP_FOR_EACH_POP (node, hmap_node, &sw->queue_numbers) {
free(node);
}
shash_destroy(&sw->queue_names);
htb_tc_destroy(struct tc *tc)
{
struct htb *htb = CONTAINER_OF(tc, struct htb, tc);
- struct htb_class *hc, *next;
+ struct htb_class *hc;
- HMAP_FOR_EACH_SAFE (hc, next, tc_queue.hmap_node, &htb->tc.queues) {
- hmap_remove(&htb->tc.queues, &hc->tc_queue.hmap_node);
+ HMAP_FOR_EACH_POP (hc, tc_queue.hmap_node, &htb->tc.queues) {
free(hc);
}
tc_destroy(tc);
void
odp_portno_names_destroy(struct hmap *portno_names)
{
- struct odp_portno_names *odp_portno_names, *odp_portno_names_next;
- HMAP_FOR_EACH_SAFE (odp_portno_names, odp_portno_names_next,
- hmap_node, portno_names) {
- hmap_remove(portno_names, &odp_portno_names->hmap_node);
+ struct odp_portno_names *odp_portno_names;
+
+ HMAP_FOR_EACH_POP (odp_portno_names, hmap_node, portno_names) {
free(odp_portno_names->name);
free(odp_portno_names);
}
void
bond_unref(struct bond *bond)
{
- struct bond_slave *slave, *next_slave;
- struct bond_pr_rule_op *pr_op, *next_op;
+ struct bond_pr_rule_op *pr_op;
+ struct bond_slave *slave;
if (!bond || ovs_refcount_unref_relaxed(&bond->ref_cnt) != 1) {
return;
hmap_remove(all_bonds, &bond->hmap_node);
ovs_rwlock_unlock(&rwlock);
- HMAP_FOR_EACH_SAFE (slave, next_slave, hmap_node, &bond->slaves) {
- hmap_remove(&bond->slaves, &slave->hmap_node);
+ HMAP_FOR_EACH_POP (slave, hmap_node, &bond->slaves) {
/* Client owns 'slave->netdev'. */
free(slave->name);
free(slave);
free(bond->hash);
free(bond->name);
- HMAP_FOR_EACH_SAFE(pr_op, next_op, hmap_node, &bond->pr_rule_ops) {
- hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
+ HMAP_FOR_EACH_POP (pr_op, hmap_node, &bond->pr_rule_ops) {
free(pr_op);
}
hmap_destroy(&bond->pr_rule_ops);
in_band_destroy(struct in_band *ib)
{
if (ib) {
- struct in_band_rule *rule, *next;
+ struct in_band_rule *rule;
- HMAP_FOR_EACH_SAFE (rule, next, hmap_node, &ib->rules) {
- hmap_remove(&ib->rules, &rule->hmap_node);
+ HMAP_FOR_EACH_POP (rule, hmap_node, &ib->rules) {
free(rule);
}
hmap_destroy(&ib->rules);
static void
dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQUIRES(mutex)
{
- struct dpif_ipfix_flow_exporter_map_node *exp_node, *exp_next;
+ struct dpif_ipfix_flow_exporter_map_node *exp_node;
struct dpif_ipfix_port *dip, *next;
dpif_ipfix_bridge_exporter_clear(&di->bridge_exporter);
- HMAP_FOR_EACH_SAFE (exp_node, exp_next, node, &di->flow_exporter_map) {
- hmap_remove(&di->flow_exporter_map, &exp_node->node);
+ HMAP_FOR_EACH_POP (exp_node, node, &di->flow_exporter_map) {
dpif_ipfix_flow_exporter_destroy(&exp_node->exporter);
free(exp_node);
}
static void
clear_skb_priorities(struct xport *xport)
{
- struct skb_priority_to_dscp *pdscp, *next;
+ struct skb_priority_to_dscp *pdscp;
- HMAP_FOR_EACH_SAFE (pdscp, next, hmap_node, &xport->skb_priorities) {
- hmap_remove(&xport->skb_priorities, &pdscp->hmap_node);
+ HMAP_FOR_EACH_POP (pdscp, hmap_node, &xport->skb_priorities) {
free(pdscp);
}
}
OVS_EXCLUDED(ofproto_mutex)
{
struct ofport *ofport, *next_ofport;
- struct ofport_usage *usage, *next_usage;
+ struct ofport_usage *usage;
if (!p) {
return;
ofport_destroy(ofport, del);
}
- HMAP_FOR_EACH_SAFE (usage, next_usage, hmap_node, &p->ofport_usage) {
- hmap_remove(&p->ofport_usage, &usage->hmap_node);
+ HMAP_FOR_EACH_POP (usage, hmap_node, &p->ofport_usage) {
free(usage);
}
pinsched_destroy(struct pinsched *ps)
{
if (ps) {
- struct pinqueue *q, *next;
+ struct pinqueue *q;
- HMAP_FOR_EACH_SAFE (q, next, node, &ps->queues) {
- hmap_remove(&ps->queues, &q->node);
+ HMAP_FOR_EACH_POP (q, node, &ps->queues) {
ofpbuf_list_delete(&q->packets);
free(q);
}
}
/* Delete any existing OVN tunnels that were not still around. */
- struct port_hash_node *hash_node, *next_hash_node;
- HMAP_FOR_EACH_SAFE (hash_node, next_hash_node, node, &tc.tunnel_hmap) {
- hmap_remove(&tc.tunnel_hmap, &hash_node->node);
+ struct port_hash_node *hash_node;
+ HMAP_FOR_EACH_POP (hash_node, node, &tc.tunnel_hmap) {
bridge_delete_port(hash_node->bridge, hash_node->port);
free(hash_node);
}
/* Destroy all of the "struct lport"s.
*
* We don't have to remove the node from both indexes. */
- struct lport *port, *next;
- HMAP_FOR_EACH_SAFE (port, next, name_node, &lports->by_name) {
- hmap_remove(&lports->by_name, &port->name_node);
+ struct lport *port;
+ HMAP_FOR_EACH_POP (port, name_node, &lports->by_name) {
free(port);
}
static void
ovn_flow_table_clear(struct hmap *flow_table)
{
- struct ovn_flow *f, *next;
- HMAP_FOR_EACH_SAFE (f, next, hmap_node, flow_table) {
- hmap_remove(flow_table, &f->hmap_node);
+ struct ovn_flow *f;
+ HMAP_FOR_EACH_POP (f, hmap_node, flow_table) {
ovn_flow_destroy(f);
}
}
ofpbuf_uninit(&ofpacts);
simap_destroy(&localvif_to_ofport);
- struct chassis_tunnel *tun_next;
- HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) {
- hmap_remove(&tunnels, &tun->hmap_node);
+ HMAP_FOR_EACH_POP (tun, hmap_node, &tunnels) {
free(tun);
}
hmap_destroy(&tunnels);
static void
flush_put_arps(void)
{
- struct put_arp *pa, *next;
- HMAP_FOR_EACH_SAFE (pa, next, hmap_node, &put_arps) {
- hmap_remove(&put_arps, &pa->hmap_node);
+ struct put_arp *pa;
+ HMAP_FOR_EACH_POP (pa, hmap_node, &put_arps) {
free(pa);
}
}
void
expr_matches_destroy(struct hmap *matches)
{
- struct expr_match *m, *n;
+ struct expr_match *m;
- HMAP_FOR_EACH_SAFE (m, n, hmap_node, matches) {
- hmap_remove(matches, &m->hmap_node);
+ HMAP_FOR_EACH_POP (m, hmap_node, matches) {
free(m->conjunctions);
free(m);
}
static void
destroy_tnlids(struct hmap *tnlids)
{
- struct tnlid_node *node, *next;
- HMAP_FOR_EACH_SAFE (node, next, hmap_node, tnlids) {
- hmap_remove(tnlids, &node->hmap_node);
+ struct tnlid_node *node;
+ HMAP_FOR_EACH_POP (node, hmap_node, tnlids) {
free(node);
}
hmap_destroy(tnlids);
struct lport_hash_node {
struct hmap_node node;
const struct nbrec_logical_port *nb;
- } *hash_node, *hash_node_next;
+ } *hash_node;
hmap_init(&lports_hmap);
}
}
- HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
- hmap_remove(&lports_hmap, &hash_node->node);
+ HMAP_FOR_EACH_POP(hash_node, node, &lports_hmap) {
free(hash_node);
}
hmap_destroy(&lports_hmap);
static void
ovsdb_monitor_json_cache_flush(struct ovsdb_monitor *dbmon)
{
- struct ovsdb_monitor_json_cache_node *node, *next;
+ struct ovsdb_monitor_json_cache_node *node;
- HMAP_FOR_EACH_SAFE(node, next, hmap_node, &dbmon->json_cache) {
- hmap_remove(&dbmon->json_cache, &node->hmap_node);
+ HMAP_FOR_EACH_POP(node, hmap_node, &dbmon->json_cache) {
json_destroy(node->json);
free(node);
}
void
ovsdb_row_hash_destroy(struct ovsdb_row_hash *rh, bool destroy_rows)
{
- struct ovsdb_row_hash_node *node, *next;
+ struct ovsdb_row_hash_node *node;
- HMAP_FOR_EACH_SAFE (node, next, hmap_node, &rh->rows) {
- hmap_remove(&rh->rows, &node->hmap_node);
+ HMAP_FOR_EACH_POP (node, hmap_node, &rh->rows) {
if (destroy_rows) {
ovsdb_row_destroy(CONST_CAST(struct ovsdb_row *, node->row));
}
AT_SETUP([test hash map])
AT_KEYWORDS([hmap])
-AT_CHECK([ovstest test-hmap], [0], [.........
+AT_CHECK([ovstest test-hmap], [0], [............
])
AT_CLEANUP
}
}
+/* Tests that HMAP_FOR_EACH_POP removes every element of a hmap. */
+static void
+test_hmap_for_each_pop(hash_func *hash)
+{
+ enum { MAX_ELEMS = 10 };
+ size_t n;
+
+ for (n = 0; n <= MAX_ELEMS; n++) {
+ struct element elements[MAX_ELEMS];
+ int values[MAX_ELEMS];
+ struct hmap hmap;
+ struct element *e;
+ size_t n_remaining, i;
+
+ make_hmap(&hmap, elements, values, n, hash);
+
+ i = 0;
+ n_remaining = n;
+ HMAP_FOR_EACH_POP (e, node, &hmap) {
+ size_t j;
+
+ assert(i < n);
+
+ for (j = 0; ; j++) {
+ assert(j < n_remaining);
+ if (values[j] == e->value) {
+ values[j] = values[--n_remaining];
+ break;
+ }
+ }
+ /* Trash the element memory (including the hmap node) */
+ memset(e, 0, sizeof *e);
+ check_hmap(&hmap, values, n_remaining, hash);
+ i++;
+ }
+ assert(i == n);
+
+ hmap_destroy(&hmap);
+ }
+}
+
static void
run_test(void (*function)(hash_func *))
{
run_test(test_hmap_insert_delete);
run_test(test_hmap_for_each_safe);
run_test(test_hmap_reserve_shrink);
+ run_test(test_hmap_for_each_pop);
printf("\n");
}