#ifndef _BIRD_HASH_H_
#define _BIRD_HASH_H_
-#define HASH(type) struct { type **data; uint count, order; }
+#define HASH(type) struct { type **data; uint count, order; char* is_in_walk; }
#define HASH_TYPE(v) typeof(** (v).data)
#define HASH_SIZE(v) (1U << (v).order)
(v).count = 0; \
(v).order = (init_order); \
(v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data)); \
+ (v).is_in_walk = mb_allocz(pool, sizeof(char)); \
+ *(v).is_in_walk = 0; \
})
#define HASH_FREE(v) \
#define HASH_INSERT(v,id,node) \
({ \
+ if (*(v).is_in_walk) \
+ bug("HASH_INSERT: Attempt to insert in HASH_WALK"); \
u32 _h = HASH_FN(v, id, id##_KEY((node))); \
HASH_TYPE(v) **_nn = (v).data + _h; \
id##_NEXT(node) = *_nn; \
#define HASH_DO_REMOVE(v,id,_nn) \
({ \
+ if (*(v).is_in_walk) \
+ bug("HASH_DELETE: Attempt to remove in HASH_WALK"); \
*_nn = id##_NEXT((*_nn)); \
(v).count--; \
})
#define HASH_WALK(v,next,n) \
do { \
HASH_TYPE(v) *n; \
+ *(v).is_in_walk = 1; \
uint _i; \
uint _s = HASH_SIZE(v); \
for (_i = 0; _i < _s; _i++) \
for (n = (v).data[_i]; n; n = n->next)
-#define HASH_WALK_END } while (0)
+#define HASH_WALK_END(v) *(v).is_in_walk = 0; } while (0)
#define HASH_WALK_DELSAFE(v,next,n) \
{
check[n->key]++;
}
- HASH_WALK_END;
+ HASH_WALK_END(hash);
for (i = 0; i < MAX_NUM; i++)
bt_assert(check[i] == 1);
return 1;
}
+void
+do_walk_delete_error(void)
+{
+ init_hash();
+ fill_hash();
+
+ HASH_WALK(hash, next, n)
+ {
+ HASH_DELETE(hash, TEST, n->key);
+ }
+ HASH_WALK_END(hash);
+}
+
+static int
+t_walk_check_bug(void)
+{
+ return bt_assert_bug(do_walk_delete_error, "HASH_DELETE: Attempt to remove in HASH_WALK");
+}
+
+
int
main(int argc, char *argv[])
{
bt_test_suite(t_walk_delsafe_remove, "HASH_WALK_DELSAFE and HASH_REMOVE");
bt_test_suite(t_walk_delsafe_remove2, "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
bt_test_suite(t_walk_filter, "HASH_WALK_FILTER");
+ bt_test_suite(t_walk_check_bug, "HASH_DO_REMOVE returns error, because called from HASH_WALK");
return bt_exit_value();
}
cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
}
- HASH_WALK_END;
+ HASH_WALK_END(scope->hash);
cli_msg(0, "");
}
mpls_unlink_fec(m, fec);
fec->policy = MPLS_POLICY_NONE;
}
- HASH_WALK_END;
+ HASH_WALK_END(m->label_hash);
/* Remove old unused handles */
rta_free(fec->rta);
fec->rta = NULL;
}
- HASH_WALK_END;
+ HASH_WALK_END(m->rta_hash);
}
/* Free allocated labels */
if (!fec->policy && !fec->handle->label_count)
mpls_free_handle(m->domain, fec->handle);
}
- HASH_WALK_END;
+ HASH_WALK_END(m->label_hash);
if (m->static_handle)
mpls_free_handle(m->domain, m->static_handle);
aggregator_bucket_update(p, b, b->rte->net);
lp_flush(rte_update_pool);
}
- HASH_WALK_END;
+ HASH_WALK_END(p->buckets);
}
HASH_REMOVE(p->buckets, AGGR_BUCK, b);
sl_free(b);
}
- HASH_WALK_END;
+ HASH_WALK_END(p->buckets);
return PS_DOWN;
}
WALK_LIST_FIRST(n, s->request_list)
bfd_submit_request(SKIP_BACK(struct bfd_request, n, n));
}
- HASH_WALK_END;
+ HASH_WALK_END(p->session_hash_id);
}
static struct resclass bfd_request_class;
if (s->ifa->changed)
bfd_reconfigure_session(p, s);
}
- HASH_WALK_END;
+ HASH_WALK_END(p->session_hash_id);
bfd_reconfigure_neighbors(p, new);
bfd_show_session(s, args->verbose);
}
- HASH_WALK_END;
+ HASH_WALK_END(p->session_hash_id);
}