cyclonedds/src/ddsrt/tests/thread.c
Jeroen Koekkoek cd6742ee12 Rearrange and fixup abstraction layer
- Replace os_result by dds_retcode_t and move DDS return code defines down.
  Eliminates the need to convert between different return code types.

- Move dds_time_t down and remove os_time.
  Eliminates the need to convert between different time representations and
  reduces code duplication.

- Remove use of Microsoft source-code annotation language (SAL).
  SAL annotations are Microsoft specific and not very well documented. This
  makes it very difficult for contributers to write.

- Rearrange the abstraction layer to be feature-based. The previous layout
  falsely assumed that the operating system dictates which implementation is
  best suited. For general purpose operating systems this is mostly true, but
  embedded targets require a slightly different approach and may not even offer
  all features. The new layout makes it possible to mix-and-match feature
  implementations and allows for features to not be implemented at all.

- Replace the os prefix by ddsrt to avoid name collisions.

- Remove various portions of unused and unwanted code.

- Export thread names on all supported platforms.

- Return native thread identifier on POSIX compatible platforms.

- Add timed wait for condition variables that takes an absolute time.

- Remove system abstraction for errno. The os_getErrno and os_setErrno were
  incorrect. Functions that might fail now simply return a DDS return code
  instead.

- Remove thread-specific memory abstraction. os_threadMemGet and accompanying
  functions were a mess and their use has been eliminated by other changes in
  this commit.

- Replace attribute (re)defines by ddsrt_ prefixed equivalents to avoid name
  collisions and problems with faulty __nonnull__ attributes.

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
2019-03-22 15:19:09 +01:00

233 lines
5.6 KiB
C

