Skip to content
This repository has been archived by the owner on Oct 24, 2023. It is now read-only.

Commit

Permalink
update ring_array docs for new API, add multi threaded unit test for …
Browse files Browse the repository at this point in the history
…ring_array (twitter#166)
  • Loading branch information
kevyang authored Jul 20, 2018
1 parent 67ce9c2 commit 441934b
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 29 deletions.
85 changes: 60 additions & 25 deletions docs/modules/cc_ring_array.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,52 +50,87 @@ These functions are used to push/pop elements in the ``ring_array``. To push an

To pop an element from the ``ring_array``, call ``ring_array_pop()`` with ``elem`` being a pointer to the memory location for where the element should be popped to, and ``arr`` being the ``ring_array`` being popped from. ``ring_array_pop()`` returns ``CC_OK`` if the element was successfully popped, and ``CC_ERROR`` if not successful (i.e. the ``ring_array`` is empty).

State
^^^^^
..code-block:: C
bool ring_array_full(const struct ring_array *arr);
bool ring_array_empty(const struct ring_array *arr);
These functions tell the caller about the state of the ``ring_array``, specifically whether it is full or empty. In a producer/consumer model, ``ring_array_full()`` is a producer facing API, and ``ring_array_empty()`` is a consumer facing API. This is so that the producer can check whether or not the ``ring_array`` is full before pushing more elements into the array; likewise, the consumer can check whether or not the ``ring_array`` is empty before attempting to pop.

Flush
^^^^^
..code-block:: C
void ring_array_flush(struct ring_array *arr);
This function is a consumer facing API that discards everything in the ``ring_array``.


Examples
--------

Hello World! with ccommon ``ring_array``:
Multi threaded Hello World! with ccommon ``ring_array``:

.. code-block:: c
#include <cc_bstring.h>
#include <cc_define.h>
#include <cc_ring_array.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int
main(int argc, char **argv)
{
struct ring_array *arr;
char c, *msg = "Hello world!\n";
int i, msg_len = strlen(msg);
rstatus_i status;
/* Create ring_array */
arr = ring_array_create(sizeof(char), 100);
#define MESSAGE "Hello world!\n"
/* Push message into ring_array */
for (i = 0; i < msg_len; ++i) {
status = ring_array_push(msg + i, arr);
struct msg_arg {
struct ring_array *arr;
struct bstring *msg;
};
if (status != CC_OK) {
printf("Could not push message!\n");
exit(1);
static void *
push_message(void *arg)
{
/* producer thread */
struct ring_array *arr = ((struct msg_arg *)arg)->arr;
struct bstring *msg = ((struct msg_arg *)arg)->msg;
for (i = 0; i < msg->len;) {
/* if there is space in the ring array, push next char in msg */
if (!ring_array_full(arr)) {
ring_array_push(&(msg->data[i++]), arr);
}
}
/* Pop chars stored in arr and print them */
for (i = 0; i < msg_len; ++i) {
status = ring_array_pop(&c, arr);
return NULL;
}
if (status != CC_OK) {
printf("Could not pop entire message!");
exit(1);
int
main(int argc, char **argv)
{
struct ring_array *arr;
pthread_t producer = NULL;
struct bstring msg = { sizeof(MESSAGE), MESSAGE };
struct msg_arg args;
arr = ring_array_create(sizeof(char), 5);
/* share array with producer thread */
args.arr = arr;
args.msg = &msg;
/* create producer thread */
pthread_create(&producer, NULL, &push_message, &args);
/* consume from arr */
for (i = 0; i < msg.len;) {
if (!ring_array_empty(arr)) {
char c;
ring_array_pop(&c, arr);
printf("%c", c);
++i
}
printf("%c", c);
}
/* Destroy ring_array */
Expand Down
4 changes: 2 additions & 2 deletions include/cc_ring_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct ring_array {
rstatus_i ring_array_push(const void *elem, struct ring_array *arr);

/* check if array is full */
bool ring_array_full(struct ring_array *arr);
bool ring_array_full(const struct ring_array *arr);


/***********************
Expand All @@ -69,7 +69,7 @@ bool ring_array_full(struct ring_array *arr);
rstatus_i ring_array_pop(void *elem, struct ring_array *arr);

/* check if array is empty */
bool ring_array_empty(struct ring_array *arr);
bool ring_array_empty(const struct ring_array *arr);

/* flush contents of ring array */
void ring_array_flush(struct ring_array *arr);
Expand Down
4 changes: 2 additions & 2 deletions src/cc_ring_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ring_array_push(const void *elem, struct ring_array *arr)
}

bool
ring_array_full(struct ring_array *arr)
ring_array_full(const struct ring_array *arr)
{
/*
* Take snapshot of rpos, since another thread might be popping. Note: other
Expand Down Expand Up @@ -134,7 +134,7 @@ ring_array_pop(void *elem, struct ring_array *arr)
}

bool
ring_array_empty(struct ring_array *arr)
ring_array_empty(const struct ring_array *arr)
{
/* take snapshot of wpos, since another thread might be pushing */
uint32_t wpos = __atomic_load_n(&(arr->wpos), __ATOMIC_RELAXED);
Expand Down
62 changes: 62 additions & 0 deletions test/ring_array/check_ring_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

#include <check.h>

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

#include <unistd.h>

#define SUITE_NAME "ring_array"
#define DEBUG_LOG SUITE_NAME ".log"

Expand Down Expand Up @@ -155,6 +158,64 @@ START_TEST(test_flush)
}
END_TEST

/*
* Threading test
*/
struct test_ring_array_arg {
uint32_t n;
struct ring_array *arr;
};

static void *
test_produce(void *arg)
{
uint32_t i, n = ((struct test_ring_array_arg *)arg)->n;
struct ring_array *arr = ((struct test_ring_array_arg *)arg)->arr;

for (i = 0; i < n;) {
if (!ring_array_full(arr)) {
ring_array_push(&i, arr);
++i;
}
}
return NULL;
}

START_TEST(test_thread)
{
#define ELEM_SIZE sizeof(uint32_t)
#define CAP 1000
#define NUM_REPS 5000
struct ring_array *arr = NULL;
pthread_t producer = NULL;
struct test_ring_array_arg arg;
uint32_t i;

arr = ring_array_create(ELEM_SIZE, CAP);
ck_assert_ptr_ne(arr, NULL);

arg.n = NUM_REPS;
arg.arr = arr;

/* create producer thread */
ck_assert_int_eq(pthread_create(&producer, NULL, &test_produce, &arg), 0);

/* parent is consumer thread */
for (i = 0; i < NUM_REPS;) {
if (!ring_array_empty(arr)) {
uint32_t val;
ck_assert_int_eq(ring_array_pop(&val, arr), CC_OK);
ck_assert_int_eq(val, i++);
}
}

ring_array_destroy(&arr);
#undef ELEM_SIZE
#undef CAP
#undef NUM_REPS
}
END_TEST

/*
* test suite
*/
Expand All @@ -173,6 +234,7 @@ ring_array_suite(void)
tcase_add_test(tc_ring_array, test_push_full);
tcase_add_test(tc_ring_array, test_push_pop_many);
tcase_add_test(tc_ring_array, test_flush);
tcase_add_test(tc_ring_array, test_thread);

return s;
}
Expand Down

0 comments on commit 441934b

Please sign in to comment.