Added new function fixed_queue_flush() and the unit test

Change-Id: Ic90e3ffdcaea9573b135bd26ef102a1740fb2d3d
diff --git a/osi/include/fixed_queue.h b/osi/include/fixed_queue.h
index a125336..54f0093 100644
--- a/osi/include/fixed_queue.h
+++ b/osi/include/fixed_queue.h
@@ -40,10 +40,18 @@
 // the returned queue with |fixed_queue_free|.
 fixed_queue_t *fixed_queue_new(size_t capacity);
 
+// Frees a queue and (optionally) the enqueued elements.
+// |queue| is the queue to free. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
 // Freeing a queue that is currently in use (i.e. has waiters
 // blocked on it) results in undefined behaviour.
 void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb);
 
+// Flushes a queue and (optionally) frees the enqueued elements.
+// |queue| is the queue to flush. If the |free_cb| callback is not null,
+// it is called on each queue element to free it.
+void fixed_queue_flush(fixed_queue_t *queue, fixed_queue_free_cb free_cb);
+
 // Returns a value indicating whether the given |queue| is empty. If |queue|
 // is NULL, the return value is true.
 bool fixed_queue_is_empty(fixed_queue_t *queue);
diff --git a/osi/src/fixed_queue.c b/osi/src/fixed_queue.c
index be4f292..7f4f0ab 100644
--- a/osi/src/fixed_queue.c
+++ b/osi/src/fixed_queue.c
@@ -83,6 +83,18 @@
   osi_free(queue);
 }
 
+void fixed_queue_flush(fixed_queue_t *queue, fixed_queue_free_cb free_cb) {
+  if (!queue)
+    return;
+
+  while (!fixed_queue_is_empty(queue)) {
+    void *data = fixed_queue_try_dequeue(queue);
+    if (free_cb != NULL) {
+      free_cb(data);
+    }
+  }
+}
+
 bool fixed_queue_is_empty(fixed_queue_t *queue) {
   if (queue == NULL)
     return true;
diff --git a/osi/test/fixed_queue_test.cc b/osi/test/fixed_queue_test.cc
index da7cf5c..675bd39 100644
--- a/osi/test/fixed_queue_test.cc
+++ b/osi/test/fixed_queue_test.cc
@@ -19,6 +19,8 @@
 static const char *DUMMY_DATA_STRING3 = "Dummy data string3";
 static future_t *received_message_future = NULL;
 
+static int test_queue_entry_free_counter = 0;
+
 // Test whether a file descriptor |fd| is readable.
 // Return true if the file descriptor is readable, otherwise false.
 static bool is_fd_readable(int fd)
@@ -46,6 +48,14 @@
   future_ready(received_message_future, msg);
 }
 
+static void
+test_queue_entry_free_cb(void *data)
+{
+  // Don't free the data, because we are testing only whether the callback
+  // is called.
+  test_queue_entry_free_counter++;
+}
+
 class FixedQueueTest : public AllocationTestHarness {};
 
 TEST_F(FixedQueueTest, test_fixed_queue_new_free) {
@@ -76,6 +86,48 @@
   fixed_queue_free(NULL, osi_free);
 }
 
+TEST_F(FixedQueueTest, test_fixed_queue_flush) {
+  fixed_queue_t *queue;
+
+  // Test a corner case: queue of size 0 and no callback to free entries
+  queue = fixed_queue_new(0);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_flush(queue, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a corner case: queue of size 0 and a callback to free entries
+  queue = fixed_queue_new(0);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_flush(queue, osi_free);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a queue of some size and no callback to free entries
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING1);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING2);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING3);
+  EXPECT_FALSE(fixed_queue_is_empty(queue));
+  fixed_queue_flush(queue, NULL);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+
+  // Test a queue of some size and a callback to free entries
+  test_queue_entry_free_counter = 0;
+  queue = fixed_queue_new(TEST_QUEUE_SIZE);
+  EXPECT_TRUE(queue != NULL);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING1);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING2);
+  fixed_queue_try_enqueue(queue, (void *)DUMMY_DATA_STRING3);
+  EXPECT_FALSE(fixed_queue_is_empty(queue));
+  fixed_queue_flush(queue, test_queue_entry_free_cb);
+  EXPECT_TRUE(test_queue_entry_free_counter == 3);
+  EXPECT_TRUE(fixed_queue_is_empty(queue));
+  fixed_queue_free(queue, osi_free);
+}
+
 TEST_F(FixedQueueTest, test_fixed_queue_is_empty) {
   fixed_queue_t *queue;