forked from Imagelibrary/rtems
437 lines
9.6 KiB
C
437 lines
9.6 KiB
C
/*
|
|
* Copyright (c) 2015 embedded brains GmbH. All rights reserved.
|
|
*
|
|
* embedded brains GmbH
|
|
* Dornierstr. 4
|
|
* 82178 Puchheim
|
|
* Germany
|
|
* <rtems@embedded-brains.de>
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "tmacros.h"
|
|
|
|
#include <threads.h>
|
|
|
|
#include <rtems/malloc.h>
|
|
|
|
const char rtems_test_name[] = "SPSTDTHREADS 1";
|
|
|
|
#define US_PER_TICK 10000
|
|
|
|
#define EVENT_MTX_LOCK RTEMS_EVENT_0
|
|
|
|
#define EVENT_MTX_UNLOCK RTEMS_EVENT_1
|
|
|
|
#define EVENT_CND_WAIT RTEMS_EVENT_2
|
|
|
|
#define EVENT_CND_TIMEDWAIT RTEMS_EVENT_3
|
|
|
|
#define EVENT_TSS RTEMS_EVENT_4
|
|
|
|
typedef struct {
|
|
rtems_id high;
|
|
rtems_id low;
|
|
once_flag once_flag;
|
|
mtx_t mtx;
|
|
cnd_t cnd;
|
|
tss_t tss;
|
|
thrd_t thrd;
|
|
int generation;
|
|
} test_context;
|
|
|
|
static test_context test_instance = {
|
|
.once_flag = ONCE_FLAG_INIT
|
|
};
|
|
|
|
static void next_generation(test_context *ctx)
|
|
{
|
|
++ctx->generation;
|
|
}
|
|
|
|
static void send_event(test_context *ctx, rtems_event_set events)
|
|
{
|
|
rtems_status_code sc;
|
|
|
|
sc = rtems_event_send(ctx->high, events);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
}
|
|
|
|
static void get_abs_timeout(struct timespec *to)
|
|
{
|
|
int rv;
|
|
|
|
rv = clock_gettime(CLOCK_REALTIME, to);
|
|
rtems_test_assert(rv == 0);
|
|
|
|
to->tv_nsec += 2 * US_PER_TICK * 1000;
|
|
if (to->tv_nsec >= 1000000000) {
|
|
++to->tv_sec;
|
|
to->tv_nsec -= 1000000000;
|
|
}
|
|
}
|
|
|
|
static void test_init(test_context *ctx)
|
|
{
|
|
int status;
|
|
|
|
status = mtx_init(&ctx->mtx, mtx_plain);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = cnd_init(&ctx->cnd);
|
|
rtems_test_assert(status == thrd_success);
|
|
}
|
|
|
|
static void test_destroy(test_context *ctx)
|
|
{
|
|
mtx_destroy(&ctx->mtx);
|
|
cnd_destroy(&ctx->cnd);
|
|
}
|
|
|
|
static void once_func(void)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
|
|
next_generation(ctx);
|
|
}
|
|
|
|
static void test_once(test_context *ctx)
|
|
{
|
|
int gen = ctx->generation;
|
|
|
|
call_once(&ctx->once_flag, once_func);
|
|
rtems_test_assert(ctx->generation == gen + 1);
|
|
|
|
call_once(&ctx->once_flag, once_func);
|
|
rtems_test_assert(ctx->generation == gen + 1);
|
|
}
|
|
|
|
static void test_mtx(test_context *ctx)
|
|
{
|
|
mtx_t *mtx = &ctx->mtx;
|
|
int gen = ctx->generation;
|
|
struct timespec to;
|
|
int status;
|
|
|
|
status = mtx_trylock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_lock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
get_abs_timeout(&to);
|
|
status = mtx_timedlock(mtx, &to);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
send_event(ctx, EVENT_MTX_LOCK);
|
|
rtems_test_assert(ctx->generation == gen + 1);
|
|
|
|
status = mtx_trylock(mtx);
|
|
rtems_test_assert(status == thrd_busy);
|
|
|
|
memset(&to, 0xff, sizeof(to));
|
|
status = mtx_timedlock(mtx, &to);
|
|
rtems_test_assert(status == thrd_error);
|
|
|
|
get_abs_timeout(&to);
|
|
status = mtx_timedlock(mtx, &to);
|
|
rtems_test_assert(status == thrd_timedout);
|
|
|
|
send_event(ctx, EVENT_MTX_UNLOCK);
|
|
rtems_test_assert(ctx->generation == gen + 2);
|
|
}
|
|
|
|
static void test_cnd(test_context *ctx)
|
|
{
|
|
cnd_t *cnd = &ctx->cnd;
|
|
mtx_t *mtx = &ctx->mtx;
|
|
int gen = ctx->generation;
|
|
struct timespec to;
|
|
int status;
|
|
|
|
send_event(ctx, EVENT_CND_WAIT);
|
|
rtems_test_assert(ctx->generation == gen + 1);
|
|
|
|
status = mtx_lock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = cnd_signal(cnd);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
rtems_test_assert(ctx->generation == gen + 2);
|
|
|
|
send_event(ctx, EVENT_CND_WAIT);
|
|
rtems_test_assert(ctx->generation == gen + 3);
|
|
|
|
status = mtx_lock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = cnd_broadcast(cnd);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
rtems_test_assert(ctx->generation == gen + 4);
|
|
|
|
status = mtx_lock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
memset(&to, 0xff, sizeof(to));
|
|
status = cnd_timedwait(cnd, mtx, &to);
|
|
rtems_test_assert(status == thrd_error);
|
|
|
|
get_abs_timeout(&to);
|
|
status = cnd_timedwait(cnd, mtx, &to);
|
|
rtems_test_assert(status == thrd_timedout);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
send_event(ctx, EVENT_CND_TIMEDWAIT);
|
|
rtems_test_assert(ctx->generation == gen + 5);
|
|
|
|
status = mtx_lock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = cnd_signal(cnd);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = mtx_unlock(mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
rtems_test_assert(ctx->generation == gen + 6);
|
|
}
|
|
|
|
static int tss_val = TSS_DTOR_ITERATIONS;
|
|
|
|
static void tss_dtor(void *val)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
|
|
rtems_test_assert(val == &tss_val);
|
|
next_generation(ctx);
|
|
}
|
|
|
|
static void test_tss(test_context *ctx)
|
|
{
|
|
tss_dtor_t dtor = tss_dtor;
|
|
int gen = ctx->generation;
|
|
int status;
|
|
|
|
status = tss_create(&ctx->tss, dtor);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
send_event(ctx, EVENT_TSS);
|
|
rtems_test_assert(ctx->generation == gen + 1);
|
|
|
|
tss_delete(ctx->tss);
|
|
}
|
|
|
|
#if defined(RTEMS_POSIX_API)
|
|
static int thrd(void *arg)
|
|
{
|
|
thrd_exit(123);
|
|
}
|
|
#endif
|
|
|
|
static void test_thrd(test_context *ctx)
|
|
{
|
|
#if defined(RTEMS_POSIX_API)
|
|
thrd_start_t thrd_start = thrd;
|
|
int status;
|
|
int exit_status;
|
|
struct timespec duration;
|
|
struct timespec remaining;
|
|
void *greedy;
|
|
|
|
rtems_test_assert(thrd_equal(rtems_task_self(), thrd_current()));
|
|
|
|
thrd_yield();
|
|
|
|
memset(&duration, 0, sizeof(duration));
|
|
duration.tv_nsec = 1;
|
|
thrd_sleep(&duration, &remaining);
|
|
rtems_test_assert(remaining.tv_sec == 0);
|
|
rtems_test_assert(remaining.tv_nsec == 0);
|
|
|
|
greedy = rtems_heap_greedy_allocate(NULL, 0);
|
|
status = thrd_create(&ctx->thrd, thrd_start, ctx);
|
|
rtems_test_assert(status == thrd_nomem);
|
|
rtems_heap_greedy_free(greedy);
|
|
|
|
status = thrd_create(&ctx->thrd, thrd_start, ctx);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = thrd_create(&ctx->thrd, thrd_start, ctx);
|
|
rtems_test_assert(status == thrd_error);
|
|
|
|
exit_status = 0;
|
|
status = thrd_join(ctx->thrd, &exit_status);
|
|
rtems_test_assert(status == thrd_success);
|
|
rtems_test_assert(exit_status == 123);
|
|
|
|
status = thrd_detach(thrd_current());
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
status = thrd_detach(11235);
|
|
rtems_test_assert(status == thrd_error);
|
|
#endif
|
|
}
|
|
|
|
static void high_task(rtems_task_argument idx)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
|
|
while (true) {
|
|
rtems_event_set events;
|
|
rtems_status_code sc;
|
|
int status;
|
|
|
|
sc = rtems_event_receive(
|
|
RTEMS_ALL_EVENTS,
|
|
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
|
RTEMS_NO_TIMEOUT,
|
|
&events
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
if ((events & EVENT_MTX_LOCK) != 0) {
|
|
status = mtx_lock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
}
|
|
|
|
if ((events & EVENT_MTX_UNLOCK) != 0) {
|
|
status = mtx_unlock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
}
|
|
|
|
if ((events & EVENT_CND_WAIT) != 0) {
|
|
status = mtx_lock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
|
|
status = cnd_wait(&ctx->cnd, &ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
|
|
status = mtx_unlock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
}
|
|
|
|
if ((events & EVENT_CND_TIMEDWAIT) != 0) {
|
|
struct timespec to;
|
|
|
|
status = mtx_lock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
|
|
get_abs_timeout(&to);
|
|
status = cnd_timedwait(&ctx->cnd, &ctx->mtx, &to);
|
|
rtems_test_assert(status == thrd_success);
|
|
next_generation(ctx);
|
|
|
|
status = mtx_unlock(&ctx->mtx);
|
|
rtems_test_assert(status == thrd_success);
|
|
}
|
|
|
|
if ((events & EVENT_TSS) != 0) {
|
|
void *val;
|
|
|
|
status = tss_set(ctx->tss, &tss_val);
|
|
rtems_test_assert(status == thrd_success);
|
|
|
|
val = tss_get(ctx->tss);
|
|
rtems_test_assert(val == &tss_val);
|
|
|
|
rtems_task_delete(RTEMS_SELF);
|
|
rtems_test_assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void test(void)
|
|
{
|
|
test_context *ctx = &test_instance;
|
|
rtems_status_code sc;
|
|
|
|
test_init(ctx);
|
|
|
|
ctx->low = rtems_task_self();
|
|
|
|
sc = rtems_task_create(
|
|
rtems_build_name('H', 'I', 'G', 'H'),
|
|
1,
|
|
RTEMS_MINIMUM_STACK_SIZE,
|
|
RTEMS_DEFAULT_MODES,
|
|
RTEMS_DEFAULT_ATTRIBUTES,
|
|
&ctx->high
|
|
);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
sc = rtems_task_start(ctx->high, high_task, 0);
|
|
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
|
|
|
test_once(ctx);
|
|
test_mtx(ctx);
|
|
test_cnd(ctx);
|
|
test_tss(ctx);
|
|
test_thrd(ctx);
|
|
test_destroy(ctx);
|
|
}
|
|
|
|
static void Init(rtems_task_argument arg)
|
|
{
|
|
TEST_BEGIN();
|
|
|
|
test();
|
|
|
|
TEST_END();
|
|
rtems_test_exit(0);
|
|
}
|
|
|
|
#define CONFIGURE_MICROSECONDS_PER_TICK US_PER_TICK
|
|
|
|
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
|
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
|
|
|
#define CONFIGURE_MAXIMUM_TASKS 4
|
|
|
|
#define CONFIGURE_MAXIMUM_POSIX_KEYS 1
|
|
#define CONFIGURE_MAXIMUM_POSIX_KEY_VALUE_PAIRS 1
|
|
|
|
#if defined(RTEMS_POSIX_API)
|
|
#define CONFIGURE_MAXIMUM_POSIX_THREADS 1
|
|
#endif
|
|
|
|
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
|
|
|
#define CONFIGURE_INIT_TASK_PRIORITY 4
|
|
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
|
|
|
|
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
|
|
|
#define CONFIGURE_SCHEDULER_NAME rtems_build_name('b', 'l', 'u', 'e')
|
|
|
|
#define CONFIGURE_INIT
|
|
|
|
#include <rtems/confdefs.h>
|