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