From 925c6af8f19e8bc28068bd5ee0fd25480d01440c Mon Sep 17 00:00:00 2001 From: Konstantin Osipov <kostja@tarantool.org> Date: Wed, 9 Sep 2015 21:51:07 +0300 Subject: [PATCH] ipc: add a simple unit test Correct return value of ipc_channel_put(), since it may return an error if the channel is closed. Make get/put functions inline. Remove a public declaration for ipc_channel_is_readonly() (towards removing the concept of readonly altogether). --- src/ipc.cc | 16 ++----- src/ipc.h | 78 +++++++++++++++++--------------- test/unit/CMakeLists.txt | 5 ++- test/unit/ipc.cc | 88 ++++++++++++++++++++++++++----------- test/unit/ipc.result | 25 ++++++++++- test/unit/ipc_stress.cc | 55 +++++++++++++++++++++++ test/unit/ipc_stress.result | 3 ++ 7 files changed, 194 insertions(+), 76 deletions(-) create mode 100644 test/unit/ipc_stress.cc create mode 100644 test/unit/ipc_stress.result diff --git a/src/ipc.cc b/src/ipc.cc index 89e23dfb33..5b253111d1 100644 --- a/src/ipc.cc +++ b/src/ipc.cc @@ -172,12 +172,6 @@ ipc_channel_get_timeout(struct ipc_channel *ch, ev_tstamp timeout) return res; } -void * -ipc_channel_get(struct ipc_channel *ch) -{ - return ipc_channel_get_timeout(ch, TIMEOUT_INFINITY); -} - static void ipc_channel_close_waiter(struct ipc_channel *ch, struct fiber *f) { @@ -217,13 +211,15 @@ ipc_channel_close(struct ipc_channel *ch) { if (ch->closed) return; - assert(ch->readonly); + if (!ch->readonly) + ipc_channel_shutdown(ch); assert(ch->count == 0); assert(rlist_empty(&ch->readers)); assert(rlist_empty(&ch->writers)); assert(ch->bcast == NULL); ch->closed = true; } + int ipc_channel_put_timeout(struct ipc_channel *ch, void *data, ev_tstamp timeout) @@ -291,12 +287,6 @@ ipc_channel_put_timeout(struct ipc_channel *ch, void *data, return res; } -void -ipc_channel_put(struct ipc_channel *ch, void *data) -{ - ipc_channel_put_timeout(ch, data, TIMEOUT_INFINITY); -} - int ipc_channel_broadcast(struct ipc_channel *ch, void *data) { diff --git a/src/ipc.h b/src/ipc.h index 39bd4c4c0e..312d51c8bc 100644 --- a/src/ipc.h +++ b/src/ipc.h @@ -39,10 +39,19 @@ */ struct ipc_channel { - struct rlist readers, writers; + /** + * Readers blocked waiting for messages while the channel + * is empty. + */ + struct rlist readers; + /** + * Writers blocked waiting for empty space while + * the channel is full. + */ + struct rlist writers; struct fiber *bcast; /* broadcast waiter */ struct fiber *close; /* close waiter */ - bool readonly; /* channel is for read only */ + bool readonly; /* channel is read only */ bool closed; /* channel is closed */ unsigned size; unsigned beg; @@ -89,30 +98,6 @@ ipc_channel_new(unsigned size); void ipc_channel_delete(struct ipc_channel *ch); -/** - * @brief Put data into a channel. - * @detail Yield current fiber if the channel is full. - * @param channel - * @param data - * @code - * ipc_channel_put(ch, "message"); - * @endcode - */ -void -ipc_channel_put(struct ipc_channel *ch, void *data); - -/** - * @brief Get data from a channel. - * @detail Yield current fiber if the channel is empty. - * @param channel - * @return data that was put into channel by ipc_channel_put - * @code - * char *msg = ipc_channel_get(ch); - * @endcode - */ -void * -ipc_channel_get(struct ipc_channel *ch); - /** * @brief Wake up all fibers that sleep in ipc_channel_get and * send a message to them. @@ -173,6 +158,22 @@ int ipc_channel_put_timeout(struct ipc_channel *ch, void *data, ev_tstamp timeout); +/** + * @brief Put data into a channel. + * @detail Yield current fiber if the channel is full. + * @param channel + * @param data + * @code + * ipc_channel_put(ch, "message"); + * @endcode + * @return -1 if the channel is closed + */ +static inline int +ipc_channel_put(struct ipc_channel *ch, void *data) +{ + return ipc_channel_put_timeout(ch, data, TIMEOUT_INFINITY); +} + /** * @brief Get data from a channel with a timeout * @param channel @@ -190,6 +191,22 @@ ipc_channel_put_timeout(struct ipc_channel *ch, void *data, void * ipc_channel_get_timeout(struct ipc_channel *ch, ev_tstamp timeout); +/** + * @brief Get data from a channel. + * @detail Yield current fiber if the channel is empty. + * @param channel + * @return data that was put into channel by ipc_channel_put + * @code + * char *msg = ipc_channel_get(ch); + * @endcode + */ +static inline void * +ipc_channel_get(struct ipc_channel *ch) +{ + return ipc_channel_get_timeout(ch, TIMEOUT_INFINITY); +} + + /** * @brief return true if channel has reader fibers that wait data * @param channel @@ -237,15 +254,6 @@ ipc_channel_count(struct ipc_channel *ch) void ipc_channel_shutdown(struct ipc_channel *ch); -/** - * @brief return true if the channel is closed for writing - */ -static inline bool -ipc_channel_is_readonly(struct ipc_channel *ch) -{ - return ch->readonly; -} - /** * @brief close the channel. * @pre ipc_channel_is_readonly(ch) && ipc_channel_is_empty(ch) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index c86a062ad7..f6f356182d 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -72,9 +72,12 @@ target_link_libraries(fiber.test core) add_executable(fiber_stress.test fiber_stress.cc) target_link_libraries(fiber_stress.test core) -add_executable(ipc.test ipc.cc ${CMAKE_SOURCE_DIR}/src/ipc.cc) +add_executable(ipc.test ipc.cc unit.c ${CMAKE_SOURCE_DIR}/src/ipc.cc) target_link_libraries(ipc.test core) +add_executable(ipc_stress.test ipc_stress.cc ${CMAKE_SOURCE_DIR}/src/ipc.cc) +target_link_libraries(ipc_stress.test core) + add_executable(coio.test coio.cc unit.c ${CMAKE_SOURCE_DIR}/src/sio.cc ${CMAKE_SOURCE_DIR}/src/evio.cc diff --git a/test/unit/ipc.cc b/test/unit/ipc.cc index c5812bbf90..c475e84cad 100644 --- a/test/unit/ipc.cc +++ b/test/unit/ipc.cc @@ -3,43 +3,81 @@ #include "ipc.h" #include "unit.h" -enum { - ITERATIONS = 100000, -}; +int status; void -push_f(va_list ap) +ipc_basic() { - struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); - for (int i = 0; i < ITERATIONS; i++) - ipc_channel_put(channel, NULL); -} + header(); + plan(10); -void -pop_f(va_list ap) -{ - struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); + struct ipc_channel *channel = ipc_channel_new(1); + ok(channel != NULL, "ipc_channel_new()"); + + ok(ipc_channel_size(channel) == 1, "ipc_channel_size()"); + + ok(ipc_channel_count(channel) == 0, "ipc_channel_count()"); + + ok(ipc_channel_is_full(channel) == false, "ipc_channel_is_full()"); + + ok(ipc_channel_is_empty(channel) == true, "ipc_channel_is_empty()"); + + char dummy; + + ipc_channel_put(channel, &dummy); + + ok(ipc_channel_size(channel) == 1, "ipc_channel_size(1)"); + + ok(ipc_channel_count(channel) == 1, "ipc_channel_count(1)"); + + ok(ipc_channel_is_full(channel) == true, "ipc_channel_is_full(1)"); + + ok(ipc_channel_is_empty(channel) == false, "ipc_channel_is_empty(1)"); + + ok(ipc_channel_get(channel) == &dummy, "ipc_channel_get()"); - for (int i = 0; i < ITERATIONS; i++) - (void) ipc_channel_get(channel); + ipc_channel_delete(channel); + + footer(); + status = check_plan(); } -void main_f(va_list ap) +void +ipc_get() { header(); - struct fiber *push = fiber_new("push_f", push_f); - fiber_set_joinable(push, true); - struct fiber *pop = fiber_new("pop_f", pop_f); - fiber_set_joinable(pop, true); + plan(7); + struct ipc_channel *channel = ipc_channel_new(1); - fiber_start(push, channel); - fiber_start(pop, channel); - fiber_join(push); - fiber_join(pop); + + char dummy; + ok(ipc_channel_put_timeout(channel, &dummy, 0) == 0, + "ipc_channel_put(0)"); + ok(ipc_channel_put_timeout(channel, &dummy, 0) == -1, + "ipc_channel_put_timeout(0)"); + ok(ipc_channel_get(channel) == &dummy, "ipc_channel_get(0)"); + ok(ipc_channel_put_timeout(channel, &dummy, 0.01) == 0, + "ipc_channel_put_timeout(1)"); + ok(ipc_channel_get(channel) == &dummy, "ipc_channel_get(1)"); + + ipc_channel_close(channel); + + ok(ipc_channel_put(channel, &dummy) == -1, "ipc_channel_put(closed)"); + + ok(ipc_channel_get(channel) == NULL, "ipc_channel_get(closed)"); + ipc_channel_delete(channel); - ev_break(loop(), EVBREAK_ALL); + footer(); + status = check_plan(); +} + +void main_f(va_list /* ap */) +{ + ipc_basic(); + ipc_get(); + ev_break(loop(), EVBREAK_ALL); } int main() @@ -51,5 +89,5 @@ int main() ev_run(loop(), 0); fiber_free(); memory_free(); - return 0; + return status; } diff --git a/test/unit/ipc.result b/test/unit/ipc.result index f3398fb9c7..a09ea9d85f 100644 --- a/test/unit/ipc.result +++ b/test/unit/ipc.result @@ -1,3 +1,24 @@ - *** main_f *** - *** main_f: done *** + *** ipc_basic *** +1..10 +ok 1 - ipc_channel_new() +ok 2 - ipc_channel_size() +ok 3 - ipc_channel_count() +ok 4 - ipc_channel_is_full() +ok 5 - ipc_channel_is_empty() +ok 6 - ipc_channel_size(1) +ok 7 - ipc_channel_count(1) +ok 8 - ipc_channel_is_full(1) +ok 9 - ipc_channel_is_empty(1) +ok 10 - ipc_channel_get() + *** ipc_basic: done *** + *** ipc_get *** +1..7 +ok 1 - ipc_channel_put(0) +ok 2 - ipc_channel_put_timeout(0) +ok 3 - ipc_channel_get(0) +ok 4 - ipc_channel_put_timeout(1) +ok 5 - ipc_channel_get(1) +ok 6 - ipc_channel_put(closed) +ok 7 - ipc_channel_get(closed) + *** ipc_get: done *** \ No newline at end of file diff --git a/test/unit/ipc_stress.cc b/test/unit/ipc_stress.cc new file mode 100644 index 0000000000..c5812bbf90 --- /dev/null +++ b/test/unit/ipc_stress.cc @@ -0,0 +1,55 @@ +#include "memory.h" +#include "fiber.h" +#include "ipc.h" +#include "unit.h" + +enum { + ITERATIONS = 100000, +}; + +void +push_f(va_list ap) +{ + struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); + + for (int i = 0; i < ITERATIONS; i++) + ipc_channel_put(channel, NULL); +} + +void +pop_f(va_list ap) +{ + struct ipc_channel *channel = va_arg(ap, struct ipc_channel *); + + for (int i = 0; i < ITERATIONS; i++) + (void) ipc_channel_get(channel); +} + +void main_f(va_list ap) +{ + header(); + struct fiber *push = fiber_new("push_f", push_f); + fiber_set_joinable(push, true); + struct fiber *pop = fiber_new("pop_f", pop_f); + fiber_set_joinable(pop, true); + struct ipc_channel *channel = ipc_channel_new(1); + fiber_start(push, channel); + fiber_start(pop, channel); + fiber_join(push); + fiber_join(pop); + ipc_channel_delete(channel); + ev_break(loop(), EVBREAK_ALL); + footer(); +} + +int main() +{ + memory_init(); + fiber_init(); + struct fiber *main= fiber_new("main", main_f); + fiber_wakeup(main); + ev_run(loop(), 0); + fiber_free(); + memory_free(); + return 0; +} diff --git a/test/unit/ipc_stress.result b/test/unit/ipc_stress.result new file mode 100644 index 0000000000..f3398fb9c7 --- /dev/null +++ b/test/unit/ipc_stress.result @@ -0,0 +1,3 @@ + *** main_f *** + *** main_f: done *** + \ No newline at end of file -- GitLab