diff --git a/docs/modules/cc_ring_array.rst b/docs/modules/cc_ring_array.rst index 36b006df0..1b8b36654 100644 --- a/docs/modules/cc_ring_array.rst +++ b/docs/modules/cc_ring_array.rst @@ -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 #include #include #include #include #include + #include - 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 */ diff --git a/include/cc_ring_array.h b/include/cc_ring_array.h index 7aab8acd3..9caf1cd26 100644 --- a/include/cc_ring_array.h +++ b/include/cc_ring_array.h @@ -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); /*********************** @@ -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); diff --git a/src/cc_ring_array.c b/src/cc_ring_array.c index c52e0b879..0d423d931 100644 --- a/src/cc_ring_array.c +++ b/src/cc_ring_array.c @@ -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 @@ -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); diff --git a/test/ring_array/check_ring_array.c b/test/ring_array/check_ring_array.c index 64d6d576e..f02f10bfc 100644 --- a/test/ring_array/check_ring_array.c +++ b/test/ring_array/check_ring_array.c @@ -2,9 +2,12 @@ #include +#include #include #include +#include + #define SUITE_NAME "ring_array" #define DEBUG_LOG SUITE_NAME ".log" @@ -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 */ @@ -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; }