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>
This commit is contained in:
parent
318968f40f
commit
cd6742ee12
439 changed files with 22117 additions and 28782 deletions
43
src/ddsrt/tests/CMakeLists.txt
Normal file
43
src/ddsrt/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
# 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(CUnit)
|
||||
|
||||
set(sources
|
||||
"atomics.c"
|
||||
"environ.c"
|
||||
"heap.c"
|
||||
"ifaddrs.c"
|
||||
"sync.c"
|
||||
"strtoll.c"
|
||||
"thread.c"
|
||||
"thread_cleanup.c"
|
||||
"string.c"
|
||||
"log.c"
|
||||
"strlcpy.c"
|
||||
"socket.c"
|
||||
"select.c")
|
||||
|
||||
add_cunit_executable(cunit_ddsrt ${sources})
|
||||
target_link_libraries(cunit_ddsrt PRIVATE ddsrt)
|
||||
|
||||
# Create a dummy export header. generate_export_header can only be used with
|
||||
# library targets, but since the targets are linked statically,
|
||||
# __declspec(dllimport) is not required anyway.
|
||||
set(export_dir "${CMAKE_CURRENT_BINARY_DIR}/include/dds")
|
||||
set(export_header "${export_dir}/export.h")
|
||||
if(NOT EXISTS "${export_header}")
|
||||
file(MAKE_DIRECTORY "${export_dir}")
|
||||
file(WRITE "${export_header}" "#define DDS_EXPORT\n")
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
cunit_ddsrt PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
|
393
src/ddsrt/tests/atomics.c
Normal file
393
src/ddsrt/tests/atomics.c
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* 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 "CUnit/Test.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
|
||||
uint32_t _osuint32 = 0;
|
||||
uint64_t _osuint64 = 0;
|
||||
uintptr_t _osaddress = 0;
|
||||
ptrdiff_t _ptrdiff = 0;
|
||||
void * _osvoidp = (uintptr_t *)0;
|
||||
|
||||
CU_Test(ddsrt_atomics, load_store)
|
||||
{
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(5);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(5);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(5);
|
||||
volatile ddsrt_atomic_voidp_t voidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)5);
|
||||
|
||||
/* Test uint32 LD-ST */
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 5); /* Returns contents of uint32 */
|
||||
ddsrt_atomic_st32 (&uint32, _osuint32); /* Writes os_uint32 into uint32 */
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == _osuint32);
|
||||
|
||||
/* Test uint64 LD-ST */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 5);
|
||||
ddsrt_atomic_st64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == _osuint64);
|
||||
#endif
|
||||
|
||||
/* Test uintptr LD-ST */
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 5);
|
||||
ddsrt_atomic_stptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == _osaddress);
|
||||
|
||||
/* Test uintvoidp LD-ST */
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&voidp) == (uintptr_t*)5);
|
||||
ddsrt_atomic_stvoidp (&voidp, _osvoidp);
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&voidp) == (uintptr_t*)_osvoidp);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, compare_and_swap)
|
||||
{
|
||||
/* Compare and Swap if (ptr == expected) { ptr = newval; } */
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(0);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(0);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(0);
|
||||
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)0);
|
||||
_osuint32 = 1;
|
||||
_osuint64 = 1;
|
||||
_osaddress = 1;
|
||||
_osvoidp = (uintptr_t *)1;
|
||||
uint32_t expected = 0, newval = 5;
|
||||
uintptr_t addr_expected = 0, addr_newval = 5;
|
||||
void *void_expected = (uintptr_t*)0;
|
||||
void *void_newval = (uintptr_t*)5;
|
||||
int ret = 0;
|
||||
|
||||
/* Test ddsrt_atomic_cas32 */
|
||||
ret = ddsrt_atomic_cas32 (&uint32, expected, newval);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == newval && ret == 1);
|
||||
ddsrt_atomic_st32 (&uint32, _osuint32);
|
||||
ret = ddsrt_atomic_cas32 (&uint32, expected, newval);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) != newval && ret == 0);
|
||||
|
||||
/* Test ddsrt_atomic_cas64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ret = ddsrt_atomic_cas64 (&uint64, expected, newval);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == newval && ret == 1);
|
||||
ddsrt_atomic_st64 (&uint64, _osuint64);
|
||||
ret = ddsrt_atomic_cas64 (&uint64, expected, newval);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) != newval && ret == 0);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_casptr */
|
||||
ret = ddsrt_atomic_casptr (&uintptr, addr_expected, addr_newval);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == addr_newval && ret == 1);
|
||||
ddsrt_atomic_stptr (&uintptr, _osaddress);
|
||||
ret = ddsrt_atomic_casptr (&uintptr, addr_expected, addr_newval);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) != addr_newval && ret == 0);
|
||||
|
||||
/* Test ddsrt_atomic_casvoidp */
|
||||
ret = ddsrt_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)void_newval && ret == 1);
|
||||
ddsrt_atomic_stvoidp (&uintvoidp, _osvoidp);
|
||||
ret = ddsrt_atomic_casvoidp (&uintvoidp, void_expected, void_newval);
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)1 && ret == 0);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, increment)
|
||||
{
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(0);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(0);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(0);
|
||||
_osuint32 = 0;
|
||||
_osuint64 = 0;
|
||||
_osaddress = 0;
|
||||
_osvoidp = (uintptr_t *)0;
|
||||
|
||||
/* Test os_inc32 */
|
||||
ddsrt_atomic_inc32 (&uint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 1);
|
||||
|
||||
/* Test os_inc64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_inc64 (&uint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 1);
|
||||
#endif
|
||||
|
||||
/* Test os_incptr */
|
||||
ddsrt_atomic_incptr (&uintptr);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 1);
|
||||
|
||||
/* Test ddsrt_atomic_inc32_nv */
|
||||
ddsrt_atomic_st32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_inc32_nv (&uint32) == 1);
|
||||
|
||||
/* Test ddsrt_atomic_inc64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_st64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_inc64_nv (&uint64) == 1);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_incptr_nv */
|
||||
ddsrt_atomic_stptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_incptr_nv(&uintptr) == 1);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, decrement)
|
||||
{
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(1);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(1);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(1);
|
||||
_osuint32 = 1;
|
||||
_osuint64 = 1;
|
||||
_osaddress = 1;
|
||||
_osvoidp = (uintptr_t *)1;
|
||||
|
||||
/* Test ddsrt_atomic_dec32 */
|
||||
ddsrt_atomic_dec32 (&uint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 0);
|
||||
|
||||
/* Test ddsrt_atomic_dec64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_dec64 (&uint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 0);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_decptr */
|
||||
ddsrt_atomic_decptr (&uintptr);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 0);
|
||||
|
||||
/* Test ddsrt_atomic_dec32_nv */
|
||||
ddsrt_atomic_st32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_dec32_nv (&uint32) == 0);
|
||||
|
||||
/* Test ddsrt_atomic_dec64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_st64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_dec64_nv (&uint64) == 0);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_decptr_nv */
|
||||
ddsrt_atomic_stptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_decptr_nv(&uintptr) == 0);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, add)
|
||||
{
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(1);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(1);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(1);
|
||||
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)1);
|
||||
_osuint32 = 2;
|
||||
_osuint64 = 2;
|
||||
_osaddress = 2;
|
||||
_ptrdiff = 2;
|
||||
|
||||
/* Test ddsrt_atomic_add32 */
|
||||
ddsrt_atomic_add32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_add64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_add64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 3);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_addptr */
|
||||
ddsrt_atomic_addptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_addvoidp */
|
||||
ddsrt_atomic_addvoidp (&uintvoidp, _ptrdiff);
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
|
||||
|
||||
/* Test ddsrt_atomic_add32_nv */
|
||||
ddsrt_atomic_st32 (&uint32, 1);
|
||||
CU_ASSERT (ddsrt_atomic_add32_nv (&uint32, _osuint32) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_add64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_st64 (&uint64, 1);
|
||||
CU_ASSERT (ddsrt_atomic_add64_nv (&uint64, _osuint64) == 3);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_addptr_nv */
|
||||
ddsrt_atomic_stptr (&uintptr, 1);
|
||||
CU_ASSERT (ddsrt_atomic_addptr_nv (&uintptr, _osaddress) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_addvoidp_nv */
|
||||
ddsrt_atomic_stvoidp (&uintvoidp, (uintptr_t*)1);
|
||||
CU_ASSERT (ddsrt_atomic_addvoidp_nv (&uintvoidp, _ptrdiff) == (uintptr_t*)3);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, subtract)
|
||||
{
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(5);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(5);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(5);
|
||||
volatile ddsrt_atomic_voidp_t uintvoidp = DDSRT_ATOMIC_VOIDP_INIT((uintptr_t)5);
|
||||
_osuint32 = 2;
|
||||
_osuint64 = 2;
|
||||
_osaddress = 2;
|
||||
_ptrdiff = 2;
|
||||
|
||||
/* Test ddsrt_atomic_sub32 */
|
||||
ddsrt_atomic_sub32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_sub64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_sub64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 3);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_subptr */
|
||||
ddsrt_atomic_subptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_subvoidp */
|
||||
ddsrt_atomic_subvoidp (&uintvoidp, _ptrdiff);
|
||||
CU_ASSERT (ddsrt_atomic_ldvoidp (&uintvoidp) == (uintptr_t*)3);
|
||||
|
||||
/* Test ddsrt_atomic_sub32_nv */
|
||||
ddsrt_atomic_st32 (&uint32, 5);
|
||||
CU_ASSERT (ddsrt_atomic_sub32_nv (&uint32, _osuint32) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_sub64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_st64 (&uint64, 5);
|
||||
CU_ASSERT (ddsrt_atomic_sub64_nv (&uint64, _osuint64) == 3);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_subptr_nv */
|
||||
ddsrt_atomic_stptr (&uintptr, 5);
|
||||
CU_ASSERT (ddsrt_atomic_subptr_nv (&uintptr, _osaddress) == 3);
|
||||
|
||||
/* Test ddsrt_atomic_subvoidp_nv */
|
||||
ddsrt_atomic_stvoidp (&uintvoidp, (uintptr_t*)5);
|
||||
CU_ASSERT (ddsrt_atomic_subvoidp_nv (&uintvoidp, _ptrdiff) == (void *)3);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, and)
|
||||
{
|
||||
/* AND Operation:
|
||||
|
||||
150 010010110
|
||||
500 111110100
|
||||
|
||||
148 010010100 */
|
||||
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(150);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(150);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(150);
|
||||
_osuint32 = 500;
|
||||
_osuint64 = 500;
|
||||
_osaddress = 500;
|
||||
|
||||
/* Test ddsrt_atomic_and32 */
|
||||
ddsrt_atomic_and32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 148);
|
||||
|
||||
/* Test ddsrt_atomic_and64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_and64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 148);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_andptr */
|
||||
ddsrt_atomic_andptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 148);
|
||||
|
||||
/* Test ddsrt_atomic_and32_ov */
|
||||
CU_ASSERT (ddsrt_atomic_and32_ov (&uint32, _osuint32) == 148);
|
||||
|
||||
/* Test ddsrt_atomic_and64_ov */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
CU_ASSERT (ddsrt_atomic_and64_ov (&uint64, _osuint64) == 148);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_andptr_ov */
|
||||
CU_ASSERT (ddsrt_atomic_andptr_ov (&uintptr, _osaddress) == 148);
|
||||
|
||||
/* Test ddsrt_atomic_and32_nv */
|
||||
CU_ASSERT (ddsrt_atomic_and32_nv (&uint32, _osuint32) == 148);
|
||||
|
||||
/* Test ddsrt_atomic_and64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
CU_ASSERT (ddsrt_atomic_and64_nv (&uint64, _osuint64) == 148);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_andptr_nv */
|
||||
CU_ASSERT (ddsrt_atomic_andptr_nv (&uintptr, _osaddress) == 148);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_atomics, or)
|
||||
{
|
||||
/* OR Operation:
|
||||
|
||||
150 010010110
|
||||
500 111110100
|
||||
|
||||
502 111110110 */
|
||||
|
||||
volatile ddsrt_atomic_uint32_t uint32 = DDSRT_ATOMIC_UINT32_INIT(150);
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
volatile ddsrt_atomic_uint64_t uint64 = DDSRT_ATOMIC_UINT64_INIT(150);
|
||||
#endif
|
||||
volatile ddsrt_atomic_uintptr_t uintptr = DDSRT_ATOMIC_UINTPTR_INIT(150);
|
||||
_osuint32 = 500;
|
||||
_osuint64 = 500;
|
||||
_osaddress = 500;
|
||||
|
||||
/* Test ddsrt_atomic_or32 */
|
||||
ddsrt_atomic_or32 (&uint32, _osuint32);
|
||||
CU_ASSERT (ddsrt_atomic_ld32 (&uint32) == 502);
|
||||
|
||||
/* Test ddsrt_atomic_or64 */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
ddsrt_atomic_or64 (&uint64, _osuint64);
|
||||
CU_ASSERT (ddsrt_atomic_ld64 (&uint64) == 502);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_orptr */
|
||||
ddsrt_atomic_orptr (&uintptr, _osaddress);
|
||||
CU_ASSERT (ddsrt_atomic_ldptr (&uintptr) == 502);
|
||||
|
||||
/* Test ddsrt_atomic_or32_ov */
|
||||
CU_ASSERT (ddsrt_atomic_or32_ov (&uint32, _osuint32) == 502);
|
||||
|
||||
/* Test ddsrt_atomic_or64_ov */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
CU_ASSERT (ddsrt_atomic_or64_ov (&uint64, _osuint64) == 502);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_orptr_ov */
|
||||
CU_ASSERT (ddsrt_atomic_orptr_ov (&uintptr, _osaddress) == 502);
|
||||
|
||||
/* Test ddsrt_atomic_or32_nv */
|
||||
CU_ASSERT (ddsrt_atomic_or32_nv (&uint32, _osuint32) == 502);
|
||||
|
||||
/* Test ddsrt_atomic_or64_nv */
|
||||
#if DDSRT_HAVE_ATOMIC64
|
||||
CU_ASSERT (ddsrt_atomic_or64_nv (&uint64, _osuint64) == 502);
|
||||
#endif
|
||||
|
||||
/* Test ddsrt_atomic_orptr_nv */
|
||||
CU_ASSERT (ddsrt_atomic_orptr_nv (&uintptr, _osaddress) == 502);
|
||||
}
|
98
src/ddsrt/tests/environ.c
Normal file
98
src/ddsrt/tests/environ.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/environ.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_environ, bad_name) = {
|
||||
CU_DataPoints(const char *, "", "foo=")
|
||||
};
|
||||
|
||||
CU_Theory((const char *name), ddsrt_environ, bad_name)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
static const char value[] = "bar";
|
||||
static char dummy[] = "foobar";
|
||||
char *ptr;
|
||||
|
||||
rc = ddsrt_setenv(name, value);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
|
||||
rc = ddsrt_unsetenv(name);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
|
||||
ptr = dummy;
|
||||
rc = ddsrt_getenv(name, &ptr);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
|
||||
CU_ASSERT_PTR_EQUAL(ptr, dummy);
|
||||
}
|
||||
|
||||
DDSRT_WARNING_MSVC_OFF(4996)
|
||||
CU_Test(ddsrt_environ, setenv)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
static const char name[] = "foo";
|
||||
static char value[] = "bar";
|
||||
char *ptr;
|
||||
|
||||
rc = ddsrt_setenv(name, value);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
ptr = getenv(name);
|
||||
CU_ASSERT_PTR_NOT_NULL(ptr);
|
||||
CU_ASSERT_STRING_EQUAL(ptr, "bar");
|
||||
/* Ensure value is copied into the environment. */
|
||||
value[2] = 'z';
|
||||
ptr = getenv(name);
|
||||
CU_ASSERT_PTR_NOT_NULL(ptr);
|
||||
CU_ASSERT_STRING_EQUAL(ptr, "bar");
|
||||
rc = ddsrt_setenv(name, "");
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
ptr = getenv(name);
|
||||
CU_ASSERT_PTR_NULL(ptr);
|
||||
}
|
||||
DDSRT_WARNING_MSVC_ON(4996)
|
||||
|
||||
CU_Test(ddsrt_environ, getenv)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
static const char name[] = "foo";
|
||||
static const char value[] = "bar";
|
||||
static char dummy[] = "foobar";
|
||||
char *ptr;
|
||||
|
||||
/* Ensure "not found" is returned. */
|
||||
rc = ddsrt_unsetenv(name);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
ptr = dummy;
|
||||
rc = ddsrt_getenv(name, &ptr);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_FOUND);
|
||||
CU_ASSERT_PTR_EQUAL(ptr, dummy);
|
||||
|
||||
/* Ensure "ok" is returned and value is what it should be. */
|
||||
rc = ddsrt_setenv(name, value);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
ptr = dummy;
|
||||
rc = ddsrt_getenv(name, &ptr);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(ptr, dummy);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL);
|
||||
if (ptr != NULL) {
|
||||
CU_ASSERT_STRING_EQUAL(ptr, "bar");
|
||||
}
|
||||
|
||||
/* Ensure environement is as it was. */
|
||||
rc = ddsrt_unsetenv(name);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
}
|
||||
|
156
src/ddsrt/tests/heap.c
Normal file
156
src/ddsrt/tests/heap.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include "CUnit/Test.h"
|
||||
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
|
||||
CU_Init(ddsrt_heap)
|
||||
{
|
||||
ddsrt_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddsrt_heap)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const size_t allocsizes[] = {0, 1, 2, 3, 4, 5, 10, 20, 257, 1024};
|
||||
static const size_t nof_allocsizes = sizeof allocsizes / sizeof *allocsizes;
|
||||
|
||||
CU_Test(ddsrt_heap, malloc)
|
||||
{
|
||||
for(size_t i = 0; i < nof_allocsizes; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes; j++) {
|
||||
size_t s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
|
||||
void *ptr = ddsrt_malloc(s);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_malloc is supposed to abort on failure */
|
||||
memset(ptr, 0, s); /* This potentially segfaults if the actual allocated block is too small */
|
||||
ddsrt_free(ptr);
|
||||
}
|
||||
}
|
||||
CU_PASS("ddsrt_malloc");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_heap, calloc)
|
||||
{
|
||||
for(size_t i = 0; i < nof_allocsizes; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes; j++) {
|
||||
char *ptr = ddsrt_calloc(allocsizes[i], allocsizes[j]);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_calloc is supposed to abort on failure */
|
||||
if(allocsizes[i] * allocsizes[j] > 0) {
|
||||
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, (allocsizes[i] * allocsizes[j]) - 1)); /* ddsrt_calloc should memset properly */
|
||||
}
|
||||
ddsrt_free(ptr);
|
||||
}
|
||||
}
|
||||
CU_PASS("ddsrt_calloc");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_heap, realloc)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
size_t unchanged, s, prevs = 0;
|
||||
|
||||
for(size_t i = 0; i < nof_allocsizes; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes; j++) {
|
||||
s = allocsizes[i] * allocsizes[j]; /* Allocates up to 1MB */
|
||||
printf("ddsrt_realloc(%p) %zu -> %zu\n", ptr, prevs, s);
|
||||
ptr = ddsrt_realloc(ptr, s);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(ptr, NULL); /* ddsrt_realloc is supposed to abort on failure */
|
||||
unchanged = (prevs < s) ? prevs : s;
|
||||
if(unchanged) {
|
||||
CU_ASSERT (ptr[0] == 1 && !memcmp(ptr, ptr + 1, unchanged - 1)); /* ddsrt_realloc shouldn't change memory */
|
||||
}
|
||||
memset(ptr, 1, s); /* This potentially segfaults if the actual allocated block is too small */
|
||||
prevs = s;
|
||||
}
|
||||
}
|
||||
ddsrt_free(ptr);
|
||||
CU_PASS("ddsrt_realloc");
|
||||
}
|
||||
|
||||
static const size_t allocsizes_s[] = {0, 1, 2, 3, 4, 5, 10, 20, 257, 1024, 8192};
|
||||
static const size_t nof_allocsizes_s = sizeof allocsizes_s / sizeof *allocsizes_s;
|
||||
|
||||
CU_Test(ddsrt_heap, malloc_s)
|
||||
{
|
||||
for(size_t i = 0; i < nof_allocsizes_s; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes_s; j++) {
|
||||
size_t s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
|
||||
void *ptr = ddsrt_malloc_s(s); /* If s == 0, ddsrt_malloc_s should still return a pointer */
|
||||
if(ptr) {
|
||||
memset(ptr, 0, s); /* This potentially segfaults if the actual allocated block is too small */
|
||||
} else if (s <= 16) {
|
||||
/* Failure to allocate can't be considered a test fault really,
|
||||
* except that a malloc(<=16) would fail is unlikely. */
|
||||
CU_FAIL("ddsrt_malloc_s(<=16) returned NULL");
|
||||
}
|
||||
ddsrt_free(ptr);
|
||||
}
|
||||
}
|
||||
CU_PASS("ddsrt_malloc_s");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_heap, calloc_s)
|
||||
{
|
||||
for(size_t i = 0; i < nof_allocsizes_s; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes_s; j++) {
|
||||
size_t s = allocsizes_s[i] * allocsizes_s[j];
|
||||
char *ptr = ddsrt_calloc_s(allocsizes_s[i], allocsizes_s[j]); /* If either one is 0, ddsrt_calloc_s should still return a pointer */
|
||||
if(ptr) {
|
||||
if(s) {
|
||||
CU_ASSERT (ptr[0] == 0 && !memcmp(ptr, ptr + 1, s - 1)); /* malloc_0_s should memset properly */
|
||||
}
|
||||
} else if (s <= 16) {
|
||||
/* Failure to allocate can't be considered a test fault really,
|
||||
* except that a calloc(<=16) would fail is unlikely. */
|
||||
CU_FAIL("ddsrt_calloc_s(<=16) returned NULL");
|
||||
}
|
||||
ddsrt_free(ptr);
|
||||
}
|
||||
}
|
||||
CU_PASS("ddsrt_calloc_s");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_heap, ddsrt_realloc_s)
|
||||
{
|
||||
char *newptr, *ptr = NULL;
|
||||
size_t unchanged, s, prevs = 0;
|
||||
|
||||
for(size_t i = 0; i < nof_allocsizes_s; i++) {
|
||||
for(size_t j = 0; j < nof_allocsizes_s; j++) {
|
||||
s = allocsizes_s[i] * allocsizes_s[j]; /* Allocates up to 8MB */
|
||||
newptr = ddsrt_realloc_s(ptr, s);
|
||||
printf("%p = ddsrt_realloc_s(%p) %zu -> %zu\n", newptr, ptr, prevs, s);
|
||||
if (s <= 16) {
|
||||
/* Failure to allocate can't be considered a test fault really,
|
||||
* except that a ddsrt_realloc_s(0 < s <=16) would fail is unlikely. */
|
||||
CU_ASSERT_PTR_NOT_EQUAL(newptr, NULL);
|
||||
}
|
||||
if(newptr){
|
||||
unchanged = (prevs < s) ? prevs : s;
|
||||
if(unchanged) {
|
||||
CU_ASSERT (newptr[0] == 1 && !memcmp(newptr, newptr + 1, unchanged - 1)); /* ddsrt_realloc_s shouldn't change memory */
|
||||
}
|
||||
memset(newptr, 1, s); /* This potentially segfaults if the actual allocated block is too small */
|
||||
}
|
||||
prevs = s;
|
||||
ptr = newptr;
|
||||
}
|
||||
}
|
||||
ddsrt_free(ptr);
|
||||
CU_PASS("ddsrt_realloc_s");
|
||||
}
|
187
src/ddsrt/tests/ifaddrs.c
Normal file
187
src/ddsrt/tests/ifaddrs.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* 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 "CUnit/Test.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/ifaddrs.h"
|
||||
#include "dds/ddsrt/retcode.h"
|
||||
|
||||
/* FIXME: It's not possible to predict what network interfaces are available
|
||||
on a given host. To properly test all combinations the abstracted
|
||||
operating system functions must be mocked. */
|
||||
|
||||
/* FIXME: It's possible that IPv6 is available in the network stack, but
|
||||
disabled in the kernel. Travis CI for example has build environments
|
||||
that do not have IPv6 enabled. */
|
||||
|
||||
#ifdef DDSRT_HAVE_IPV6
|
||||
static int ipv6_enabled = 1;
|
||||
#endif
|
||||
|
||||
CU_Init(ddsrt_getifaddrs)
|
||||
{
|
||||
ddsrt_init();
|
||||
|
||||
#ifdef DDSRT_HAVE_IPV6
|
||||
#ifdef __linux
|
||||
FILE *fh;
|
||||
const char *const *path;
|
||||
static const char *const paths[] = {
|
||||
"/proc/sys/net/ipv6/conf/all/disable_ipv6",
|
||||
"/proc/sys/net/ipv6/conf/default/disable_ipv6",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (path = paths; ipv6_enabled == 1 && *path != NULL; path++) {
|
||||
if ((fh = fopen(*path, "r")) != NULL) {
|
||||
ipv6_enabled = (fgetc(fh) == '0');
|
||||
fclose(fh);
|
||||
fh = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* __linux */
|
||||
#endif /* DDSRT_HAVE_IPV6 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddsrt_getifaddrs)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume every test machine has at least one IPv4 enabled interface. This
|
||||
simple test verifies an interface can at least be found and that the
|
||||
IFF_LOOPBACK flags are properly set. */
|
||||
CU_Test(ddsrt_getifaddrs, ipv4)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
int seen = 0;
|
||||
ddsrt_ifaddrs_t *ifa_root, *ifa;
|
||||
const int afs[] = { AF_INET, DDSRT_AF_TERM };
|
||||
|
||||
ret = ddsrt_getifaddrs(&ifa_root, afs);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
for (ifa = ifa_root; ifa; ifa = ifa->next) {
|
||||
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
|
||||
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET);
|
||||
if (ifa->addr->sa_family == AF_INET) {
|
||||
if (ifa->flags & IFF_LOOPBACK) {
|
||||
CU_ASSERT(ddsrt_sockaddr_isloopback(ifa->addr));
|
||||
} else {
|
||||
CU_ASSERT(!ddsrt_sockaddr_isloopback(ifa->addr));
|
||||
}
|
||||
seen = 1;
|
||||
}
|
||||
}
|
||||
|
||||
CU_ASSERT_EQUAL(seen, 1);
|
||||
ddsrt_freeifaddrs(ifa_root);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_getifaddrs, null_filter)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
int cnt = 0;
|
||||
ddsrt_ifaddrs_t *ifa_root, *ifa;
|
||||
|
||||
ret = ddsrt_getifaddrs(&ifa_root, NULL);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
for (ifa = ifa_root; ifa; ifa = ifa->next) {
|
||||
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
CU_ASSERT(cnt > 0);
|
||||
ddsrt_freeifaddrs(ifa_root);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_getifaddrs, empty_filter)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
ddsrt_ifaddrs_t *ifa_root;
|
||||
const int afs[] = { DDSRT_AF_TERM };
|
||||
|
||||
ret = ddsrt_getifaddrs(&ifa_root, afs);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_PTR_EQUAL(ifa_root, NULL);
|
||||
ddsrt_freeifaddrs(ifa_root);
|
||||
}
|
||||
|
||||
#ifdef DDSRT_HAVE_IPV6
|
||||
CU_Test(ddsrt_getifaddrs, ipv6)
|
||||
{
|
||||
if (ipv6_enabled == 1) {
|
||||
dds_retcode_t ret;
|
||||
int have_ipv6 = 0;
|
||||
ddsrt_ifaddrs_t *ifa_root, *ifa;
|
||||
const int afs[] = { AF_INET6, DDSRT_AF_TERM };
|
||||
|
||||
ret = ddsrt_getifaddrs(&ifa_root, afs);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
for (ifa = ifa_root; ifa; ifa = ifa->next) {
|
||||
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
|
||||
CU_ASSERT_EQUAL(ifa->addr->sa_family, AF_INET6);
|
||||
if (ifa->addr->sa_family == AF_INET6) {
|
||||
have_ipv6 = 1;
|
||||
/* macOS assigns a link-local address to the loopback interface, so
|
||||
the loopback address must be assigned to the loopback interface,
|
||||
but the loopback interface can have addresses other than the
|
||||
loopback address assigned. */
|
||||
if (ddsrt_sockaddr_isloopback(ifa->addr)) {
|
||||
CU_ASSERT(ifa->flags & IFF_LOOPBACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CU_ASSERT_EQUAL(have_ipv6, 1);
|
||||
ddsrt_freeifaddrs(ifa_root);
|
||||
CU_PASS("IPv6 enabled in test environment");
|
||||
} else {
|
||||
CU_PASS("IPv6 disabled in test environment");
|
||||
}
|
||||
}
|
||||
|
||||
/* Assume at least one IPv4 and one IPv6 interface are available when IPv6 is
|
||||
available on the platform. */
|
||||
CU_Test(ddsrt_getifaddrs, ipv4_n_ipv6)
|
||||
{
|
||||
if (ipv6_enabled == 1) {
|
||||
dds_retcode_t ret;
|
||||
int have_ipv4 = 0;
|
||||
int have_ipv6 = 0;
|
||||
ddsrt_ifaddrs_t *ifa_root, *ifa;
|
||||
const int afs[] = { AF_INET, AF_INET6, DDSRT_AF_TERM };
|
||||
|
||||
ret = ddsrt_getifaddrs(&ifa_root, afs);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
for (ifa = ifa_root; ifa; ifa = ifa->next) {
|
||||
CU_ASSERT_PTR_NOT_EQUAL_FATAL(ifa->addr, NULL);
|
||||
CU_ASSERT(ifa->addr->sa_family == AF_INET ||
|
||||
ifa->addr->sa_family == AF_INET6);
|
||||
if (ifa->addr->sa_family == AF_INET) {
|
||||
have_ipv4 = 1;
|
||||
} else if (ifa->addr->sa_family == AF_INET6) {
|
||||
have_ipv6 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
CU_ASSERT_EQUAL(have_ipv4, 1);
|
||||
CU_ASSERT_EQUAL(have_ipv6, 1);
|
||||
ddsrt_freeifaddrs(ifa_root);
|
||||
CU_PASS("IPv6 enabled in test environment");
|
||||
} else {
|
||||
CU_PASS("IPv6 disabled in test environment");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DDSRT_HAVE_IPV6 */
|
366
src/ddsrt/tests/log.c
Normal file
366
src/ddsrt/tests/log.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <pthread.h>
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#include "CUnit/Test.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds/ddsrt/log.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/string.h"
|
||||
#include "dds/ddsrt/sync.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
|
||||
static FILE *fh = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
|
||||
/* Windows does not support opening a stream to a buffer like fmemopen on
|
||||
* Linux does. A temporary file that will never be flushed to disk is created
|
||||
* instead. See the link below for more detail.
|
||||
*
|
||||
* https://blogs.msdn.microsoft.com/larryosterman/2004/04/19/its-only-temporary/
|
||||
*/
|
||||
|
||||
FILE *fmemopen(void *buf, size_t size, const char *mode)
|
||||
{
|
||||
int err = 0;
|
||||
int fd = -1;
|
||||
DWORD ret;
|
||||
FILE *fh = NULL;
|
||||
HANDLE hdl = INVALID_HANDLE_VALUE;
|
||||
/* GetTempFileName will fail if the directory is be longer than MAX_PATH-14
|
||||
characters */
|
||||
char tmpdir[(MAX_PATH + 1) - 14];
|
||||
char tmpfile[MAX_PATH + 1];
|
||||
static const int max = 1000;
|
||||
static const char pfx[] = "cyclone"; /* Up to first three are used. */
|
||||
|
||||
(void)buf;
|
||||
(void)size;
|
||||
|
||||
ret = GetTempPath(sizeof(tmpdir), tmpdir);
|
||||
if (ret == 0) {
|
||||
err = GetLastError();
|
||||
} else if (ret > sizeof(tmpdir)) {
|
||||
err = ENOMEM;
|
||||
}
|
||||
|
||||
if (GetTempFileName(tmpdir, pfx, 0, tmpfile) == 0) {
|
||||
err = GetLastError();
|
||||
assert(err != ERROR_BUFFER_OVERFLOW);
|
||||
} else {
|
||||
/* The combination of FILE_ATTRIBUTE_TEMPORARY and
|
||||
FILE_FLAG_DELETE_ON_CLOSE hints to the filesystem that the file should
|
||||
never be flushed to disk. */
|
||||
hdl = CreateFile(
|
||||
tmpfile,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY,
|
||||
NULL);
|
||||
if (hdl == INVALID_HANDLE_VALUE) {
|
||||
err = GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
errno = err;
|
||||
} else {
|
||||
DDSRT_WARNING_MSVC_OFF(4996);
|
||||
if ((fd = _open_osfhandle((intptr_t)hdl, _O_APPEND)) == -1) {
|
||||
/* errno set by _open_osfhandle. */
|
||||
CloseHandle(hdl);
|
||||
} else if ((fh = fdopen(fd, mode)) == NULL) {
|
||||
/* errno set by fdopen. */
|
||||
_close(fd); /* Automatically closes underlying handle. */
|
||||
} else {
|
||||
return fh;
|
||||
}
|
||||
DDSRT_WARNING_MSVC_ON(4996);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static void count(void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
(void)data;
|
||||
*(int *)ptr += 1;
|
||||
}
|
||||
|
||||
static void copy(void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
*(char **)ptr = ddsrt_strdup(data->message);
|
||||
}
|
||||
|
||||
static void setup(void)
|
||||
{
|
||||
fh = fmemopen(NULL, 1024, "wb+");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(fh);
|
||||
}
|
||||
|
||||
static void teardown(void)
|
||||
{
|
||||
(void)fclose(fh);
|
||||
}
|
||||
|
||||
/* By default only DDS_LC_FATAL and DDS_LC_ERROR are set. This means setting a
|
||||
trace sink should not have any effect, because no trace categories are
|
||||
enabled. The message should end up in the log file. */
|
||||
CU_Test(dds_log, only_log_file, .init=setup, .fini=teardown)
|
||||
{
|
||||
char buf[1024], *ptr;
|
||||
int cnt = 0;
|
||||
size_t nbytes;
|
||||
|
||||
dds_set_log_file(fh);
|
||||
dds_set_trace_sink(&count, &cnt);
|
||||
DDS_ERROR("foo%s\n", "bar");
|
||||
(void)fseek(fh, 0L, SEEK_SET);
|
||||
nbytes = fread(buf, 1, sizeof(buf) - 1, fh);
|
||||
/* At least foobar should have been printed to the log file. */
|
||||
CU_ASSERT_FATAL(nbytes > 6);
|
||||
buf[nbytes] = '\0';
|
||||
ptr = strstr(buf, "foobar\n");
|
||||
CU_ASSERT_PTR_NOT_NULL(ptr);
|
||||
/* No trace categories are enabled by default, verify trace callback was
|
||||
not invoked. */
|
||||
CU_ASSERT_EQUAL(cnt, 0);
|
||||
}
|
||||
|
||||
/* Messages must be printed to the trace file if at least one trace category
|
||||
is enabled. Messages must not be written twice if the trace file is the
|
||||
same as the log file. */
|
||||
CU_Test(dds_log, same_file, .init=setup, .fini=teardown)
|
||||
{
|
||||
char buf[1024], *ptr;
|
||||
size_t nbytes;
|
||||
|
||||
dds_set_log_mask(DDS_LC_ALL);
|
||||
dds_set_log_file(fh);
|
||||
dds_set_trace_file(fh);
|
||||
DDS_ERROR("foo%s\n", "bar");
|
||||
(void)fseek(fh, 0L, SEEK_SET);
|
||||
nbytes = fread(buf, 1, sizeof(buf) - 1, fh);
|
||||
/* At least foobar should have been written to the trace file. */
|
||||
CU_ASSERT_FATAL(nbytes > 6);
|
||||
buf[nbytes] = '\0';
|
||||
ptr = strstr(buf, "foobar\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
|
||||
/* The message should only have been printed once, verify foobar does not
|
||||
occur again. */
|
||||
ptr = strstr(ptr + 1, "foobar\n");
|
||||
CU_ASSERT_PTR_NULL(ptr);
|
||||
}
|
||||
|
||||
/* The sinks are considered to be the same only if the callback and userdata
|
||||
both are an exact match. If the userdata is different, the function should
|
||||
be called twice for log messages. */
|
||||
CU_Test(dds_log, same_sink_function)
|
||||
{
|
||||
int log_cnt = 0, trace_cnt = 0;
|
||||
|
||||
dds_set_log_mask(DDS_LC_ALL);
|
||||
dds_set_log_sink(&count, &log_cnt);
|
||||
dds_set_trace_sink(&count, &trace_cnt);
|
||||
DDS_ERROR("foo%s\n", "bar");
|
||||
CU_ASSERT_EQUAL(log_cnt, 1);
|
||||
CU_ASSERT_EQUAL(trace_cnt, 1);
|
||||
}
|
||||
|
||||
CU_Test(dds_log, exact_same_sink)
|
||||
{
|
||||
int cnt = 0;
|
||||
|
||||
dds_set_log_mask(DDS_LC_ALL);
|
||||
dds_set_log_sink(&count, &cnt);
|
||||
dds_set_trace_sink(&count, &cnt);
|
||||
DDS_ERROR("foo%s\n", "bar");
|
||||
CU_ASSERT_EQUAL(cnt, 1);
|
||||
}
|
||||
|
||||
/* The log file must be restored if the sink is unregistered, verify the log
|
||||
file is not used while the sink is registered. Verify use of the log file is
|
||||
restored again when the sink is unregistered. */
|
||||
CU_Test(dds_log, no_sink, .init=setup, .fini=teardown)
|
||||
{
|
||||
int ret;
|
||||
char buf[1024], *ptr = NULL;
|
||||
size_t cnt[2] = {0, 0};
|
||||
|
||||
/* Set the destination log file and verify the message is written. */
|
||||
dds_set_log_file(fh);
|
||||
DDS_ERROR("foobar\n");
|
||||
ret = fseek(fh, 0L, SEEK_SET);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 0);
|
||||
buf[0] = '\0';
|
||||
cnt[0] = fread(buf, 1, sizeof(buf) - 1, fh);
|
||||
buf[cnt[0]] = '\0';
|
||||
ptr = strstr(buf, "foobar\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
|
||||
|
||||
/* Register a custom sink and verify it receives the message. */
|
||||
ptr = NULL;
|
||||
dds_set_log_sink(©, &ptr);
|
||||
DDS_ERROR("foobaz\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
|
||||
CU_ASSERT(strcmp(ptr, "foobaz\n") == 0);
|
||||
ddsrt_free(ptr);
|
||||
ptr = NULL;
|
||||
/* Verify it has not been written to the stream. */
|
||||
ret = fseek(fh, 0L, SEEK_SET);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 0);
|
||||
buf[0] = '\0';
|
||||
cnt[1] = fread(buf, 1, sizeof(buf) - 1, fh);
|
||||
buf[cnt[1]] = '\0';
|
||||
ptr = strstr(buf, "foobaz\n");
|
||||
CU_ASSERT_PTR_NULL_FATAL(ptr);
|
||||
|
||||
/* Unregister the custom sink and verify the default is restored. */
|
||||
dds_set_log_sink(0, NULL);
|
||||
ret = fseek(fh, 0, SEEK_SET);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, 0);
|
||||
ptr = NULL;
|
||||
DDS_ERROR("foobaz\n");
|
||||
ret = fseek(fh, 0, SEEK_SET);
|
||||
CU_ASSERT_PTR_NULL(ptr);
|
||||
if (ptr != NULL) {
|
||||
ddsrt_free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
buf[0]= '\0';
|
||||
cnt[1] = fread(buf, 1, sizeof(buf) - 1, fh);
|
||||
#ifdef _WIN32
|
||||
/* Write on Windows appends. */
|
||||
CU_ASSERT_EQUAL(cnt[1], cnt[0] * 2);
|
||||
#else
|
||||
CU_ASSERT_EQUAL(cnt[1], cnt[0]);
|
||||
#endif
|
||||
buf[cnt[1]] = '\0';
|
||||
ptr = strstr(buf, "foobaz\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(ptr);
|
||||
}
|
||||
|
||||
/* A newline terminates the message. Until that a newline is encountered, the
|
||||
messages must be concatenated in the buffer. The newline is replaced by a
|
||||
NULL byte if it is flushed to a sink. */
|
||||
CU_Test(dds_log, newline_terminates)
|
||||
{
|
||||
char *msg = NULL;
|
||||
|
||||
dds_set_log_sink(©, &msg);
|
||||
DDS_ERROR("foo");
|
||||
CU_ASSERT_PTR_NULL_FATAL(msg);
|
||||
DDS_ERROR("bar");
|
||||
CU_ASSERT_PTR_NULL_FATAL(msg);
|
||||
DDS_ERROR("baz\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
|
||||
CU_ASSERT(strcmp(msg, "foobarbaz\n") == 0);
|
||||
ddsrt_free(msg);
|
||||
}
|
||||
|
||||
/* Nothing must be written unless a category is enabled. */
|
||||
CU_Test(dds_log, disabled_categories_discarded)
|
||||
{
|
||||
char *msg = NULL;
|
||||
|
||||
dds_set_log_sink(©, &msg);
|
||||
DDS_INFO("foobar\n");
|
||||
CU_ASSERT_PTR_NULL_FATAL(msg);
|
||||
dds_set_log_mask(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_INFO);
|
||||
DDS_INFO("foobar\n");
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
|
||||
CU_ASSERT(strcmp(msg, "foobar\n") == 0);
|
||||
ddsrt_free(msg);
|
||||
}
|
||||
|
||||
|
||||
static ddsrt_cond_t cond;
|
||||
static ddsrt_mutex_t mutex;
|
||||
|
||||
struct arg {
|
||||
ddsrt_cond_t *cond;
|
||||
ddsrt_mutex_t *mutex;
|
||||
dds_time_t stamp;
|
||||
dds_duration_t pause;
|
||||
};
|
||||
|
||||
static void dummy(void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)data;
|
||||
}
|
||||
|
||||
static void block(void *ptr, const dds_log_data_t *data)
|
||||
{
|
||||
(void)data;
|
||||
struct arg *arg = (struct arg *)ptr;
|
||||
ddsrt_mutex_lock(arg->mutex);
|
||||
arg->stamp = dds_time();
|
||||
ddsrt_cond_broadcast(arg->cond);
|
||||
ddsrt_mutex_unlock(arg->mutex);
|
||||
dds_sleepfor(arg->pause);
|
||||
}
|
||||
|
||||
static uint32_t run(void *ptr)
|
||||
{
|
||||
(void)ptr;
|
||||
|
||||
DDS_ERROR("foobar\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Log and trace sinks can be changed at runtime. However, the operation must
|
||||
be synchronous! Verify the dds_set_log_sink blocks while other threads
|
||||
reside in the log or trace sinks. */
|
||||
CU_Test(dds_log, synchronous_sink_changes)
|
||||
{
|
||||
struct arg arg;
|
||||
dds_time_t diff, stamp;
|
||||
ddsrt_thread_t tid;
|
||||
ddsrt_threadattr_t tattr;
|
||||
dds_retcode_t ret;
|
||||
|
||||
ddsrt_mutex_init(&mutex);
|
||||
ddsrt_cond_init(&cond);
|
||||
(void)memset(&arg, 0, sizeof(arg));
|
||||
arg.mutex = &mutex;
|
||||
arg.cond = &cond;
|
||||
arg.pause = 1000000;
|
||||
|
||||
ddsrt_mutex_lock(&mutex);
|
||||
dds_set_log_sink(&block, &arg);
|
||||
ddsrt_threadattr_init(&tattr);
|
||||
ret = ddsrt_thread_create(&tid, "foobar", &tattr, &run, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
ddsrt_cond_wait(&cond, &mutex);
|
||||
dds_set_log_sink(dummy, NULL);
|
||||
stamp = dds_time();
|
||||
|
||||
CU_ASSERT(arg.stamp < stamp);
|
||||
diff = stamp - arg.stamp;
|
||||
CU_ASSERT(arg.pause < diff);
|
||||
}
|
325
src/ddsrt/tests/select.c
Normal file
325
src/ddsrt/tests/select.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* 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 "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/sockets_priv.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
|
||||
CU_Init(ddsrt_select)
|
||||
{
|
||||
ddsrt_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddsrt_select)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct timeval tv_init = { .tv_sec = -2, .tv_usec = -2 };
|
||||
|
||||
#define CU_ASSERT_TIMEVAL_EQUAL(tv, secs, usecs) \
|
||||
CU_ASSERT((tv.tv_sec == secs) && (tv.tv_usec == usecs))
|
||||
|
||||
/* Simple test to validate that duration to timeval conversion is correct. */
|
||||
CU_Test(ddsrt_select, duration_to_timeval)
|
||||
{
|
||||
struct timeval tv, *tvptr;
|
||||
dds_duration_t nsecs_max;
|
||||
dds_duration_t secs_max = DDSRT_MAX_INTEGER(ddsrt_tv_sec_t);
|
||||
dds_duration_t usecs_max = 999999;
|
||||
|
||||
if (DDS_INFINITY > secs_max) {
|
||||
CU_ASSERT_EQUAL_FATAL(secs_max, INT32_MAX);
|
||||
nsecs_max = DDS_INFINITY * secs_max;
|
||||
} else {
|
||||
CU_ASSERT_EQUAL_FATAL(secs_max, DDS_INFINITY);
|
||||
nsecs_max = DDS_INFINITY / DDS_NSECS_IN_SEC;
|
||||
}
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(INT64_MIN, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(INT64_MIN + 1, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(-2, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(-1, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(0, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max - 1, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(nsecs_max + 1, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(DDS_INFINITY - 1, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, &tv);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, secs_max, usecs_max);
|
||||
|
||||
tv = tv_init;
|
||||
tvptr = ddsrt_duration_to_timeval_ceil(DDS_INFINITY, &tv);
|
||||
CU_ASSERT_PTR_EQUAL(tvptr, NULL);
|
||||
CU_ASSERT_TIMEVAL_EQUAL(tv, 0, 0);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
dds_duration_t delay;
|
||||
dds_duration_t skew;
|
||||
ddsrt_socket_t sock;
|
||||
} thread_arg_t;
|
||||
|
||||
static void
|
||||
sockets_pipe(ddsrt_socket_t socks[2])
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_socket_t sock;
|
||||
int reuseaddr = 1;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
addr.sin_port = htons(54321);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL_FATAL(socks);
|
||||
rc = ddsrt_socket(&sock, AF_INET, SOCK_STREAM, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_setsockopt(
|
||||
sock, SOL_SOCKET, SO_REUSEADDR, (void*)&reuseaddr, sizeof(reuseaddr));
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_socket(&socks[1], AF_INET, SOCK_STREAM, 0);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_bind(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_listen(sock, 1);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_connect(socks[1], (struct sockaddr *)&addr, sizeof(addr));
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_accept(sock, NULL, NULL, &socks[0]);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
ddsrt_close(sock);
|
||||
}
|
||||
|
||||
static const char mesg[] = "foobar";
|
||||
|
||||
static uint32_t select_timeout_routine(void *ptr)
|
||||
{
|
||||
int cnt = -1;
|
||||
dds_retcode_t rc;
|
||||
dds_time_t before, after;
|
||||
dds_duration_t delay;
|
||||
fd_set rdset;
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
uint32_t res = 0;
|
||||
|
||||
FD_ZERO(&rdset);
|
||||
FD_SET(arg->sock, &rdset);
|
||||
|
||||
before = dds_time();
|
||||
rc = ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &cnt);
|
||||
after = dds_time();
|
||||
delay = after - before;
|
||||
|
||||
fprintf(stderr, "Waited for %"PRId64" (nanoseconds)\n", delay);
|
||||
fprintf(stderr, "Expected to wait %"PRId64" (nanoseconds)\n", arg->delay);
|
||||
fprintf(stderr, "ddsrt_select returned %d\n", rc);
|
||||
fprintf(stderr, "ddsrt_select reported %d ready\n", cnt);
|
||||
|
||||
if (rc == DDS_RETCODE_TIMEOUT) {
|
||||
res = (((after - delay) >= (arg->delay - arg->skew)) && (cnt == 0));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_select, timeout)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_socket_t socks[2];
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg;
|
||||
uint32_t res = 0;
|
||||
|
||||
sockets_pipe(socks);
|
||||
|
||||
arg.delay = DDS_MSECS(100);
|
||||
/* Allow the delay to be off by x microseconds (arbitrarily chosen) for
|
||||
systems with a really poor clock. This test is just to get some
|
||||
confidence that time calculation is not completely broken, it is by
|
||||
no means proof that time calculation is entirely correct! */
|
||||
arg.skew = DDS_MSECS(20);
|
||||
arg.sock = socks[0];
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "select_timeout", &attr, &select_timeout_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
/* Allow the thread some time to get ready. */
|
||||
dds_sleepfor(arg.delay * 2);
|
||||
/* Send data to the read socket to avoid blocking indefinitely. */
|
||||
ssize_t sent = 0;
|
||||
rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
rc = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
|
||||
(void)ddsrt_close(socks[0]);
|
||||
(void)ddsrt_close(socks[1]);
|
||||
}
|
||||
|
||||
static uint32_t recv_routine(void *ptr)
|
||||
{
|
||||
thread_arg_t *arg = (thread_arg_t*)ptr;
|
||||
|
||||
int nfds = 0;
|
||||
fd_set rdset;
|
||||
ssize_t rcvd = -1;
|
||||
char buf[sizeof(mesg)];
|
||||
|
||||
FD_ZERO(&rdset);
|
||||
FD_SET(arg->sock, &rdset);
|
||||
|
||||
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
|
||||
|
||||
if (ddsrt_recv(arg->sock, buf, sizeof(buf), 0, &rcvd) == DDS_RETCODE_OK) {
|
||||
return (rcvd == sizeof(mesg) && strcmp(buf, mesg) == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_select, send_recv)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_socket_t socks[2];
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg;
|
||||
uint32_t res = 0;
|
||||
|
||||
sockets_pipe(socks);
|
||||
|
||||
arg.delay = DDS_SECS(1);
|
||||
arg.skew = 0;
|
||||
arg.sock = socks[0];
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "recv", &attr, &recv_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
ssize_t sent = 0;
|
||||
rc = ddsrt_send(socks[1], mesg, sizeof(mesg), 0, &sent);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(sent, sizeof(mesg));
|
||||
|
||||
rc = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
|
||||
(void)ddsrt_close(socks[0]);
|
||||
(void)ddsrt_close(socks[1]);
|
||||
}
|
||||
|
||||
static uint32_t recvmsg_routine(void *ptr)
|
||||
{
|
||||
thread_arg_t *arg = (thread_arg_t*)ptr;
|
||||
|
||||
int nfds = 0;
|
||||
fd_set rdset;
|
||||
ssize_t rcvd = -1;
|
||||
char buf[sizeof(mesg)];
|
||||
ddsrt_msghdr_t msg;
|
||||
ddsrt_iovec_t iov;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
FD_ZERO(&rdset);
|
||||
FD_SET(arg->sock, &rdset);
|
||||
|
||||
(void)ddsrt_select(arg->sock + 1, &rdset, NULL, NULL, arg->delay, &nfds);
|
||||
|
||||
if (ddsrt_recvmsg(arg->sock, &msg, 0, &rcvd) == DDS_RETCODE_OK) {
|
||||
return (rcvd == sizeof(mesg) && strcmp(buf, mesg) == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_select, sendmsg_recvmsg)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_socket_t socks[2];
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg;
|
||||
uint32_t res = 0;
|
||||
|
||||
sockets_pipe(socks);
|
||||
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.sock = socks[0];
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "recvmsg", &attr, &recvmsg_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
ssize_t sent = 0;
|
||||
ddsrt_msghdr_t msg;
|
||||
ddsrt_iovec_t iov;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
iov.iov_base = (void*)mesg;
|
||||
iov.iov_len = (ddsrt_iov_len_t)sizeof(mesg);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
rc = ddsrt_sendmsg(socks[1], &msg, 0, &sent);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(sent, sizeof(mesg));
|
||||
|
||||
rc = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
|
||||
(void)ddsrt_close(socks[0]);
|
||||
(void)ddsrt_close(socks[1]);
|
||||
}
|
198
src/ddsrt/tests/socket.c
Normal file
198
src/ddsrt/tests/socket.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/endian.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/sockets.h"
|
||||
|
||||
DDSRT_WARNING_MSVC_OFF(4305)
|
||||
#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN
|
||||
static const struct sockaddr_in ipv4_loopback =
|
||||
{ .sin_family = AF_INET, .sin_addr = { .s_addr = 0x7f000001 } };
|
||||
#else
|
||||
static const struct sockaddr_in ipv4_loopback =
|
||||
{ .sin_family = AF_INET, .sin_addr = { .s_addr = 0x0100007f } };
|
||||
#endif /* DDSRT_ENDIAN */
|
||||
DDSRT_WARNING_MSVC_ON(4305)
|
||||
|
||||
#if DDSRT_HAVE_IPV6
|
||||
static const struct sockaddr_in6 ipv6_loopback =
|
||||
{ .sin6_family = AF_INET6, .sin6_addr = IN6ADDR_LOOPBACK_INIT };
|
||||
#endif
|
||||
|
||||
static void setup(void)
|
||||
{
|
||||
ddsrt_init();
|
||||
}
|
||||
|
||||
static void teardown(void)
|
||||
{
|
||||
ddsrt_fini();
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sockaddrfromstr, bad_family)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
struct sockaddr_storage sa;
|
||||
rc = ddsrt_sockaddrfromstr(AF_UNSPEC, "127.0.0.1", &sa);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
static void sockaddrfromstr_test(char *str, int af, dds_retcode_t exp)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
struct sockaddr_storage ss;
|
||||
rc = ddsrt_sockaddrfromstr(af, str, &ss);
|
||||
CU_ASSERT_EQUAL(rc, exp);
|
||||
if (rc == DDS_RETCODE_OK) {
|
||||
CU_ASSERT_EQUAL(ss.ss_family, af);
|
||||
}
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv4) = {
|
||||
CU_DataPoints(char *, "127.0.0.1", "0.0.0.0",
|
||||
"nip"),
|
||||
CU_DataPoints(int, AF_INET, AF_INET,
|
||||
AF_INET),
|
||||
CU_DataPoints(dds_retcode_t, DDS_RETCODE_OK, DDS_RETCODE_OK,
|
||||
DDS_RETCODE_BAD_PARAMETER)
|
||||
};
|
||||
|
||||
CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv4, .init=setup, .fini=teardown)
|
||||
{
|
||||
sockaddrfromstr_test(str, af, exp);
|
||||
}
|
||||
|
||||
#if DDSRT_HAVE_IPV6
|
||||
CU_TheoryDataPoints(ddsrt_sockaddrfromstr, ipv6) = {
|
||||
CU_DataPoints(char *, "127.0.0.1", "::1",
|
||||
"::1", "::",
|
||||
"nip"),
|
||||
CU_DataPoints(int, AF_INET6, AF_INET6,
|
||||
AF_INET, AF_INET6,
|
||||
AF_INET6),
|
||||
CU_DataPoints(dds_retcode_t, DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
|
||||
DDS_RETCODE_BAD_PARAMETER, DDS_RETCODE_OK,
|
||||
DDS_RETCODE_BAD_PARAMETER)
|
||||
};
|
||||
|
||||
CU_Theory((char *str, int af, dds_retcode_t exp), ddsrt_sockaddrfromstr, ipv6, .init=setup, .fini=teardown)
|
||||
{
|
||||
sockaddrfromstr_test(str, af, exp);
|
||||
}
|
||||
#endif /* DDSRT_HAVE_IPV6 */
|
||||
|
||||
CU_Test(ddsrt_sockaddrtostr, bad_sockaddr, .init=setup, .fini=teardown)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
char buf[128] = { 0 };
|
||||
struct sockaddr_in sa;
|
||||
memcpy(&sa, &ipv4_loopback, sizeof(ipv4_loopback));
|
||||
sa.sin_family = AF_UNSPEC;
|
||||
rc = ddsrt_sockaddrtostr(&sa, buf, sizeof(buf));
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sockaddrtostr, no_space, .init=setup, .fini=teardown)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
char buf[1] = { 0 };
|
||||
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sockaddrtostr, ipv4)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
char buf[128] = { 0 };
|
||||
rc = ddsrt_sockaddrtostr(&ipv4_loopback, buf, sizeof(buf));
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_STRING_EQUAL(buf, "127.0.0.1");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sockaddrtostr, ipv6)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
char buf[128] = { 0 };
|
||||
rc = ddsrt_sockaddrtostr(&ipv6_loopback, buf, sizeof(buf));
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_STRING_EQUAL(buf, "::1");
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sockets, gethostname)
|
||||
{
|
||||
int ret;
|
||||
dds_retcode_t rc;
|
||||
char sysbuf[200], buf[200];
|
||||
|
||||
buf[0] = '\0';
|
||||
rc = ddsrt_gethostname(buf, sizeof(buf));
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
sysbuf[0] = '\0';
|
||||
ret = gethostname(sysbuf, sizeof(sysbuf));
|
||||
CU_ASSERT_EQUAL(ret, 0);
|
||||
CU_ASSERT(strcmp(buf, sysbuf) == 0);
|
||||
|
||||
rc = ddsrt_gethostname(buf, strlen(buf) - 1);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_NOT_ENOUGH_SPACE);
|
||||
}
|
||||
|
||||
#if DDSRT_HAVE_DNS
|
||||
static void gethostbyname_test(char *name, int af, dds_retcode_t exp)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_hostent_t *hent = NULL;
|
||||
rc = ddsrt_gethostbyname(name, af, &hent);
|
||||
CU_ASSERT_EQUAL(rc, exp);
|
||||
if (rc == DDS_RETCODE_OK) {
|
||||
CU_ASSERT_FATAL(hent->naddrs > 0);
|
||||
if (af != AF_UNSPEC) {
|
||||
CU_ASSERT_EQUAL(hent->addrs[0].ss_family, af);
|
||||
}
|
||||
}
|
||||
ddsrt_free(hent);
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_gethostbyname, ipv4) = {
|
||||
CU_DataPoints(char *, "", "127.0.0.1", "127.0.0.1"),
|
||||
CU_DataPoints(int, AF_UNSPEC, AF_INET, AF_UNSPEC),
|
||||
CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK)
|
||||
};
|
||||
|
||||
CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv4, .init=setup, .fini=teardown)
|
||||
{
|
||||
gethostbyname_test(name, af, exp);
|
||||
}
|
||||
|
||||
#if DDSRT_HAVE_IPV6
|
||||
/* Lookup of IPv4 address and specifying AF_INET6 is not invalid as it may
|
||||
return an IPV4-mapped IPv6 address. */
|
||||
CU_TheoryDataPoints(ddsrt_gethostbyname, ipv6) = {
|
||||
CU_DataPoints(char *, "::1", "::1", "::1"),
|
||||
CU_DataPoints(int, AF_INET, AF_INET6, AF_UNSPEC),
|
||||
CU_DataPoints(dds_retcode_t, DDS_RETCODE_HOST_NOT_FOUND, DDS_RETCODE_OK, DDS_RETCODE_OK)
|
||||
};
|
||||
|
||||
CU_Theory((char *name, int af, dds_retcode_t exp), ddsrt_gethostbyname, ipv6, .init=setup, .fini=teardown)
|
||||
{
|
||||
gethostbyname_test(name, af, exp);
|
||||
}
|
||||
#endif /* DDSRT_HAVE_IPV6 */
|
||||
#endif /* DDSRT_HAVE_DNS */
|
101
src/ddsrt/tests/string.c
Normal file
101
src/ddsrt/tests/string.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/string.h"
|
||||
|
||||
typedef enum { eq, lt, gt } eq_t;
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strcasecmp, basic) = {
|
||||
CU_DataPoints(const char *, "a", "aa", "a", "a", "A", "a", "b", "a", "B", "A", "", "a"),
|
||||
CU_DataPoints(const char *, "a", "a", "aa", "A", "a", "b", "a", "b", "A", "B", "a", ""),
|
||||
CU_DataPoints(eq_t, eq, gt, lt, eq, eq, lt, gt, lt, gt, lt, lt, gt)
|
||||
};
|
||||
|
||||
CU_Theory((const char *s1, const char *s2, eq_t e), ddsrt_strcasecmp, basic)
|
||||
{
|
||||
int r = ddsrt_strcasecmp(s1, s2);
|
||||
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strncasecmp, basic) = {
|
||||
CU_DataPoints(const char *, "a", "aa", "a", "A", "a", "b", "a", "B", "A", "", "a"),
|
||||
CU_DataPoints(const char *, "a", "a", "aa", "a", "A", "a", "b", "A", "B", "a", ""),
|
||||
CU_DataPoints(size_t, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
CU_DataPoints(eq_t, eq, gt, lt, eq, eq, gt, lt, gt, lt, lt, gt)
|
||||
};
|
||||
|
||||
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, basic)
|
||||
{
|
||||
int r = ddsrt_strncasecmp(s1, s2, n);
|
||||
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strncasecmp, empty) = {
|
||||
CU_DataPoints(const char *, "a", "", "a", "", "a", ""),
|
||||
CU_DataPoints(const char *, "", "a", "", "a", "", "a"),
|
||||
CU_DataPoints(size_t, 1, 1, 0, 0, 2, 2),
|
||||
CU_DataPoints(eq_t, gt, lt, eq, eq, gt, lt)
|
||||
};
|
||||
|
||||
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, empty)
|
||||
{
|
||||
int r = ddsrt_strncasecmp(s1, s2, n);
|
||||
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strncasecmp, length) = {
|
||||
CU_DataPoints(const char *, "aBcD", "AbCX", "aBcD", "AbCX", "aBcD"),
|
||||
CU_DataPoints(const char *, "AbCX", "aBcD", "AbCX", "aBcD", "AbCd"),
|
||||
CU_DataPoints(size_t, 3, 3, 4, 4, 5, 5),
|
||||
CU_DataPoints(eq_t, eq, eq, lt, gt, eq, eq)
|
||||
};
|
||||
|
||||
CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, length)
|
||||
{
|
||||
int r = ddsrt_strncasecmp(s1, s2, n);
|
||||
CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0));
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_string, strtok_r)
|
||||
{
|
||||
char *res;
|
||||
char *saveptr;
|
||||
char ts1[] = "123,234";
|
||||
char ts2[] = ",;,123abc,,456,:,";
|
||||
char ts3[] = ",,,123,,456,789,,,";
|
||||
|
||||
res = ddsrt_strtok_r(ts1, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "123") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "234") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",", &saveptr);
|
||||
CU_ASSERT(res == NULL);
|
||||
|
||||
res = ddsrt_strtok_r(ts2, ",;", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "123abc") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "456") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",:", &saveptr);
|
||||
CU_ASSERT(res == NULL);
|
||||
|
||||
res = ddsrt_strtok_r(ts3, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "123") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "456") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",", &saveptr);
|
||||
CU_ASSERT(strcmp(res, "789") == 0);
|
||||
res = ddsrt_strtok_r( NULL, ",:", &saveptr);
|
||||
CU_ASSERT(res == NULL);
|
||||
}
|
||||
|
80
src/ddsrt/tests/strlcpy.c
Normal file
80
src/ddsrt/tests/strlcpy.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/string.h"
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strlcpy, dest_size) = {
|
||||
CU_DataPoints(char *, "foo", "foo", "foo", "foo", "foo", "", "", ""),
|
||||
CU_DataPoints(size_t, 0, 1, 3, 4, 5, 0, 1, 2)
|
||||
};
|
||||
|
||||
CU_Theory((char *src, size_t size), ddsrt_strlcpy, dest_size)
|
||||
{
|
||||
char dest[] = "................";
|
||||
size_t len, srclen;
|
||||
|
||||
srclen = strlen(src);
|
||||
len = ddsrt_strlcpy(dest, src, size);
|
||||
CU_ASSERT_EQUAL(len, srclen);
|
||||
if (size > 0) {
|
||||
if ((size - 1) < len) {
|
||||
len = size - 1;
|
||||
}
|
||||
CU_ASSERT_EQUAL(dest[len], '\0');
|
||||
CU_ASSERT_EQUAL(dest[len+1], '.');
|
||||
CU_ASSERT((strncmp(dest, src, len) == 0));
|
||||
} else {
|
||||
CU_ASSERT_EQUAL(dest[0], '.');
|
||||
}
|
||||
}
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_strlcat, dest_size) = {
|
||||
CU_DataPoints(char *, "", "", "", "", "foo", "foo", "foo", "foo", "foo", "foo", "foo", "", "", "foo", "foo", "foo"),
|
||||
CU_DataPoints(char *, "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "bar", "", "", "", "", ""),
|
||||
CU_DataPoints(size_t, 0, 1, 3, 4, 0, 1, 3, 4, 5, 6, 7, 0, 1, 3, 4, 5)
|
||||
};
|
||||
|
||||
CU_Theory((char *seed, char *src, size_t size), ddsrt_strlcat, dest_size)
|
||||
{
|
||||
char dest[] = "................";
|
||||
size_t len, seedlen, srclen;
|
||||
seedlen = strlen(seed);
|
||||
srclen = strlen(src);
|
||||
memcpy(dest, seed, seedlen);
|
||||
dest[seedlen] = '\0';
|
||||
|
||||
len = ddsrt_strlcat(dest, src, size);
|
||||
CU_ASSERT_EQUAL(len, (seedlen + srclen));
|
||||
if (size > 0) {
|
||||
char foobar[sizeof(dest)];
|
||||
|
||||
if ((size - 1) <= seedlen) {
|
||||
len = seedlen;
|
||||
} else if ((size - 1) <= len) {
|
||||
len = size - 1;
|
||||
}
|
||||
|
||||
CU_ASSERT_EQUAL(dest[len], '\0');
|
||||
|
||||
if (seedlen < (size - 1)) {
|
||||
CU_ASSERT_EQUAL(dest[len+1], '.');
|
||||
}
|
||||
|
||||
(void)snprintf(foobar, len+1, "%s%s", seed, src);
|
||||
CU_ASSERT((strncmp(dest, foobar, len) == 0));
|
||||
} else {
|
||||
CU_ASSERT((strcmp(dest, seed) == 0));
|
||||
}
|
||||
}
|
343
src/ddsrt/tests/strtoll.c
Normal file
343
src/ddsrt/tests/strtoll.c
Normal file
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* 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 "CUnit/Test.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/misc.h"
|
||||
#include "dds/ddsrt/strtol.h"
|
||||
|
||||
const char *str;
|
||||
char *ptr;
|
||||
char buf[100];
|
||||
char str_llmin[100];
|
||||
char str_llmax[100];
|
||||
char str_ullmax[100];
|
||||
char str_llrange[100];
|
||||
char str_ullrange[100];
|
||||
|
||||
char str_xllmin[99], str_xllmax[99];
|
||||
|
||||
/* Really test with the maximum values supported on a platform, not some
|
||||
made up number. */
|
||||
long long llmin = DDSRT_MIN_INTEGER(long long);
|
||||
long long llmax = DDSRT_MAX_INTEGER(long long);
|
||||
unsigned long long ullmax = DDSRT_MAX_INTEGER(unsigned long long);
|
||||
|
||||
CU_Init(ddsrt_strtoll)
|
||||
{
|
||||
ddsrt_init();
|
||||
(void)snprintf (str_llmin, sizeof(str_llmin), "%lld", llmin);
|
||||
(void)snprintf (str_llmax, sizeof(str_llmax), "%lld", llmax);
|
||||
(void)snprintf (str_llrange, sizeof(str_llrange), "%lld1", llmax);
|
||||
(void)snprintf (str_ullmax, sizeof(str_ullmax), "%llu", ullmax);
|
||||
(void)snprintf (str_ullrange, sizeof(str_ullrange), "%llu1", ullmax);
|
||||
(void)snprintf (str_xllmin, sizeof(str_xllmin), "-%llx", llmin);
|
||||
(void)snprintf (str_xllmax, sizeof(str_xllmax), "+%llx", llmax);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddstr_strtoll)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, strtoll)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
long long ll;
|
||||
static char dummy[] = "dummy";
|
||||
|
||||
str = "gibberish";
|
||||
ll = -1;
|
||||
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0 && ptr == str);
|
||||
|
||||
str = "+gibberish";
|
||||
ll = -2;
|
||||
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0 && ptr == str);
|
||||
|
||||
str = "-gibberish";
|
||||
ll = -3;
|
||||
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0 && ptr == str);
|
||||
|
||||
str = "gibberish";
|
||||
ptr = NULL;
|
||||
ll = -4;
|
||||
rc = ddsrt_strtoll(str, &ptr, 36, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 46572948005345 && ptr && *ptr == '\0');
|
||||
|
||||
str = "1050505055";
|
||||
ptr = dummy;
|
||||
ll = -5;
|
||||
rc = ddsrt_strtoll(str, &ptr, 37, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_BAD_PARAMETER);
|
||||
CU_ASSERT (ll == -5 && ptr == dummy);
|
||||
|
||||
str = " \t \n 1050505055";
|
||||
ll = -6;
|
||||
rc = ddsrt_strtoll(str, NULL, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 1050505055LL);
|
||||
|
||||
str = " \t \n -1050505055";
|
||||
ptr = NULL;
|
||||
ll = -7;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == -1050505055LL);
|
||||
|
||||
str = " \t \n - \t \n 1050505055";
|
||||
ptr = NULL;
|
||||
ll = -8;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0LL && ptr == str);
|
||||
|
||||
str = "10x";
|
||||
ptr = NULL;
|
||||
ll = -9;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
|
||||
|
||||
str = "+10x";
|
||||
ll = -10;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 10LL && ptr && *ptr == 'x');
|
||||
|
||||
str = "-10x";
|
||||
ll = -11;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == -10LL && ptr && *ptr == 'x');
|
||||
|
||||
str = (const char *)str_llmax;
|
||||
ll = -12;
|
||||
rc = ddsrt_strtoll(str, NULL, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == llmax);
|
||||
|
||||
str = (const char *)str_llmin;
|
||||
ll = -13;
|
||||
rc = ddsrt_strtoll(str, NULL, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == llmin);
|
||||
|
||||
str = (const char *)str_llrange;
|
||||
ll = -14;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OUT_OF_RANGE);
|
||||
CU_ASSERT (ll == llmax && *ptr == '1');
|
||||
|
||||
str = "0x100";
|
||||
ll = -15;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x100LL);
|
||||
|
||||
str = "0X100";
|
||||
ll = -16;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x100LL);
|
||||
|
||||
str = "0x1DEFCAB";
|
||||
ll = -17;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x1DEFCABLL);
|
||||
|
||||
str = "0x1defcab";
|
||||
ll = -18;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x1DEFCABLL);
|
||||
|
||||
str = (char *)str_xllmin;
|
||||
ll = -19;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == llmin);
|
||||
|
||||
str = (char *)str_xllmax;
|
||||
ll = -20;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == llmax);
|
||||
|
||||
str = "0x100";
|
||||
ll = -21;
|
||||
rc = ddsrt_strtoll(str, NULL, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x100LL);
|
||||
|
||||
str = "100";
|
||||
ll = -22;
|
||||
rc = ddsrt_strtoll(str, NULL, 16, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0x100LL);
|
||||
|
||||
/* calling os_strtoll with \"%s\" and base 10, expected result 0 */
|
||||
str = "0x100";
|
||||
ll = -23;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 0 && ptr && *ptr == 'x');
|
||||
|
||||
/* calling os_strtoll with \"%s\" and base 0, expected result 256 */
|
||||
str = "0x100g";
|
||||
ll = -24;
|
||||
rc = ddsrt_strtoll(str, &ptr, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 256 && ptr && *ptr == 'g');
|
||||
|
||||
str = "0100";
|
||||
ll = -25;
|
||||
rc = ddsrt_strtoll(str, NULL, 0, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 64LL);
|
||||
|
||||
str = "0100";
|
||||
ll = -26;
|
||||
rc = ddsrt_strtoll(str, NULL, 8, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 64LL);
|
||||
|
||||
str = "100";
|
||||
ll = -27;
|
||||
rc = ddsrt_strtoll(str, NULL, 8, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 64LL);
|
||||
|
||||
/* calling os_strtoll with \"%s\" and base 10, expected result 100 */
|
||||
str = "0100";
|
||||
ll = -28;
|
||||
rc = ddsrt_strtoll(str, &ptr, 10, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 100);
|
||||
|
||||
/* calling os_strtoll with \"%s\" and base 0, expected result 64 */
|
||||
str = "01008";
|
||||
ll = -29;
|
||||
rc = ddsrt_strtoll(str, &ptr, 8, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 64LL && ptr && *ptr == '8');
|
||||
|
||||
str = "00001010";
|
||||
ll = -30;
|
||||
rc = ddsrt_strtoll(str, NULL, 2, &ll);
|
||||
CU_ASSERT (rc == DDS_RETCODE_OK);
|
||||
CU_ASSERT (ll == 10LL);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, strtoull)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
unsigned long long ull;
|
||||
|
||||
str = "0xffffffffffffffff";
|
||||
ull = 1;
|
||||
rc = ddsrt_strtoull(str, NULL, 0, &ull);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT(ull == ullmax);
|
||||
|
||||
str = "-1";
|
||||
ull = 2;
|
||||
rc = ddsrt_strtoull(str, NULL, 0, &ull);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT(ull == ullmax);
|
||||
|
||||
str = "-2";
|
||||
ull = 3;
|
||||
rc = ddsrt_strtoull(str, NULL, 0, &ull);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT(ull == (ullmax - 1));
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, atoll)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
long long ll;
|
||||
|
||||
str = "10";
|
||||
ll = -1;
|
||||
rc = ddsrt_atoll(str, &ll);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT(ll == 10);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, atoull)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
unsigned long long ull;
|
||||
|
||||
str = "10";
|
||||
ull = 1;
|
||||
rc = ddsrt_atoull(str, &ull);
|
||||
CU_ASSERT_EQUAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT(ull == 10);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, lltostr)
|
||||
{
|
||||
long long ll;
|
||||
|
||||
ll = llmax;
|
||||
ptr = ddsrt_lltostr(ll, buf, 0, NULL);
|
||||
CU_ASSERT(ptr == NULL);
|
||||
|
||||
/* calling os_lltostr with %lld with buffer size of 5, expected result \"5432\" */
|
||||
ll = 54321;
|
||||
ptr = ddsrt_lltostr(ll, buf, 5, NULL);
|
||||
CU_ASSERT(strcmp(ptr, "5432") == 0);
|
||||
|
||||
ll = llmax;
|
||||
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, str_llmax) == 0);
|
||||
|
||||
ll = llmin;
|
||||
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, str_llmin) == 0);
|
||||
|
||||
ll = 1;
|
||||
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, "1") == 0);
|
||||
|
||||
ll = 0;
|
||||
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, "0") == 0);
|
||||
|
||||
ll = -1;
|
||||
ptr = ddsrt_lltostr(ll, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, "-1") == 0);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_strtoll, ulltostr)
|
||||
{
|
||||
unsigned long long ull;
|
||||
|
||||
ull = ullmax;
|
||||
ptr = ddsrt_ulltostr(ull, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, str_ullmax) == 0);
|
||||
|
||||
ull = 0ULL;
|
||||
ptr = ddsrt_ulltostr(ull, buf, sizeof(buf), NULL);
|
||||
CU_ASSERT(strcmp(ptr, "0") == 0);
|
||||
}
|
||||
|
357
src/ddsrt/tests/sync.c
Normal file
357
src/ddsrt/tests/sync.c
Normal file
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "CUnit/Theory.h"
|
||||
#include "dds/ddsrt/atomics.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/sync.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
#include "dds/ddsrt/time.h"
|
||||
|
||||
CU_Init(ddsrt_sync)
|
||||
{
|
||||
ddsrt_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddsrt_sync)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ddsrt_atomic_uint32_t cnt;
|
||||
ddsrt_mutex_t lock;
|
||||
ddsrt_rwlock_t rwlock;
|
||||
ddsrt_cond_t cond;
|
||||
dds_time_t abstime;
|
||||
dds_time_t reltime;
|
||||
} thread_arg_t;
|
||||
|
||||
static uint32_t mutex_lock_routine(void *ptr)
|
||||
{
|
||||
int res;
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
|
||||
ddsrt_atomic_inc32(&arg->cnt);
|
||||
ddsrt_mutex_lock(&arg->lock);
|
||||
res = ddsrt_atomic_cas32(&arg->cnt, 2UL, 4UL);
|
||||
ddsrt_mutex_unlock(&arg->lock);
|
||||
return (uint32_t)res;
|
||||
}
|
||||
|
||||
/* This test is merely best-effort, the scheduler might schedule the main
|
||||
main thread before a lock operation is attempted by the second thread. */
|
||||
CU_Test(ddsrt_sync, mutex_lock_conc)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0) };
|
||||
uint32_t res = 0;
|
||||
|
||||
ddsrt_mutex_init(&arg.lock);
|
||||
ddsrt_mutex_lock(&arg.lock);
|
||||
ddsrt_threadattr_init(&attr);
|
||||
ret = ddsrt_thread_create(&thr, "mutex_lock_conc", &attr, &mutex_lock_routine, &arg);
|
||||
CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK);
|
||||
while (ddsrt_atomic_ld32(&arg.cnt) == 0)
|
||||
/* Wait for thread to be scheduled. */ ;
|
||||
ddsrt_atomic_inc32(&arg.cnt);
|
||||
ddsrt_mutex_unlock(&arg.lock);
|
||||
ret = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
CU_ASSERT_EQUAL(ddsrt_atomic_ld32(&arg.cnt), 4UL);
|
||||
ddsrt_mutex_destroy(&arg.lock);
|
||||
}
|
||||
|
||||
static uint32_t mutex_trylock_routine(void *ptr)
|
||||
{
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
|
||||
if (ddsrt_mutex_trylock(&arg->lock)) {
|
||||
ddsrt_atomic_inc32(&arg->cnt);
|
||||
}
|
||||
|
||||
return ddsrt_atomic_ld32(&arg->cnt);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sync, mutex_trylock)
|
||||
{
|
||||
bool locked;
|
||||
ddsrt_mutex_t lock;
|
||||
|
||||
ddsrt_mutex_init(&lock);
|
||||
locked = ddsrt_mutex_trylock(&lock);
|
||||
CU_ASSERT(locked == true);
|
||||
locked = ddsrt_mutex_trylock (&lock);
|
||||
/* NOTE: On VxWorks RTP mutexes seemingly can be locked recursively. Still,
|
||||
behavior should be consistent across targets. If this fails, fix
|
||||
the implementation instead. */
|
||||
CU_ASSERT(locked == false);
|
||||
ddsrt_mutex_unlock(&lock);
|
||||
ddsrt_mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
static uint32_t rwlock_tryread_routine(void *ptr)
|
||||
{
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
|
||||
if (ddsrt_rwlock_tryread(&arg->rwlock)) {
|
||||
ddsrt_atomic_inc32(&arg->cnt);
|
||||
ddsrt_rwlock_unlock(&arg->rwlock);
|
||||
}
|
||||
|
||||
return ddsrt_atomic_ld32(&arg->cnt);
|
||||
}
|
||||
|
||||
static uint32_t rwlock_trywrite_routine(void *ptr)
|
||||
{
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
|
||||
/* This operation should never succeed in the test, but if it does the
|
||||
result must reflect it. */
|
||||
if (ddsrt_rwlock_trywrite(&arg->rwlock)) {
|
||||
ddsrt_atomic_inc32(&arg->cnt);
|
||||
ddsrt_rwlock_unlock(&arg->rwlock);
|
||||
}
|
||||
|
||||
return ddsrt_atomic_ld32(&arg->cnt);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sync, mutex_trylock_conc)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(1) };
|
||||
uint32_t res = 0;
|
||||
|
||||
ddsrt_mutex_init(&arg.lock);
|
||||
ddsrt_mutex_lock(&arg.lock);
|
||||
ddsrt_threadattr_init(&attr);
|
||||
ret = ddsrt_thread_create(&thr, "mutex_trylock_conc", &attr, &mutex_trylock_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
ret = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
ddsrt_mutex_unlock(&arg.lock);
|
||||
ddsrt_mutex_destroy(&arg.lock);
|
||||
}
|
||||
|
||||
#define READ (1)
|
||||
#define TRYREAD (2)
|
||||
#define WRITE (3)
|
||||
#define TRYWRITE (4)
|
||||
|
||||
CU_TheoryDataPoints(ddsrt_sync, rwlock_trylock_conc) = {
|
||||
CU_DataPoints(uint32_t, READ, READ, WRITE, WRITE),
|
||||
CU_DataPoints(uint32_t, TRYREAD, TRYWRITE, TRYREAD, TRYWRITE),
|
||||
CU_DataPoints(uint32_t, 2, 1, 1, 1)
|
||||
};
|
||||
|
||||
CU_Theory((uint32_t lock, uint32_t trylock, uint32_t exp), ddsrt_sync, rwlock_trylock_conc)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
ddsrt_thread_routine_t func;
|
||||
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(1) };
|
||||
uint32_t res = 0;
|
||||
|
||||
ddsrt_rwlock_init(&arg.rwlock);
|
||||
if (lock == READ) {
|
||||
ddsrt_rwlock_read(&arg.rwlock);
|
||||
} else {
|
||||
ddsrt_rwlock_write(&arg.rwlock);
|
||||
}
|
||||
|
||||
if (trylock == TRYREAD) {
|
||||
func = &rwlock_tryread_routine;
|
||||
} else {
|
||||
func = &rwlock_trywrite_routine;
|
||||
}
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
ret = ddsrt_thread_create(&thr, "rwlock_trylock_conc", &attr, func, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
ret = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
ddsrt_rwlock_unlock(&arg.rwlock);
|
||||
CU_ASSERT_EQUAL(res, exp);
|
||||
ddsrt_rwlock_destroy(&arg.rwlock);
|
||||
}
|
||||
|
||||
/* An atomic read is used for synchronization because it is important that the
|
||||
threads try to access the once control concurrently as much as possible. Of
|
||||
course, this is only best-effort as there is no guarantee that
|
||||
initialization is actually tried concurrently. */
|
||||
static ddsrt_atomic_uint32_t once_count = DDSRT_ATOMIC_UINT32_INIT(0);
|
||||
static ddsrt_once_t once_control = DDSRT_ONCE_INIT;
|
||||
|
||||
#define ONCE_THREADS (8)
|
||||
|
||||
static void do_once(void)
|
||||
{
|
||||
ddsrt_atomic_inc32(&once_count);
|
||||
}
|
||||
|
||||
static uint32_t once_routine(void *ptr)
|
||||
{
|
||||
(void)ptr;
|
||||
while (ddsrt_atomic_ld32(&once_count) == 0)
|
||||
/* Wait for the go-ahead. */ ;
|
||||
ddsrt_once(&once_control, &do_once);
|
||||
return ddsrt_atomic_ld32(&once_count);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sync, once_conc)
|
||||
{
|
||||
dds_retcode_t ret;
|
||||
ddsrt_thread_t thrs[ONCE_THREADS];
|
||||
ddsrt_threadattr_t attr;
|
||||
uint32_t res;
|
||||
char buf[32];
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
for (int i = 0; i < ONCE_THREADS; i++) {
|
||||
(void)snprintf(buf, sizeof(buf), "once_conc%d", i + 1);
|
||||
ret = ddsrt_thread_create(&thrs[i], buf, &attr, &once_routine, NULL);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
}
|
||||
|
||||
ddsrt_atomic_st32(&once_count, 1);
|
||||
|
||||
for (int i = 0; i < ONCE_THREADS; i++) {
|
||||
res = 0;
|
||||
ret = ddsrt_thread_join(thrs[i], &res);
|
||||
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 2);
|
||||
}
|
||||
|
||||
ddsrt_once(&once_control, &do_once);
|
||||
CU_ASSERT_EQUAL(ddsrt_atomic_ld32(&once_count), 2);
|
||||
}
|
||||
|
||||
static uint32_t waitfor_routine(void *ptr)
|
||||
{
|
||||
dds_time_t before, after;
|
||||
dds_duration_t reltime;
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
uint32_t cnt = 0, res = 0;
|
||||
|
||||
while (ddsrt_atomic_ld32(&arg->cnt) == 0)
|
||||
/* Wait for go-ahead. */ ;
|
||||
ddsrt_mutex_lock(&arg->lock);
|
||||
before = dds_time();
|
||||
reltime = arg->reltime;
|
||||
while (ddsrt_cond_waitfor(&arg->cond, &arg->lock, reltime)) {
|
||||
after = dds_time();
|
||||
if ((after - before) < arg->reltime && (after - before) > 0) {
|
||||
reltime = arg->reltime - (after - before);
|
||||
} else {
|
||||
reltime = 0;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
after = dds_time();
|
||||
reltime = after - before;
|
||||
fprintf(stderr, "waited for %"PRId64" (nanoseconds)\n", reltime);
|
||||
fprintf(stderr, "expected to wait %"PRId64" (nanoseconds)\n", arg->reltime);
|
||||
fprintf(stderr, "woke up %u times\n", cnt);
|
||||
ddsrt_mutex_unlock(&arg->lock);
|
||||
if (reltime >= arg->reltime) {
|
||||
/* Ensure that the condition variable at least waited for the amount of
|
||||
time so that time calculation is not (too) broken.*/
|
||||
res = cnt < 3; /* An arbitrary number to ensure the implementation
|
||||
did not just spin, aka is completely broken. */
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sync, cond_waitfor)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0), .reltime = DDS_MSECS(100) };
|
||||
uint32_t res = 0;
|
||||
|
||||
ddsrt_mutex_init(&arg.lock);
|
||||
ddsrt_cond_init(&arg.cond);
|
||||
ddsrt_mutex_lock(&arg.lock);
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "cond_waitfor", &attr, &waitfor_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
ddsrt_mutex_unlock(&arg.lock);
|
||||
/* Give go-ahead. */
|
||||
ddsrt_atomic_inc32(&arg.cnt);
|
||||
/* Wait a little longer than the waiting thread. */
|
||||
dds_sleepfor(arg.reltime * 2);
|
||||
/* Send a signal too avoid blocking indefinitely. */
|
||||
ddsrt_cond_signal(&arg.cond);
|
||||
rc = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
}
|
||||
|
||||
static uint32_t waituntil_routine(void *ptr)
|
||||
{
|
||||
dds_time_t after;
|
||||
thread_arg_t *arg = (thread_arg_t *)ptr;
|
||||
uint32_t cnt = 0, res = 0;
|
||||
|
||||
ddsrt_mutex_lock(&arg->lock);
|
||||
while(ddsrt_cond_waituntil(&arg->cond, &arg->lock, arg->abstime)) {
|
||||
cnt++;
|
||||
}
|
||||
after = dds_time();
|
||||
ddsrt_mutex_unlock(&arg->lock);
|
||||
fprintf(stderr, "waited until %"PRId64" (nanoseconds)\n", after);
|
||||
fprintf(stderr, "expected to wait until %"PRId64" (nanoseconds)\n", arg->abstime);
|
||||
fprintf(stderr, "woke up %u times\n", cnt);
|
||||
if (after > arg->abstime) {
|
||||
res = cnt < 3; /* An arbitrary number to ensure the implementation
|
||||
did not just spin, aka is completely broken. */
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_sync, cond_waituntil)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
dds_duration_t delay = DDS_MSECS(100);
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
thread_arg_t arg = { .cnt = DDSRT_ATOMIC_UINT32_INIT(0) };
|
||||
uint32_t res = 0;
|
||||
|
||||
arg.abstime = dds_time() + delay;
|
||||
ddsrt_mutex_init(&arg.lock);
|
||||
ddsrt_cond_init(&arg.cond);
|
||||
ddsrt_mutex_lock(&arg.lock);
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "cond_waituntil", &attr, &waituntil_routine, &arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
ddsrt_mutex_unlock(&arg.lock);
|
||||
dds_sleepfor(delay * 2);
|
||||
/* Send a signal too avoid blocking indefinitely. */
|
||||
ddsrt_cond_signal(&arg.cond);
|
||||
rc = ddsrt_thread_join(thr, &res);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
CU_ASSERT_EQUAL(res, 1);
|
||||
}
|
233
src/ddsrt/tests/thread.c
Normal file
233
src/ddsrt/tests/thread.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
286
src/ddsrt/tests/thread_cleanup.c
Normal file
286
src/ddsrt/tests/thread_cleanup.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#include "CUnit/Test.h"
|
||||
#include "dds/ddsrt/cdtors.h"
|
||||
#include "dds/ddsrt/heap.h"
|
||||
#include "dds/ddsrt/sync.h"
|
||||
#include "dds/ddsrt/threads.h"
|
||||
|
||||
CU_Init(ddsrt_thread_cleanup)
|
||||
{
|
||||
ddsrt_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CU_Clean(ddsrt_thread_cleanup)
|
||||
{
|
||||
ddsrt_fini();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define THREAD_RESET_1 (1<<0)
|
||||
#define THREAD_RESET_2 (1<<1)
|
||||
#define THREAD_RUN_OFFSET (4)
|
||||
#define THREAD_RUN_1 (1<<(THREAD_RUN_OFFSET))
|
||||
#define THREAD_RUN_2 (1<<(THREAD_RUN_OFFSET + 1))
|
||||
|
||||
struct thread_argument {
|
||||
int flags;
|
||||
int pop;
|
||||
int one;
|
||||
int two;
|
||||
int executed;
|
||||
int cancelled;
|
||||
int block;
|
||||
ddsrt_mutex_t *mutex;
|
||||
ddsrt_thread_t thread;
|
||||
};
|
||||
|
||||
static struct thread_argument *
|
||||
make_thread_argument(
|
||||
int flags, int pop, int one, int two)
|
||||
{
|
||||
struct thread_argument *targ = ddsrt_malloc(sizeof(*targ));
|
||||
memset(targ, 0, sizeof(*targ));
|
||||
targ->flags = flags;
|
||||
targ->pop = pop;
|
||||
targ->one = one;
|
||||
targ->two = two;
|
||||
|
||||
return targ;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_one(
|
||||
void *arg)
|
||||
{
|
||||
struct thread_argument *targ = (struct thread_argument *)arg;
|
||||
targ->one = 0;
|
||||
targ->executed++;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_two(
|
||||
void *arg)
|
||||
{
|
||||
struct thread_argument *targ = (struct thread_argument *)arg;
|
||||
targ->two = 0;
|
||||
targ->executed++;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
thread_main(
|
||||
void *arg)
|
||||
{
|
||||
int pushed = 0;
|
||||
int popped = 0;
|
||||
int execute = 0;
|
||||
struct thread_argument *targ = (struct thread_argument *)arg;
|
||||
|
||||
if (targ->flags & THREAD_RESET_1) {
|
||||
ddsrt_thread_cleanup_push(&reset_one, arg);
|
||||
pushed++;
|
||||
}
|
||||
if (targ->flags & THREAD_RESET_2) {
|
||||
ddsrt_thread_cleanup_push(&reset_two, arg);
|
||||
pushed++;
|
||||
}
|
||||
|
||||
assert(targ->pop <= pushed);
|
||||
|
||||
if (targ->block) {
|
||||
ddsrt_mutex_lock(targ->mutex);
|
||||
}
|
||||
|
||||
while (popped < targ->pop) {
|
||||
execute = 1 << (THREAD_RUN_OFFSET + (targ->pop - (popped + 1)));
|
||||
ddsrt_thread_cleanup_pop(targ->flags & execute);
|
||||
targ->cancelled++;
|
||||
popped++;
|
||||
}
|
||||
|
||||
if (targ->block) {
|
||||
ddsrt_mutex_unlock(targ->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
setup(
|
||||
struct thread_argument *arg)
|
||||
{
|
||||
dds_retcode_t rc;
|
||||
ddsrt_thread_t thr;
|
||||
ddsrt_threadattr_t attr;
|
||||
|
||||
uint32_t tres = 0;
|
||||
|
||||
ddsrt_threadattr_init(&attr);
|
||||
rc = ddsrt_thread_create(&thr, "", &attr, &thread_main, (void *)arg);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
|
||||
arg->thread = thr;
|
||||
if (!arg->block) {
|
||||
rc = ddsrt_thread_join(thr, &tres);
|
||||
CU_ASSERT_EQUAL_FATAL(rc, DDS_RETCODE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
/* verify the cleanup routine is called */
|
||||
CU_Test(ddsrt_thread_cleanup, push_one)
|
||||
{
|
||||
int flags = THREAD_RESET_1;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 0, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 2);
|
||||
CU_ASSERT_EQUAL(targ->executed, 1);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 0);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
/* verify all cleanup routines are called if multiple are registered */
|
||||
CU_Test(ddsrt_thread_cleanup, push_two)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 0, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 0);
|
||||
CU_ASSERT_EQUAL(targ->executed, 2);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 0);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
/* verify the first cleanup routine is still called if second got popped */
|
||||
CU_Test(ddsrt_thread_cleanup, push_two_pop_one_no_exec)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 1, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 2);
|
||||
CU_ASSERT_EQUAL(targ->executed, 1);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 1);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_thread_cleanup, push_two_pop_one_exec)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 1, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 0);
|
||||
CU_ASSERT_EQUAL(targ->executed, 2);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 1);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
/* verify no cleanup routines are called if all got popped */
|
||||
CU_Test(ddsrt_thread_cleanup, push_two_pop_two_no_exec)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 1);
|
||||
CU_ASSERT_EQUAL(targ->two, 2);
|
||||
CU_ASSERT_EQUAL(targ->executed, 0);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 2);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_thread_cleanup, push_two_pop_two_exec_one)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 2);
|
||||
CU_ASSERT_EQUAL(targ->executed, 1);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 2);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_thread_cleanup, push_two_pop_two_exec_both)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2 | THREAD_RUN_1 | THREAD_RUN_2;
|
||||
struct thread_argument *targ = make_thread_argument(flags, 2, 1, 2);
|
||||
setup(targ);
|
||||
|
||||
CU_ASSERT_EQUAL(targ->one, 0);
|
||||
CU_ASSERT_EQUAL(targ->two, 0);
|
||||
CU_ASSERT_EQUAL(targ->executed, 2);
|
||||
CU_ASSERT_EQUAL(targ->cancelled, 2);
|
||||
|
||||
ddsrt_free(targ);
|
||||
}
|
||||
|
||||
CU_Test(ddsrt_thread_cleanup, no_interference)
|
||||
{
|
||||
int flags = THREAD_RESET_1 | THREAD_RESET_2;
|
||||
struct thread_argument *targ1 = make_thread_argument(flags, 0, 1, 2);
|
||||
struct thread_argument *targ2 = make_thread_argument(flags, 2, 1, 2);
|
||||
ddsrt_mutex_t mutex1, mutex2;
|
||||
|
||||
ddsrt_mutex_init(&mutex1);
|
||||
ddsrt_mutex_init(&mutex2);
|
||||
ddsrt_mutex_lock(&mutex1);
|
||||
ddsrt_mutex_lock(&mutex2);
|
||||
|
||||
targ1->mutex = &mutex1;
|
||||
targ1->block = 1;
|
||||
targ2->mutex = &mutex2;
|
||||
targ2->block = 1;
|
||||
|
||||
setup(targ1);
|
||||
setup(targ2);
|
||||
|
||||
/* ensure thread 2 pops it's cleanup routines while thread 1 blocks */
|
||||
ddsrt_mutex_unlock(&mutex2);
|
||||
ddsrt_thread_join(targ2->thread, NULL);
|
||||
|
||||
CU_ASSERT_EQUAL(targ2->one, 1);
|
||||
CU_ASSERT_EQUAL(targ2->two, 2);
|
||||
CU_ASSERT_EQUAL(targ2->executed, 0);
|
||||
CU_ASSERT_EQUAL(targ2->cancelled, 2);
|
||||
|
||||
/* instruct thread 1 to continue */
|
||||
ddsrt_mutex_unlock(&mutex1);
|
||||
ddsrt_thread_join(targ1->thread, NULL);
|
||||
|
||||
CU_ASSERT_EQUAL(targ1->one, 0);
|
||||
CU_ASSERT_EQUAL(targ1->two, 0);
|
||||
CU_ASSERT_EQUAL(targ1->executed, 2);
|
||||
CU_ASSERT_EQUAL(targ1->cancelled, 0);
|
||||
|
||||
ddsrt_mutex_destroy(&mutex1);
|
||||
ddsrt_mutex_destroy(&mutex2);
|
||||
ddsrt_free(targ1);
|
||||
ddsrt_free(targ2);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue