[PATCH 2/2] libstdthreads: Add C11 threads

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Sep 21 07:56:20 UTC 2015


---
 cpukit/Makefile.am                                 |   1 +
 cpukit/configure.ac                                |   4 +
 cpukit/libstdthreads/Makefile.am                   |  21 +
 cpukit/libstdthreads/call_once.c                   |   6 +-
 cpukit/libstdthreads/cnd.c                         |  31 +-
 cpukit/libstdthreads/mtx.c                         |  48 +--
 cpukit/libstdthreads/thrd.c                        |   9 +-
 cpukit/libstdthreads/tss.c                         |   7 +-
 cpukit/wrapup/Makefile.am                          |   1 +
 testsuites/sptests/Makefile.am                     |   3 +
 testsuites/sptests/configure.ac                    |   4 +
 testsuites/sptests/spstdthreads01/Makefile.am      |  19 +
 testsuites/sptests/spstdthreads01/init.c           | 438 +++++++++++++++++++++
 .../sptests/spstdthreads01/spstdthreads01.doc      |  35 ++
 .../sptests/spstdthreads01/spstdthreads01.scn      |   2 +
 15 files changed, 554 insertions(+), 75 deletions(-)
 create mode 100644 cpukit/libstdthreads/Makefile.am
 create mode 100644 testsuites/sptests/spstdthreads01/Makefile.am
 create mode 100644 testsuites/sptests/spstdthreads01/init.c
 create mode 100644 testsuites/sptests/spstdthreads01/spstdthreads01.doc
 create mode 100644 testsuites/sptests/spstdthreads01/spstdthreads01.scn

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index c9a4e0f..063a795 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -16,6 +16,7 @@ SUBDIRS += libmisc
 SUBDIRS += libmd
 SUBDIRS += libgnat
 SUBDIRS += libdl
+SUBDIRS += libstdthreads
 SUBDIRS += wrapup
 
 SUBDIRS += zlib
