+static int
+stale_cb (BVT (clib_bihash_kv) * kv, void *ctx)
+{
+ test_main_t *tm = ctx;
+
+ tm->noverwritten++;
+
+ return 1;
+}
+
+static clib_error_t *
+test_bihash_stale_overwrite (test_main_t * tm)
+{
+ BVT (clib_bihash) * h;
+ BVT (clib_bihash_kv) kv;
+ int i;
+ tm->noverwritten = 0;
+
+ h = &tm->hash;
+
+#if BIHASH_32_64_SVM
+ BV (clib_bihash_master_init_svm) (h, "test", tm->nbuckets,
+ 0x30000000 /* base_addr */ ,
+ tm->hash_memory_size);
+#else
+ BV (clib_bihash_init) (h, "test", tm->nbuckets, tm->hash_memory_size);
+#endif
+
+ fformat (stdout, "Add %d items to %d buckets\n", tm->nitems, tm->nbuckets);
+
+ for (i = 0; i < tm->nitems; i++)
+ {
+ kv.key = i;
+ kv.value = 1;
+
+ BV (clib_bihash_add_or_overwrite_stale) (h, &kv, stale_cb, tm);
+ }
+
+ fformat (stdout, "%d items overwritten\n", tm->noverwritten);
+ fformat (stdout, "%U", BV (format_bihash), h, 0);
+
+ return 0;
+}
+
+void *
+test_bihash_thread_fn (void *arg)
+{
+ BVT (clib_bihash) * h;
+ BVT (clib_bihash_kv) kv;
+ test_main_t *tm = &test_main;
+
+ int i, j;
+
+ u32 my_thread_index = (u32) (u64) arg;
+ __os_thread_index = my_thread_index;
+ clib_mem_set_per_cpu_heap (tm->global_heap);
+
+ while (tm->thread_barrier)
+ ;
+
+ h = &tm->hash;
+
+ for (i = 0; i < tm->ncycles; i++)
+ {
+ for (j = 0; j < tm->nitems; j++)
+ {
+ kv.key = ((u64) my_thread_index << 32) | (u64) j;
+ kv.value = ((u64) my_thread_index << 32) | (u64) j;
+ (void) __atomic_add_fetch (&tm->sequence_number, 1,
+ __ATOMIC_ACQUIRE);
+ BV (clib_bihash_add_del) (h, &kv, 1 /* is_add */ );
+ }
+ for (j = 0; j < tm->nitems; j++)
+ {
+ kv.key = ((u64) my_thread_index << 32) | (u64) j;
+ kv.value = ((u64) my_thread_index << 32) | (u64) j;
+ (void) __atomic_add_fetch (&tm->sequence_number, 1,
+ __ATOMIC_ACQUIRE);
+ BV (clib_bihash_add_del) (h, &kv, 0 /* is_add */ );
+ }
+ }
+
+ (void) __atomic_sub_fetch (&tm->threads_running, 1, __ATOMIC_ACQUIRE);
+ while (1)
+ {
+ struct timespec ts, tsrem;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ }
+ return (0); /* not so much */
+}
+
+static clib_error_t *
+test_bihash_threads (test_main_t * tm)
+{
+ int i;
+ pthread_t handle;
+ BVT (clib_bihash) * h;
+ int rv;
+
+ h = &tm->hash;
+
+#if BIHASH_32_64_SVM
+ BV (clib_bihash_master_init_svm) (h, "test", tm->nbuckets,
+ 0x30000000 /* base_addr */ ,
+ tm->hash_memory_size);
+#else
+ BV (clib_bihash_init) (h, "test", tm->nbuckets, tm->hash_memory_size);
+#endif
+
+ tm->thread_barrier = 1;
+
+ /* Start the worker threads */
+ for (i = 0; i < tm->nthreads; i++)
+ {
+ rv = pthread_create (&handle, NULL, test_bihash_thread_fn,
+ (void *) (u64) i);
+ if (rv)
+ {
+ clib_unix_warning ("pthread_create returned %d", rv);
+ }
+ }
+ tm->threads_running = i;
+ tm->sequence_number = 0;
+ CLIB_MEMORY_BARRIER ();
+
+ /* start the workers */
+ tm->thread_barrier = 0;
+
+ while (tm->threads_running)
+ {
+ struct timespec ts, tsrem;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 20 * 1000 * 1000; /* sleep for 20ms at a time */
+
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ }
+
+ return 0;
+}
+
+