forked from Imagelibrary/rtems
libstdthreads: Add C11 threads
This commit is contained in:
@@ -40,6 +40,9 @@ endif
|
||||
if HAS__THREAD_QUEUE_QUEUE
|
||||
_SUBDIRS += spsyslock01
|
||||
endif
|
||||
if HAS_THREADS_H
|
||||
_SUBDIRS += spstdthreads01
|
||||
endif
|
||||
_SUBDIRS += sptasknopreempt01
|
||||
_SUBDIRS += spintrcritical23
|
||||
_SUBDIRS += sptimecounter01
|
||||
|
||||
@@ -33,6 +33,9 @@ AC_CHECK_SIZEOF([time_t])
|
||||
AC_CHECK_TYPES([struct _Thread_queue_Queue],[],[],[#include <sys/lock.h>])
|
||||
AM_CONDITIONAL(HAS__THREAD_QUEUE_QUEUE,test x"${ac_cv_type_struct__Thread_queue_Queue}" = x"yes")
|
||||
|
||||
AC_CHECK_HEADERS([threads.h])
|
||||
AM_CONDITIONAL([HAS_THREADS_H],[test x"$ac_cv_header_threads_h" = x"yes"])
|
||||
|
||||
# Added to newlib pthreads for RTEMS SMP (np), may not be present
|
||||
AC_CHECK_HEADERS([sys/cpuset.h])
|
||||
AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes")
|
||||
@@ -43,6 +46,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes")
|
||||
|
||||
# Explicitly list all Makefiles here
|
||||
AC_CONFIG_FILES([Makefile
|
||||
spstdthreads01/Makefile
|
||||
spsyslock01/Makefile
|
||||
sptasknopreempt01/Makefile
|
||||
spintrcritical23/Makefile
|
||||
|
||||
19
testsuites/sptests/spstdthreads01/Makefile.am
Normal file
19
testsuites/sptests/spstdthreads01/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = spstdthreads01
|
||||
spstdthreads01_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = spstdthreads01.scn spstdthreads01.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(spstdthreads01_OBJECTS)
|
||||
LINK_LIBS = $(spstdthreads01_LDLIBS)
|
||||
|
||||
spstdthreads01$(EXEEXT): $(spstdthreads01_OBJECTS) $(spstdthreads01_DEPENDENCIES)
|
||||
@rm -f spstdthreads01$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
438
testsuites/sptests/spstdthreads01/init.c
Normal file
438
testsuites/sptests/spstdthreads01/init.c
Normal file
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
|
||||
|
||||
#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>
|
||||
35
testsuites/sptests/spstdthreads01/spstdthreads01.doc
Normal file
35
testsuites/sptests/spstdthreads01/spstdthreads01.doc
Normal file
@@ -0,0 +1,35 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: spstdthreads01
|
||||
|
||||
directives:
|
||||
|
||||
- call_once()
|
||||
- cnd_broadcast()
|
||||
- cnd_destroy()
|
||||
- cnd_init()
|
||||
- cnd_signal()
|
||||
- cnd_timedwait()
|
||||
- cnd_wait()
|
||||
- mtx_destroy()
|
||||
- mtx_init()
|
||||
- mtx_lock()
|
||||
- mtx_timedlock()
|
||||
- mtx_trylock()
|
||||
- mtx_unlock()
|
||||
- thrd_create()
|
||||
- thrd_current()
|
||||
- thrd_detach()
|
||||
- thrd_equal()
|
||||
- thrd_exit()
|
||||
- thrd_join()
|
||||
- thrd_sleep()
|
||||
- thrd_yield()
|
||||
- tss_create()
|
||||
- tss_delete()
|
||||
- tss_get()
|
||||
- tss_set()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that the C11 threads API works.
|
||||
2
testsuites/sptests/spstdthreads01/spstdthreads01.scn
Normal file
2
testsuites/sptests/spstdthreads01/spstdthreads01.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SPSTDTHREADS 1 ***
|
||||
*** END OF TEST SPSTDTHREADS 1 ***
|
||||
Reference in New Issue
Block a user