Skip to content
Snippets Groups Projects
Commit 925c6af8 authored by Konstantin Osipov's avatar Konstantin Osipov
Browse files

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).
parent 6bf941c0
No related branches found
No related tags found
No related merge requests found
......@@ -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)
{
......
......@@ -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)
......
......@@ -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
......
......@@ -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;
}
*** 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
#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;
}
*** main_f ***
*** main_f: done ***
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment