2017-08-30 12:36:15 +02:00
|
|
|
/** Unit tests for queue_signalled
|
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2020-01-20 17:17:00 +01:00
|
|
|
* @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
|
2017-08-30 12:36:15 +02:00
|
|
|
* @license GNU General Public License (version 3)
|
|
|
|
*
|
|
|
|
* VILLASnode
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************************/
|
|
|
|
|
|
|
|
#include <criterion/criterion.h>
|
|
|
|
#include <criterion/parameterized.h>
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <poll.h>
|
|
|
|
|
2019-04-23 13:09:50 +02:00
|
|
|
#include <villas/utils.hpp>
|
2018-03-26 12:50:15 +02:00
|
|
|
#include <villas/memory.h>
|
|
|
|
#include <villas/queue_signalled.h>
|
2017-08-30 12:36:15 +02:00
|
|
|
|
2018-08-13 14:58:52 +02:00
|
|
|
extern void init_memory();
|
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
#define NUM_ELEM 1000
|
|
|
|
|
|
|
|
struct param {
|
2019-06-23 16:13:23 +02:00
|
|
|
enum QueueSignalledMode mode;
|
2017-08-30 12:36:15 +02:00
|
|
|
int flags;
|
2018-10-21 13:00:50 +01:00
|
|
|
bool polled;
|
2017-08-30 12:36:15 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void * producer(void * ctx)
|
|
|
|
{
|
|
|
|
int ret;
|
2018-08-23 13:32:44 +02:00
|
|
|
struct queue_signalled *q = (struct queue_signalled *) ctx;
|
2017-08-30 12:36:15 +02:00
|
|
|
|
|
|
|
for (intptr_t i = 0; i < NUM_ELEM; i++) {
|
|
|
|
ret = queue_signalled_push(q, (void *) i);
|
|
|
|
if (ret != 1)
|
|
|
|
return (void *) 1; /* Indicates an error to the parent thread */
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
usleep(0.1e-3 * 1e6); /* 1 ms */
|
|
|
|
}
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2018-08-27 11:21:57 +02:00
|
|
|
return nullptr;
|
2017-08-30 12:36:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void * consumer(void * ctx)
|
|
|
|
{
|
|
|
|
int ret;
|
2018-08-23 13:32:44 +02:00
|
|
|
struct queue_signalled *q = (struct queue_signalled *) ctx;
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
void *data[NUM_ELEM];
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
for (intptr_t i = 0; i < NUM_ELEM;) {
|
|
|
|
ret = queue_signalled_pull_many(q, data, ARRAY_LEN(data));
|
|
|
|
if (ret <= 0)
|
|
|
|
return (void *) 1; /* Indicates an error to the parent thread */
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
for (intptr_t j = 0; j < ret; j++, i++) {
|
|
|
|
if ((intptr_t) data[j] != i)
|
|
|
|
return (void *) 2; /* Indicates an error to the parent thread */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 11:21:57 +02:00
|
|
|
return nullptr;
|
2017-08-30 12:36:15 +02:00
|
|
|
}
|
|
|
|
|
2018-03-26 12:50:15 +02:00
|
|
|
void * polled_consumer(void *ctx)
|
2017-08-30 12:36:15 +02:00
|
|
|
{
|
|
|
|
int ret, fd;
|
2018-08-23 13:32:44 +02:00
|
|
|
struct queue_signalled *q = (struct queue_signalled *) ctx;
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
fd = queue_signalled_fd(q);
|
|
|
|
cr_assert_geq(fd, 0);
|
|
|
|
|
|
|
|
struct pollfd pfd = {
|
|
|
|
.fd = fd,
|
|
|
|
.events = POLLIN
|
|
|
|
};
|
|
|
|
|
|
|
|
for (intptr_t i = 0; i < NUM_ELEM; i++) {
|
|
|
|
again: ret = poll(&pfd, 1, -1);
|
|
|
|
if (ret < 0)
|
|
|
|
return (void *) 3;
|
|
|
|
else if (ret == 0)
|
|
|
|
goto again;
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
|
|
|
|
void *p;
|
|
|
|
ret = queue_signalled_pull(q, &p);
|
|
|
|
if (ret != 1)
|
|
|
|
return (void *) 1; /* Indicates an error to the parent thread */
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
if ((intptr_t) p != i)
|
|
|
|
return (void *) 2; /* Indicates an error to the parent thread */
|
|
|
|
}
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2018-08-27 11:21:57 +02:00
|
|
|
return nullptr;
|
2017-08-30 12:36:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ParameterizedTestParameters(queue_signalled, simple)
|
|
|
|
{
|
|
|
|
static struct param params[] = {
|
2019-06-23 16:13:23 +02:00
|
|
|
{ QueueSignalledMode::AUTO, 0, false },
|
|
|
|
{ QueueSignalledMode::PTHREAD, 0, false },
|
|
|
|
{ QueueSignalledMode::PTHREAD, 0, false },
|
|
|
|
{ QueueSignalledMode::PTHREAD, (int) QueueSignalledFlags::PROCESS_SHARED, false },
|
|
|
|
{ QueueSignalledMode::POLLING, 0, false },
|
2018-08-09 14:19:35 +02:00
|
|
|
#if defined(__linux__) && defined(HAS_EVENTFD)
|
2019-06-23 16:13:23 +02:00
|
|
|
{ QueueSignalledMode::EVENTFD, 0, false },
|
|
|
|
{ QueueSignalledMode::EVENTFD, 0, true }
|
2017-08-30 12:36:15 +02:00
|
|
|
#endif
|
|
|
|
};
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
return cr_make_param_array(struct param, params, ARRAY_LEN(params));
|
|
|
|
}
|
|
|
|
|
2020-09-11 14:57:05 +02:00
|
|
|
// cppcheck-suppress unknownMacro
|
2018-08-13 14:58:52 +02:00
|
|
|
ParameterizedTest(struct param *param, queue_signalled, simple, .timeout = 5, .init = init_memory)
|
2017-08-30 12:36:15 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
void *r1, *r2;
|
2018-08-23 13:32:44 +02:00
|
|
|
struct queue_signalled q;
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
pthread_t t1, t2;
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2019-06-23 16:13:23 +02:00
|
|
|
ret = queue_signalled_init(&q, LOG2_CEIL(NUM_ELEM), &memory_heap, param->mode, param->flags);
|
|
|
|
cr_assert_eq(ret, 0, "Failed to initialize queue: mode=%d, flags=%#x, ret=%d", (int) param->mode, param->flags, ret);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2018-08-27 11:21:57 +02:00
|
|
|
ret = pthread_create(&t1, nullptr, producer, &q);
|
2017-08-30 12:36:15 +02:00
|
|
|
cr_assert_eq(ret, 0);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2018-08-27 11:21:57 +02:00
|
|
|
ret = pthread_create(&t2, nullptr, param->polled ? polled_consumer : consumer, &q);
|
2017-08-30 12:36:15 +02:00
|
|
|
cr_assert_eq(ret, 0);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
ret = pthread_join(t1, &r1);
|
|
|
|
cr_assert_eq(ret, 0);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
ret = pthread_join(t2, &r2);
|
|
|
|
cr_assert_eq(ret, 0);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
cr_assert_null(r1, "Producer failed: %p", r1);
|
|
|
|
cr_assert_null(r2, "Consumer failed: %p", r2);
|
2018-03-26 12:50:15 +02:00
|
|
|
|
2017-08-30 12:36:15 +02:00
|
|
|
ret = queue_signalled_available(&q);
|
|
|
|
cr_assert_eq(ret, 0);
|
|
|
|
|
|
|
|
ret = queue_signalled_close(&q);
|
2018-03-26 12:50:15 +02:00
|
|
|
cr_assert_eq(ret, 0);
|
2017-08-30 12:36:15 +02:00
|
|
|
|
|
|
|
ret = queue_signalled_destroy(&q);
|
2018-03-26 12:50:15 +02:00
|
|
|
cr_assert_eq(ret, 0);
|
|
|
|
}
|