diff --git a/cpukit/configure.ac b/cpukit/configure.ac
index 14ce0f1..01da86d 100644
--- a/cpukit/configure.ac
+++ b/cpukit/configure.ac
@@ -141,6 +141,9 @@ AS_IF([test -n "$rtems_missing_header"],
 AC_CHECK_HEADERS([semaphore.h])
 AM_CONDITIONAL([HAVE_SEMAPHORE_H],[test x"$ac_cv_header_semaphore_h" = x"yes"])
 
+AC_CHECK_HEADERS([threads.h])
+AM_CONDITIONAL([HAVE_THREADS_H],[test x"$ac_cv_header_threads_h" = x"yes"])
+
 ## error out if libc doesn't provide stdint.h
 AS_IF([test x"${ac_cv_header_stdint_h}" != xyes],
 [AC_MSG_ERROR([Required header stdint.h not found])])
@@ -481,6 +484,7 @@ libmisc/Makefile
 libi2c/Makefile
 libmd/Makefile
 libdl/Makefile
+libstdthreads/Makefile
 zlib/Makefile
 ftpd/Makefile
 telnetd/Makefile
diff --git a/cpukit/libstdthreads/Makefile.am b/cpukit/libstdthreads/Makefile.am
new file mode 100644
index 0000000..8b4ffaa
--- /dev/null
+++ b/cpukit/libstdthreads/Makefile.am
@@ -0,0 +1,21 @@
+include $(top_srcdir)/automake/compile.am
+
+include_HEADERS =
+
+noinst_LIBRARIES = libstdthreads.a
+
+libstdthreads_a_CFLAGS = -std=c11
+libstdthreads_a_CPPFLAGS = $(AM_CPPFLAGS)
+
+libstdthreads_a_SOURCES =
+if HAVE_THREADS_H
+libstdthreads_a_SOURCES += call_once.c
+libstdthreads_a_SOURCES += cnd.c
+libstdthreads_a_SOURCES += mtx.c
+if HAS_PTHREADS
+libstdthreads_a_SOURCES += thrd.c
+endif
+libstdthreads_a_SOURCES += tss.c
+endif
+
+include $(top_srcdir)/automake/local.am
diff --git a/cpukit/libstdthreads/call_once.c b/cpukit/libstdthreads/call_once.c
index 2d7d6ff..9a577d6 100644
--- a/cpukit/libstdthreads/call_once.c
+++ b/cpukit/libstdthreads/call_once.c
@@ -26,13 +26,9 @@
  * $FreeBSD r228904 2011-12-26T21:51:53Z$
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <threads.h>
 #include <pthread.h>
 
-#include "threads.h"
-
 void
 call_once(once_flag *flag, void (*func)(void))
 {
diff --git a/cpukit/libstdthreads/cnd.c b/cpukit/libstdthreads/cnd.c
index cccf728..7ed750a 100644
--- a/cpukit/libstdthreads/cnd.c
+++ b/cpukit/libstdthreads/cnd.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2011 Ed Schouten <ed at FreeBSD.org>
+ * Copyright (c) 2015 embedded brains GmbH <info at embedded-brains.de>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,20 +27,14 @@
  * $FreeBSD r228904 2011-12-26T21:51:53Z$
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <threads.h>
 #include <errno.h>
-#include <pthread.h>
-
-#include "threads.h"
 
 int
 cnd_broadcast(cnd_t *cond)
 {
 
-	if (pthread_cond_broadcast(cond) != 0)
-		return (thrd_error);
+	_Condition_Broadcast(cond);
 	return (thrd_success);
 }
 
@@ -47,29 +42,22 @@ void
 cnd_destroy(cnd_t *cond)
 {
 
-	(void)pthread_cond_destroy(cond);
+	_Condition_Destroy(cond);
 }
 
 int
 cnd_init(cnd_t *cond)
 {
 
-	switch (pthread_cond_init(cond, NULL)) {
-	case 0:
-		return (thrd_success);
-	case ENOMEM:
-		return (thrd_nomem);
-	default:
-		return (thrd_error);
-	}
+	_Condition_Initialize(cond);
+	return (thrd_success);
 }
 
 int
 cnd_signal(cnd_t *cond)
 {
 
-	if (pthread_cond_signal(cond) != 0)
-		return (thrd_error);
+	_Condition_Signal(cond);
 	return (thrd_success);
 }
 
@@ -78,7 +66,7 @@ cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx,
     const struct timespec *restrict ts)
 {
 
-	switch (pthread_cond_timedwait(cond, mtx, ts)) {
+	switch (_Condition_Wait_recursive_timed(cond, mtx, ts)) {
 	case 0:
 		return (thrd_success);
 	case ETIMEDOUT:
@@ -92,7 +80,6 @@ int
 cnd_wait(cnd_t *cond, mtx_t *mtx)
 {
 
-	if (pthread_cond_wait(cond, mtx) != 0)
-		return (thrd_error);
+	_Condition_Wait_recursive(cond, mtx);
 	return (thrd_success);
 }
diff --git a/cpukit/libstdthreads/mtx.c b/cpukit/libstdthreads/mtx.c
index 2d42f8a..48369c2 100644
--- a/cpukit/libstdthreads/mtx.c
+++ b/cpukit/libstdthreads/mtx.c
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2011 Ed Schouten <ed at FreeBSD.org>
+ * Copyright (c) 2015 embedded brains GmbH <info at embedded-brains.de>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,46 +27,23 @@
  * $FreeBSD r279326 2015-02-26T16:39:57Z$
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <threads.h>
+#include <sys/lock.h>
 #include <errno.h>
-#include <pthread.h>
-
-#include "threads.h"
 
 void
 mtx_destroy(mtx_t *mtx)
 {
 
-	(void)pthread_mutex_destroy(mtx);
+	_Mutex_recursive_Destroy(mtx);
 }
 
 int
 mtx_init(mtx_t *mtx, int type)
 {
-	pthread_mutexattr_t attr;
-	int mt;
 
-	switch (type) {
-	case mtx_plain:
-	case mtx_timed:
-		mt = PTHREAD_MUTEX_NORMAL;
-		break;
-	case mtx_plain | mtx_recursive:
-	case mtx_timed | mtx_recursive:
-		mt = PTHREAD_MUTEX_RECURSIVE;
-		break;
-	default:
-		return (thrd_error);
-	}
-
-	if (pthread_mutexattr_init(&attr) != 0)
-		return (thrd_error);
-	if (pthread_mutexattr_settype(&attr, mt) != 0)
-		return (thrd_error);
-	if (pthread_mutex_init(mtx, &attr) != 0)
-		return (thrd_error);
+	(void)type;
+	_Mutex_recursive_Initialize(mtx);
 	return (thrd_success);
 }
 
@@ -73,8 +51,7 @@ int
 mtx_lock(mtx_t *mtx)
 {
 
-	if (pthread_mutex_lock(mtx) != 0)
-		return (thrd_error);
+	_Mutex_recursive_Acquire(mtx);
 	return (thrd_success);
 }
 
@@ -82,7 +59,7 @@ int
 mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts)
 {
 
-	switch (pthread_mutex_timedlock(mtx, ts)) {
+	switch (_Mutex_recursive_Acquire_timed(mtx, ts)) {
 	case 0:
 		return (thrd_success);
 	case ETIMEDOUT:
@@ -96,13 +73,11 @@ int
 mtx_trylock(mtx_t *mtx)
 {
 
-	switch (pthread_mutex_trylock(mtx)) {
+	switch (_Mutex_recursive_Try_acquire(mtx)) {
 	case 0:
 		return (thrd_success);
-	case EBUSY:
-		return (thrd_busy);
 	default:
-		return (thrd_error);
+		return (thrd_busy);
 	}
 }
 
@@ -110,7 +85,6 @@ int
 mtx_unlock(mtx_t *mtx)
 {
 
-	if (pthread_mutex_unlock(mtx) != 0)
-		return (thrd_error);
+	_Mutex_recursive_Release(mtx);
 	return (thrd_success);
 }
diff --git a/cpukit/libstdthreads/thrd.c b/cpukit/libstdthreads/thrd.c
index 562e806..c2e439f 100644
--- a/cpukit/libstdthreads/thrd.c
+++ b/cpukit/libstdthreads/thrd.c
@@ -26,15 +26,12 @@
  * $FreeBSD r279318 2015-02-26T09:42:03Z$
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <threads.h>
 #include <pthread.h>
+#include <sched.h>
 #include <stdint.h>
 #include <stdlib.h>
 
-#include "threads.h"
-
 struct thrd_param {
 	thrd_start_t	 func;
 	void		*arg;
@@ -124,5 +121,5 @@ void
 thrd_yield(void)
 {
 
-	pthread_yield();
+	sched_yield();
 }
diff --git a/cpukit/libstdthreads/tss.c b/cpukit/libstdthreads/tss.c
index 0d4eea7..9ff9d3b 100644
--- a/cpukit/libstdthreads/tss.c
+++ b/cpukit/libstdthreads/tss.c
@@ -26,13 +26,10 @@
  * $FreeBSD r228904 2011-12-26T21:51:53Z$
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <threads.h>
+#include <limits.h>
 #include <pthread.h>
 
-#include "threads.h"
-
 int
 tss_create(tss_t *key, tss_dtor_t dtor)
 {
diff --git a/cpukit/wrapup/Makefile.am b/cpukit/wrapup/Makefile.am
index 5fd6e33..57ef832 100644
--- a/cpukit/wrapup/Makefile.am
+++ b/cpukit/wrapup/Makefile.am
@@ -20,6 +20,7 @@ TMP_LIBS += ../libgnat/libgnat.a
 endif
 
 TMP_LIBS += ../libcrypt/libcrypt.a
+TMP_LIBS += ../libstdthreads/libstdthreads.a
 TMP_LIBS += ../libcsupport/libcsupport.a
 TMP_LIBS += ../libcsupport/libcalloc.a
 TMP_LIBS += ../libblock/libblock.a
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index d012019..688c66f 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -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
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index be69f09..ea96dbf 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -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
diff --git a/testsuites/sptests/spstdthreads01/Makefile.am b/testsuites/sptests/spstdthreads01/Makefile.am
new file mode 100644
index 0000000..bef6888
--- /dev/null
+++ b/testsuites/sptests/spstdthreads01/Makefile.am
@@ -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 at .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
diff --git a/testsuites/sptests/spstdthreads01/init.c b/testsuites/sptests/spstdthreads01/init.c
new file mode 100644
index 0000000..40d44d6
--- /dev/null
+++ b/testsuites/sptests/spstdthreads01/init.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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>
diff --git a/testsuites/sptests/spstdthreads01/spstdthreads01.doc b/testsuites/sptests/spstdthreads01/spstdthreads01.doc
new file mode 100644
index 0000000..1594374
--- /dev/null
+++ b/testsuites/sptests/spstdthreads01/spstdthreads01.doc
@@ -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.
diff --git a/testsuites/sptests/spstdthreads01/spstdthreads01.scn b/testsuites/sptests/spstdthreads01/spstdthreads01.scn
new file mode 100644
index 0000000..010272d
--- /dev/null
+++ b/testsuites/sptests/spstdthreads01/spstdthreads01.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTDTHREADS 1 ***
+*** END OF TEST SPSTDTHREADS 1 ***
-- 
1.8.4.5



More information about the devel mailing list