/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <stdlib.h>
#if !defined(_WIN32)
#include <sched.h>
#include <unistd.h>
#endif
#include "CUnit/Theory.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/retcode.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/threads.h"
static int32_t min_fifo_prio = 250;
static int32_t max_fifo_prio = 250;
static int32_t max_other_prio = 60;
static int32_t min_other_prio = 250;
CU_Init(ddsrt_thread)
{
ddsrt_init();
#if defined(WIN32)
max_fifo_prio = THREAD_PRIORITY_HIGHEST;
min_fifo_prio = THREAD_PRIORITY_LOWEST;
max_other_prio = THREAD_PRIORITY_HIGHEST;
min_other_prio = THREAD_PRIORITY_LOWEST;
#else
min_fifo_prio = sched_get_priority_min(SCHED_FIFO);
max_fifo_prio = sched_get_priority_max(SCHED_FIFO);
# if !defined(_WRS_KERNEL)
max_other_prio = sched_get_priority_max(SCHED_OTHER);
min_other_prio = sched_get_priority_min(SCHED_OTHER);
# endif
#endif
return 0;
}
CU_Clean(ddsrt_thread)
{
ddsrt_fini();
return 0;
}
typedef struct {
int res;
int ret;
ddsrt_threadattr_t *attr;
} thread_arg_t;
uint32_t thread_main(void *ptr)
{
thread_arg_t *arg = (thread_arg_t *)ptr;
ddsrt_threadattr_t *attr;
assert(arg != NULL);
attr = arg->attr;
#if _WIN32
int prio = GetThreadPriority(GetCurrentThread());
if (prio == THREAD_PRIORITY_ERROR_RETURN)
abort();
if (prio == attr->schedPriority) {
arg->res = 1;
}
#else
int err;
int policy;
struct sched_param sched;
err = pthread_getschedparam(pthread_self(), &policy, &sched);
if (err != 0) {
abort();
}
if (((policy == SCHED_OTHER && attr->schedClass == DDSRT_SCHED_TIMESHARE) ||
(policy == SCHED_FIFO && attr->schedClass == DDSRT_SCHED_REALTIME))
&& (sched.sched_priority == attr->schedPriority))
{
arg->res = 1;
}
#endif
return (uint32_t)arg->ret;
}
CU_TheoryDataPoints(ddsrt_thread, create_and_join) = {
CU_DataPoints(ddsrt_sched_t, DDSRT_SCHED_TIMESHARE, DDSRT_SCHED_TIMESHARE,
DDSRT_SCHED_REALTIME, DDSRT_SCHED_REALTIME),
CU_DataPoints(int32_t *, &min_other_prio, &max_other_prio,
&min_fifo_prio, &max_fifo_prio),
CU_DataPoints(uint32_t, 10101, 20202,
30303, 40404)
};
CU_Theory((ddsrt_sched_t sched, int32_t *prio, uint32_t exp), ddsrt_thread, create_and_join)
{
int skip = 0;
uint32_t res = 50505;
dds_retcode_t ret;
ddsrt_thread_t thr;
ddsrt_threadattr_t attr;
thread_arg_t arg;
#if defined(__VXWORKS__)
# if defined(_WRS_KERNEL)
if (sched == DDSRT_SCHED_TIMESHARE) {
skip = 1;
CU_PASS("VxWorks DKM only supports SCHED_FIFO");
}
# endif
#elif !defined(_WIN32)
if (sched == DDSRT_SCHED_REALTIME && (getuid() != 0 && geteuid() != 0)) {
skip = 1;
CU_PASS("SCHED_FIFO requires root privileges");
}
#endif
if (!skip) {
ddsrt_threadattr_init(&attr);
attr.schedClass = sched;
attr.schedPriority = *prio;
memset(&arg, 0, sizeof(arg));
arg.ret = (int32_t)exp;
arg.attr = &attr;
ret = ddsrt_thread_create(&thr, "thread", &attr, &thread_main, &arg);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
if (ret == DDS_RETCODE_OK) {
ret = ddsrt_thread_join (thr, &res);
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL(res, exp);
if (ret == DDS_RETCODE_OK) {
CU_ASSERT_EQUAL(arg.res, 1);
}
}
}
}
CU_Test(ddsrt_thread, thread_id)
{
int eq = 0;
ddsrt_thread_t thr;
#if defined(_WIN32)
DWORD _tid;
#else
pthread_t _thr;
#endif
thr = ddsrt_thread_self();
#if defined(_WIN32)
_tid = GetCurrentThreadId();
eq = (thr.tid == _tid);
#else
_thr = pthread_self();
eq = pthread_equal(thr.v, _thr);
#endif
CU_ASSERT_NOT_EQUAL(eq, 0);
}
static ddsrt_mutex_t locks[2];
uint32_t thread_main_waitforme(void *ptr)
{
uint32_t ret = 0;
(void)ptr;
ddsrt_mutex_lock(&locks[0]);
ret = 10101;
ddsrt_mutex_unlock(&locks[0]);
return ret;
}
uint32_t thread_main_waitforit(void *ptr)
{
uint32_t res = 0;
ddsrt_thread_t *thr = (ddsrt_thread_t *)ptr;
ddsrt_mutex_lock(&locks[1]);
(void)ddsrt_thread_join(*thr, &res);
ddsrt_mutex_unlock(&locks[1]);
return res + 20202;
}
CU_Test(ddsrt_thread, stacked_join)
{
dds_retcode_t ret;
ddsrt_thread_t thrs[2];
ddsrt_threadattr_t attr;
uint32_t res = 0;
ddsrt_mutex_init(&locks[0]);
ddsrt_mutex_init(&locks[1]);
ddsrt_mutex_lock(&locks[0]);
ddsrt_mutex_lock(&locks[1]);
ddsrt_threadattr_init(&attr);
ret = ddsrt_thread_create(&thrs[0], "", &attr, &thread_main_waitforme, NULL);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ret = ddsrt_thread_create(&thrs[1], "", &attr, &thread_main_waitforit, &thrs[0]);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
ddsrt_mutex_unlock(&locks[1]);
dds_sleepfor(DDS_MSECS(100)); /* 100ms */
ddsrt_mutex_unlock(&locks[0]);
ddsrt_thread_join(thrs[1], &res);
CU_ASSERT_EQUAL(res, 30303);
ddsrt_mutex_destroy(&locks[0]);
ddsrt_mutex_destroy(&locks[1]);
}
CU_Test(ddsrt_thread, attribute)
{
ddsrt_threadattr_t attr;
ddsrt_threadattr_init(&attr);
CU_ASSERT_EQUAL(attr.schedClass, DDSRT_SCHED_DEFAULT);
CU_ASSERT_EQUAL(attr.schedPriority, 0);
CU_ASSERT_EQUAL(attr.stackSize, 0);
}