From 93360e1fbd9c08ab7e727a9b1e3d10bb7d6d3ca4 Mon Sep 17 00:00:00 2001
From: Sree Kuchibhotla <sreek@google.com>
Date: Mon, 7 Dec 2015 18:30:08 -0800
Subject: [PATCH] Add test coverage for gpr_refn() function

---
 test/core/support/sync_test.c | 55 ++++++++++++++++++++++-------------
 1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 220b16b60f..6bc5f792e5 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -153,6 +153,7 @@ struct test {
   gpr_int64 counter;
   int thread_count; /* used to allocate thread ids */
   int done;         /* threads not yet completed */
+  int incr_step;    /* how much to increment/decrement refcount each time */
 
   gpr_mu mu; /* protects iterations, counter, thread_count, done */
 
@@ -170,13 +171,14 @@ struct test {
 };
 
 /* Return pointer to a new struct test. */
-static struct test *test_new(int threads, gpr_int64 iterations) {
+static struct test *test_new(int threads, gpr_int64 iterations, int incr_step) {
   struct test *m = gpr_malloc(sizeof(*m));
   m->threads = threads;
   m->iterations = iterations;
   m->counter = 0;
   m->thread_count = 0;
   m->done = threads;
+  m->incr_step = incr_step;
   gpr_mu_init(&m->mu);
   gpr_cv_init(&m->cv);
   gpr_cv_init(&m->done_cv);
@@ -238,9 +240,12 @@ static void mark_thread_done(struct test *m) {
 
 /* Test several threads running (*body)(struct test *m) for increasing settings
    of m->iterations, until about timeout_s to 2*timeout_s seconds have elapsed.
-   If extra!=NULL, run (*extra)(m) in an additional thread.  */
+   If extra!=NULL, run (*extra)(m) in an additional thread.
+   incr_step controls by how much m->refcount should be incremented/decremented
+   (if at all) each time in the tests.
+   */
 static void test(const char *name, void (*body)(void *m),
-                 void (*extra)(void *m), int timeout_s) {
+                 void (*extra)(void *m), int timeout_s, int incr_step) {
   gpr_int64 iterations = 1024;
   struct test *m;
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
@@ -251,7 +256,7 @@ static void test(const char *name, void (*body)(void *m),
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
     fprintf(stderr, " %ld", (long)iterations);
-    m = test_new(10, iterations);
+    m = test_new(10, iterations, incr_step);
     if (extra != NULL) {
       gpr_thd_id id;
       GPR_ASSERT(gpr_thd_new(&id, extra, m, NULL));
@@ -259,7 +264,7 @@ static void test(const char *name, void (*body)(void *m),
     }
     test_create_threads(m, body);
     test_wait(m);
-    if (m->counter != m->threads * m->iterations) {
+    if (m->counter != m->threads * m->iterations * m->incr_step) {
       fprintf(stderr, "counter %ld  threads %d  iterations %ld\n",
               (long)m->counter, m->threads, (long)m->iterations);
       GPR_ASSERT(0);
@@ -406,14 +411,18 @@ static void statsinc(void *v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Increment m->refcount m->iterations times, decrement m->thread_refcount
-   once, and if it reaches zero, set m->event to (void*)1; then mark thread as
-   done.  */
+/* Increment m->refcount by m->incr_step for m->iterations times. Decrement
+   m->thread_refcount once, and if it reaches zero, set m->event to (void*)1;
+   then mark thread as done.  */
 static void refinc(void *v /*=m*/) {
   struct test *m = v;
   gpr_int64 i;
   for (i = 0; i != m->iterations; i++) {
-    gpr_ref(&m->refcount);
+    if (m->incr_step == 1) {
+      gpr_ref(&m->refcount);
+    } else {
+      gpr_refn(&m->refcount, m->incr_step);
+    }
   }
   if (gpr_unref(&m->thread_refcount)) {
     gpr_event_set(&m->event, (void *)1);
@@ -421,12 +430,13 @@ static void refinc(void *v /*=m*/) {
   mark_thread_done(m);
 }
 
-/* Wait until m->event is set to (void *)1, then decrement m->refcount
-   m->stats_counter m->iterations times, and ensure that the last decrement
-   caused the counter to reach zero, then mark thread as done.  */
+
+/* Wait until m->event is set to (void *)1, then decrement m->refcount by 1
+   (m->threads * m->iterations * m->incr_step) times, and ensure that the last
+   decrement caused the counter to reach zero, then mark thread as done.  */
 static void refcheck(void *v /*=m*/) {
   struct test *m = v;
-  gpr_int64 n = m->iterations * m->threads;
+  gpr_int64 n = m->iterations * m->threads * m->incr_step;
   gpr_int64 i;
   GPR_ASSERT(gpr_event_wait(&m->event, gpr_inf_future(GPR_CLOCK_REALTIME)) ==
              (void *)1);
@@ -444,13 +454,16 @@ static void refcheck(void *v /*=m*/) {
 
 int main(int argc, char *argv[]) {
   grpc_test_init(argc, argv);
-  test("mutex", &inc, NULL, 1);
-  test("mutex try", &inctry, NULL, 1);
-  test("cv", &inc_by_turns, NULL, 1);
-  test("timedcv", &inc_with_1ms_delay, NULL, 1);
-  test("queue", &many_producers, &consumer, 10);
-  test("stats_counter", &statsinc, NULL, 1);
-  test("refcount", &refinc, &refcheck, 1);
-  test("timedevent", &inc_with_1ms_delay_event, NULL, 1);
+  test("mutex", &inc, NULL, 1, 1);
+  test("mutex try", &inctry, NULL, 1, 1);
+  test("cv", &inc_by_turns, NULL, 1, 1);
+  test("timedcv", &inc_with_1ms_delay, NULL, 1, 1);
+  test("queue", &many_producers, &consumer, 10, 1);
+  test("stats_counter", &statsinc, NULL, 1, 1);
+  test("refcount by 1", &refinc, &refcheck, 1, 1);
+  test("refcount by 3", &refinc, &refcheck, 1, 3); /* incr_step of 3 is an
+                                                      arbitrary choice. Any
+                                                      number > 1 is okay here */
+  test("timedevent", &inc_with_1ms_delay_event, NULL, 1, 1);
   return 0;
 }
-- 
GitLab