From 79c086868f2b14e59b33ac9c3fb366c28721c8a3 Mon Sep 17 00:00:00 2001 From: Thijs Sassen Date: Thu, 19 Mar 2020 09:19:53 +0100 Subject: [PATCH 1/6] Fixed compile errors for targets that do not support IPV6 Signed-off-by: Thijs Sassen --- src/core/ddsi/src/ddsi_eth.c | 1 + src/core/ddsi/src/ddsi_tcp.c | 2 ++ src/core/ddsi/src/ddsi_udp.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/core/ddsi/src/ddsi_eth.c b/src/core/ddsi/src/ddsi_eth.c index 670667d..a36d314 100644 --- a/src/core/ddsi/src/ddsi_eth.c +++ b/src/core/ddsi/src/ddsi_eth.c @@ -16,6 +16,7 @@ int ddsi_eth_enumerate_interfaces (ddsi_tran_factory_t fact, enum transport_sele int afs[] = { AF_INET, DDSRT_AF_TERM }; (void)fact; + (void)transport_selector; #if DDSRT_HAVE_IPV6 if (transport_selector == TRANS_TCP6 || diff --git a/src/core/ddsi/src/ddsi_tcp.c b/src/core/ddsi/src/ddsi_tcp.c index de7a7e6..e6544e2 100644 --- a/src/core/ddsi/src/ddsi_tcp.c +++ b/src/core/ddsi/src/ddsi_tcp.c @@ -42,7 +42,9 @@ union addr { struct sockaddr a; struct sockaddr_in a4; +#if DDSRT_HAVE_IPV6 struct sockaddr_in6 a6; +#endif }; typedef struct ddsi_tcp_conn { diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 3410510..9f4e509 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -30,7 +30,9 @@ union addr { struct sockaddr_storage x; struct sockaddr a; struct sockaddr_in a4; +#if DDSRT_HAVE_IPV6 struct sockaddr_in6 a6; +#endif }; typedef struct ddsi_udp_conn { From 63f67ae965586971c136e79b6bf479f347b66660 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Fri, 20 Mar 2020 11:48:13 +0100 Subject: [PATCH 2/6] Fix IPv6 multicast breakage The moving around and cleaning up of network code broke the IPv6 multicast support by memcpy'ing a sockaddr_in6 instead of an in6_addr in a multicast join record. Signed-off-by: Erik Boasson --- src/core/ddsi/src/ddsi_udp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 9f4e509..65d10fd 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -561,7 +561,7 @@ static int joinleave_asm_mcgroup (ddsrt_socket_t socket, int join, const nn_loca { struct ipv6_mreq ipv6mreq; memset (&ipv6mreq, 0, sizeof (ipv6mreq)); - memcpy (&ipv6mreq.ipv6mr_multiaddr, &mcip.a6, sizeof (ipv6mreq.ipv6mr_multiaddr)); + ipv6mreq.ipv6mr_multiaddr = mcip.a6.sin6_addr; ipv6mreq.ipv6mr_interface = interf ? interf->if_index : 0; rc = ddsrt_setsockopt (socket, IPPROTO_IPV6, join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, &ipv6mreq, sizeof (ipv6mreq)); } @@ -592,8 +592,8 @@ static int joinleave_ssm_mcgroup (ddsrt_socket_t socket, int join, const nn_loca struct group_source_req gsr; memset (&gsr, 0, sizeof (gsr)); gsr.gsr_interface = interf ? interf->if_index : 0; - memcpy (&gsr.gsr_group, &mcip.a6, sizeof (gsr.gsr_group)); - memcpy (&gsr.gsr_source, &srcip.a6, sizeof (gsr.gsr_source)); + gsr.gsr_group = mcip.x; + gsr.gsr_source = srcip.x; rc = ddsrt_setsockopt (socket, IPPROTO_IPV6, join ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof (gsr)); } else From d089ce946c45c6b6dd9616392b38cf9583a3fc01 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Tue, 24 Mar 2020 18:50:09 +0100 Subject: [PATCH 3/6] Dedup function to create unique topic names in tests Signed-off-by: Erik Boasson --- src/core/ddsc/tests/CMakeLists.txt | 4 ++- src/core/ddsc/tests/basic.c | 2 +- src/core/ddsc/tests/builtin_topics.c | 7 ++-- src/core/ddsc/tests/config.c | 3 +- src/core/ddsc/tests/deadline.c | 16 ++------- src/core/ddsc/tests/dispose.c | 17 ++------- src/core/ddsc/tests/entity_hierarchy.c | 36 +++++++------------ src/core/ddsc/tests/entity_status.c | 17 +++------ src/core/ddsc/tests/lifespan.c | 17 ++------- src/core/ddsc/tests/listener.c | 15 ++------ src/core/ddsc/tests/liveliness.c | 30 ++++++---------- src/core/ddsc/tests/multi_sertopic.c | 16 ++------- src/core/ddsc/tests/querycondition.c | 17 ++------- src/core/ddsc/tests/read_instance.c | 18 ++-------- src/core/ddsc/tests/readcondition.c | 18 ++-------- src/core/ddsc/tests/reader.c | 22 +++--------- src/core/ddsc/tests/reader_iterator.c | 24 ++++--------- src/core/ddsc/tests/register.c | 18 ++-------- src/core/ddsc/tests/take_instance.c | 18 ++-------- src/core/ddsc/tests/test-common.c | 31 ---------------- src/core/ddsc/tests/test_common.c | 26 ++++++++++++++ .../tests/{test-common.h => test_common.h} | 14 ++++++-- src/core/ddsc/tests/topic.c | 19 +++------- src/core/ddsc/tests/unregister.c | 20 +++-------- src/core/ddsc/tests/unsupported.c | 2 +- src/core/ddsc/tests/waitset.c | 18 ++-------- src/core/ddsc/tests/whc.c | 17 ++------- src/core/ddsc/tests/write_various_types.c | 18 +++------- 28 files changed, 133 insertions(+), 347 deletions(-) delete mode 100644 src/core/ddsc/tests/test-common.c create mode 100644 src/core/ddsc/tests/test_common.c rename src/core/ddsc/tests/{test-common.h => test_common.h} (58%) diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index bdd239e..e0ed9f1 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -55,7 +55,9 @@ set(ddsc_test_sources "whc.c" "write.c" "write_various_types.c" - "writer.c") + "writer.c" + "test_common.c" + "test_common.h") if(ENABLE_LIFESPAN) list(APPEND ddsc_test_sources "lifespan.c") diff --git a/src/core/ddsc/tests/basic.c b/src/core/ddsc/tests/basic.c index b2bb597..d08b5b6 100644 --- a/src/core/ddsc/tests/basic.c +++ b/src/core/ddsc/tests/basic.c @@ -10,7 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" -#include "CUnit/Test.h" +#include "test_common.h" CU_Test(ddsc_basic, test) { diff --git a/src/core/ddsc/tests/builtin_topics.c b/src/core/ddsc/tests/builtin_topics.c index 747b1d2..3c511fd 100644 --- a/src/core/ddsc/tests/builtin_topics.c +++ b/src/core/ddsc/tests/builtin_topics.c @@ -10,10 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" -#include "RoundTrip.h" -#include "Space.h" -#include "test-common.h" -#include "CUnit/Test.h" +#include "test_common.h" static dds_entity_t g_participant = 0; static dds_entity_t g_subscriber = 0; @@ -336,7 +333,7 @@ CU_Test(ddsc_builtin_topics, read_nothing) CU_ASSERT_FATAL (ret == 0); ret = dds_return_loan (rd, &raw2, n2); CU_ASSERT_FATAL (ret == 0); - + ret = dds_delete (pp); CU_ASSERT_FATAL (ret == 0); } diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c index 82eda1b..f9e36c1 100644 --- a/src/core/ddsc/tests/config.c +++ b/src/core/ddsc/tests/config.c @@ -12,7 +12,6 @@ #include #include "dds/dds.h" -#include "CUnit/Test.h" #include "config_env.h" #include "dds/version.h" @@ -20,6 +19,8 @@ #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" +#include "test_common.h" + #define FORCE_ENV #define URI_VARIABLE DDS_PROJECT_NAME_NOSPACE_CAPS"_URI" diff --git a/src/core/ddsc/tests/deadline.c b/src/core/ddsc/tests/deadline.c index 818847a..e10bd74 100644 --- a/src/core/ddsc/tests/deadline.c +++ b/src/core/ddsc/tests/deadline.c @@ -13,9 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" #include "dds/ddsrt/environ.h" @@ -24,6 +21,8 @@ #include "dds/ddsi/q_whc.h" #include "dds__entity.h" +#include "test_common.h" + #define MAX_RUNS 4 #define WRITER_DEADLINE DDS_MSECS(50) @@ -42,15 +41,6 @@ static dds_entity_t g_remote_participant = 0; static dds_entity_t g_remote_subscriber = 0; static dds_entity_t g_remote_topic = 0; - -static char * create_topic_name(const char *prefix, char *name, size_t size) -{ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void sync_reader_writer(dds_entity_t participant, dds_entity_t reader, dds_entity_t writer) { dds_attach_t triggered; @@ -126,7 +116,7 @@ static void deadline_init(void) g_publisher = dds_create_publisher(g_participant, NULL, NULL); CU_ASSERT_FATAL(g_publisher > 0); - create_topic_name("ddsc_qos_deadline_test", name, sizeof name); + create_unique_topic_name("ddsc_qos_deadline_test", name, sizeof name); g_topic = dds_create_topic(g_participant, &Space_Type1_desc, name, NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_remote_topic = dds_create_topic(g_remote_participant, &Space_Type1_desc, name, NULL, NULL); diff --git a/src/core/ddsc/tests/dispose.c b/src/core/ddsc/tests/dispose.c index ef6435f..b0a0dc4 100644 --- a/src/core/ddsc/tests/dispose.c +++ b/src/core/ddsc/tests/dispose.c @@ -12,13 +12,12 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -41,16 +40,6 @@ static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; static dds_sample_info_t g_info[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void disposing_init(void) { @@ -69,7 +58,7 @@ disposing_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_disposing_test", name, sizeof name), qos, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_disposing_test", name, sizeof name), qos, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps one sample on three instances. */ diff --git a/src/core/ddsc/tests/entity_hierarchy.c b/src/core/ddsc/tests/entity_hierarchy.c index 44d5917..851cadb 100644 --- a/src/core/ddsc/tests/entity_hierarchy.c +++ b/src/core/ddsc/tests/entity_hierarchy.c @@ -12,14 +12,12 @@ #include #include "dds/dds.h" -#include "CUnit/Test.h" -#include "CUnit/Theory.h" -#include "RoundTrip.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -44,16 +42,6 @@ accept_all(const void * sample) return true; } -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void hierarchy_init(void) { @@ -63,7 +51,7 @@ hierarchy_init(void) g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(g_participant > 0 ); - g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_hierarchy_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_hierarchy_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_publisher = dds_create_publisher(g_participant, NULL, NULL); @@ -179,7 +167,7 @@ CU_Test(ddsc_entity_delete, recursive_with_deleted_topic) /* First, create a topic and a writer with that topic. */ g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(g_participant > 0); - g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_hierarchy_test", name, 100), NULL, NULL); + g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_hierarchy_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_writer = dds_create_writer(g_participant, g_topic, NULL, NULL); CU_ASSERT_FATAL(g_writer> 0); @@ -747,7 +735,7 @@ CU_Test(ddsc_entity_implicit_publisher, deleted) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_publisher_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_publisher_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); writer = dds_create_writer(participant, topic, NULL, NULL); @@ -799,7 +787,7 @@ CU_Test(ddsc_entity_implicit_subscriber, deleted) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_subscriber_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_subscriber_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); reader = dds_create_reader(participant, topic, NULL, NULL); @@ -854,7 +842,7 @@ CU_Test(ddsc_entity_get_children, implicit_publisher) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_publisher_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_publisher_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); writer = dds_create_writer(participant, topic, NULL, NULL); @@ -898,7 +886,7 @@ CU_Test(ddsc_entity_get_children, implicit_subscriber) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_subscriber_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_subscriber_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); reader = dds_create_reader(participant, topic, NULL, NULL); @@ -942,7 +930,7 @@ CU_Test(ddsc_entity_get_parent, implicit_publisher) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_publisher_promotion_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_publisher_promotion_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); writer = dds_create_writer(participant, topic, NULL, NULL); @@ -973,7 +961,7 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_subscriber_promotion_test", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_subscriber_promotion_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); reader = dds_create_reader(participant, topic, NULL, NULL); @@ -1005,7 +993,7 @@ CU_Test(ddsc_entity_implicit, delete_publisher) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_publisher", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_delete_publisher", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); writer = dds_create_writer(participant, topic, NULL, NULL); @@ -1037,7 +1025,7 @@ CU_Test(ddsc_entity_implicit, delete_subscriber) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(participant > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_entity_implicit_delete_subscriber", name, 100), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_entity_implicit_delete_subscriber", name, 100), NULL, NULL); CU_ASSERT_FATAL(topic > 0); reader = dds_create_reader(participant, topic, NULL, NULL); diff --git a/src/core/ddsc/tests/entity_status.c b/src/core/ddsc/tests/entity_status.c index 297f2cd..be14103 100644 --- a/src/core/ddsc/tests/entity_status.c +++ b/src/core/ddsc/tests/entity_status.c @@ -11,13 +11,13 @@ */ #include #include -#include "CUnit/Theory.h" -#include "dds/dds.h" -#include "RoundTrip.h" +#include "dds/dds.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /**************************************************************************** * Test globals. ****************************************************************************/ @@ -56,15 +56,6 @@ static dds_instance_handle_t writer_i_hdl = 0; /**************************************************************************** * Test initializations and teardowns. ****************************************************************************/ -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} static void init_entity_status(void) @@ -74,7 +65,7 @@ init_entity_status(void) participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT(participant > 0); - top = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_status_test", topicName, 100), NULL, NULL); + top = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_status_test", topicName, 100), NULL, NULL); CU_ASSERT(top > 0); qos = dds_create_qos(); diff --git a/src/core/ddsc/tests/lifespan.c b/src/core/ddsc/tests/lifespan.c index fea4079..ff296c4 100644 --- a/src/core/ddsc/tests/lifespan.c +++ b/src/core/ddsc/tests/lifespan.c @@ -13,9 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" #include "dds/ddsi/ddsi_entity_index.h" @@ -23,6 +20,8 @@ #include "dds/ddsi/q_whc.h" #include "dds__entity.h" +#include "test_common.h" + static dds_entity_t g_participant = 0; static dds_entity_t g_subscriber = 0; static dds_entity_t g_publisher = 0; @@ -33,16 +32,6 @@ static dds_entity_t g_waitset = 0; static dds_entity_t g_rcond = 0; static dds_entity_t g_qcond = 0; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void lifespan_init(void) { dds_attach_t triggered; @@ -65,7 +54,7 @@ static void lifespan_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_qos_lifespan_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_qos_lifespan_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); dds_qset_history(qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED); diff --git a/src/core/ddsc/tests/listener.c b/src/core/ddsc/tests/listener.c index 49a2915..1ad9f71 100644 --- a/src/core/ddsc/tests/listener.c +++ b/src/core/ddsc/tests/listener.c @@ -10,8 +10,6 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" -#include "RoundTrip.h" -#include "CUnit/Test.h" #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/misc.h" @@ -19,6 +17,8 @@ #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /**************************************************************************** * TODO: Add DDS_INCONSISTENT_TOPIC_STATUS test * TODO: Add DDS_OFFERED/REQUESTED_DEADLINE_MISSED_STATUS test @@ -311,15 +311,6 @@ waitfor_cb(uint32_t expected) /**************************************************************************** * Test initializations and teardowns. ****************************************************************************/ -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} static void init_triggering_base(void) @@ -340,7 +331,7 @@ init_triggering_base(void) g_publisher = dds_create_publisher(g_participant, NULL, NULL); CU_ASSERT_FATAL(g_publisher > 0); - g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_listener_test", name, 100), NULL, NULL); + g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_listener_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_listener = dds_create_listener(NULL); diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c index 04cec98..cf3adab 100644 --- a/src/core/ddsc/tests/liveliness.c +++ b/src/core/ddsc/tests/liveliness.c @@ -13,8 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" #include "config_env.h" #include "dds/version.h" @@ -29,12 +27,13 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/time.h" +#include "test_common.h" + #define DDS_DOMAINID_PUB 0 #define DDS_DOMAINID_SUB 1 #define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" #define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}cyclonedds_liveliness_tests.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.logfinest0" -uint32_t g_topic_nr = 0; static dds_entity_t g_pub_domain = 0; static dds_entity_t g_pub_participant = 0; static dds_entity_t g_pub_publisher = 0; @@ -43,15 +42,6 @@ static dds_entity_t g_sub_domain = 0; static dds_entity_t g_sub_participant = 0; static dds_entity_t g_sub_subscriber = 0; -static char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size) -{ - /* Get unique g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void)snprintf(name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); - return name; -} - static void liveliness_init(void) { /* Domains for pub and sub use a different domain id, but the portgain setting @@ -179,7 +169,7 @@ static void test_pmd_count(dds_liveliness_kind_t kind, uint32_t ldur, double mul dds_sleepfor(DDS_MSECS(50)); /* topics */ - create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_pmd_count", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -272,7 +262,7 @@ static void test_expire_liveliness_kinds(uint32_t ldur, double mult, uint32_t wr ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, remote_reader ? "remote" : "local"); /* topics */ - create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_expire_kinds", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -428,7 +418,7 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli uint32_t n; /* topics */ - create_topic_name("ddsc_liveliness_ldur", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_ldur", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -489,7 +479,7 @@ static void test_lease_duration_pwr(bool remote_reader) printf("running test lease_duration_pwr: %s reader\n", remote_reader ? "remote" : "local"); /* topics */ - create_topic_name("ddsc_liveliness_ldurpwr", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_ldurpwr", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -571,7 +561,7 @@ static void test_create_delete_writer_stress(bool remote_reader) printf("running test create_delete_writer_stress: %s reader\n", remote_reader ? "remote" : "local"); /* topics */ - create_topic_name("ddsc_liveliness_wr_stress", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_wr_stress", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -672,7 +662,7 @@ static void test_status_counts(bool remote_reader) printf("running test status_counts: %s reader\n", remote_reader ? "remote" : "local"); /* topics */ - create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_status_counts", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -772,7 +762,7 @@ static void test_assert_liveliness(uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur, remote_reader ? "remote" : "local"); /* topics */ - create_topic_name("ddsc_liveliness_assert", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_assert", name, sizeof name); CU_ASSERT_FATAL((pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); if (remote_reader) CU_ASSERT_FATAL((sub_topic = dds_create_topic(g_sub_participant, &Space_Type1_desc, name, NULL, NULL)) > 0); @@ -1018,7 +1008,7 @@ static void lease_duration_zero_or_one_impl (dds_duration_t sleep, dds_livelines dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); dds_qset_history(qos, DDS_HISTORY_KEEP_ALL, 0); - create_topic_name("ddsc_liveliness_lease_duration_zero", g_topic_nr++, name, sizeof name); + create_unique_topic_name("ddsc_liveliness_lease_duration_zero", name, sizeof name); pub_topic = dds_create_topic(g_pub_participant, &Space_Type1_desc, name, qos, NULL); CU_ASSERT_FATAL(pub_topic > 0); if (remote_reader) diff --git a/src/core/ddsc/tests/multi_sertopic.c b/src/core/ddsc/tests/multi_sertopic.c index 1bbdfbf..f66b89b 100644 --- a/src/core/ddsc/tests/multi_sertopic.c +++ b/src/core/ddsc/tests/multi_sertopic.c @@ -13,8 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" #include "config_env.h" #include "dds/version.h" @@ -30,6 +28,8 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/time.h" +#include "test_common.h" + #define DDS_DOMAINID_PUB 0 #define DDS_DOMAINID_SUB 1 #define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" @@ -167,7 +167,6 @@ static const dds_topic_descriptor_t type_ary2_desc = .m_meta = "" /* this is on its way out anyway */ }; -static uint32_t g_topic_nr = 0; static dds_entity_t g_pub_domain = 0; static dds_entity_t g_pub_participant = 0; static dds_entity_t g_pub_publisher = 0; @@ -176,15 +175,6 @@ static dds_entity_t g_sub_domain = 0; static dds_entity_t g_sub_participant = 0; static dds_entity_t g_sub_subscriber = 0; -static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) -{ - /* Get unique g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); - return name; -} - static void multi_sertopic_init (void) { /* Domains for pub and sub use a different domain id, but the portgain setting @@ -366,7 +356,7 @@ static void ddsc_multi_sertopic_impl (dds_entity_t pp_pub, dds_entity_t pp_sub, dds_qset_destination_order (qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); - create_topic_name ("ddsc_multi_sertopic_lease_duration_zero", g_topic_nr++, name, sizeof name); + create_unique_topic_name ("ddsc_multi_sertopic_lease_duration_zero", name, sizeof name); for (size_t i = 0; i < sizeof (pub_topics) / sizeof (pub_topics[0]); i++) { diff --git a/src/core/ddsc/tests/querycondition.c b/src/core/ddsc/tests/querycondition.c index d1afbf5..960437e 100644 --- a/src/core/ddsc/tests/querycondition.c +++ b/src/core/ddsc/tests/querycondition.c @@ -12,13 +12,12 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -68,16 +67,6 @@ filter_mod2(const void * sample) return (s->long_1 % 2 == 0); } -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void querycondition_init_hdepth(int hdepth) { @@ -93,7 +82,7 @@ querycondition_init_hdepth(int hdepth) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_querycondition_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_querycondition_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps last sample of all instances. */ diff --git a/src/core/ddsc/tests/read_instance.c b/src/core/ddsc/tests/read_instance.c index db46759..4c85e1b 100644 --- a/src/core/ddsc/tests/read_instance.c +++ b/src/core/ddsc/tests/read_instance.c @@ -13,13 +13,11 @@ #include #include "dds/dds.h" -#include "Space.h" -#include "RoundTrip.h" -#include "CUnit/Theory.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -67,16 +65,6 @@ filter_mod2(const void * sample) return (s->long_2 % 2 == 0); } -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void read_instance_init(void) { @@ -101,7 +89,7 @@ read_instance_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_read_instance_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_read_instance_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a writer that will not automatically dispose unregistered samples. */ diff --git a/src/core/ddsc/tests/readcondition.c b/src/core/ddsc/tests/readcondition.c index 4566d0c..af180a9 100644 --- a/src/core/ddsc/tests/readcondition.c +++ b/src/core/ddsc/tests/readcondition.c @@ -10,14 +10,12 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" -#include "CUnit/Test.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -60,16 +58,6 @@ static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; static dds_sample_info_t g_info[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void readcondition_init(void) { @@ -85,7 +73,7 @@ readcondition_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_readcondition_test", name, 100), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_readcondition_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps last sample of all instances. */ diff --git a/src/core/ddsc/tests/reader.c b/src/core/ddsc/tests/reader.c index 97f8131..ca5d9fe 100644 --- a/src/core/ddsc/tests/reader.c +++ b/src/core/ddsc/tests/reader.c @@ -13,14 +13,12 @@ #include #include "dds/dds.h" -#include "Space.h" -#include "RoundTrip.h" -#include "CUnit/Theory.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -64,16 +62,6 @@ static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; static dds_sample_info_t g_info[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void reader_init(void) { @@ -94,7 +82,7 @@ reader_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_reader_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_reader_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps last sample of all instances. */ @@ -306,7 +294,7 @@ CU_Test(ddsc_reader_create, participant_mismatch) sub1 = dds_create_subscriber(par1, NULL, NULL); CU_ASSERT_FATAL(sub1 > 0); - top2 = dds_create_topic(par2, &Space_Type1_desc, create_topic_name("ddsc_reader_participant_mismatch", name, sizeof name), NULL, NULL); + top2 = dds_create_topic(par2, &Space_Type1_desc, create_unique_topic_name("ddsc_reader_participant_mismatch", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(top2 > 0); /* Create reader with participant mismatch. */ @@ -2512,7 +2500,7 @@ CU_Test(ddsc_take_mask, take_instance_last_sample) CU_ASSERT_FATAL(g_participant > 0); g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_reader_test", name, 100), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_reader_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_reader = dds_create_reader(g_participant, g_topic, g_qos, NULL); CU_ASSERT_FATAL(g_reader > 0); diff --git a/src/core/ddsc/tests/reader_iterator.c b/src/core/ddsc/tests/reader_iterator.c index a714a67..df1e4c1 100644 --- a/src/core/ddsc/tests/reader_iterator.c +++ b/src/core/ddsc/tests/reader_iterator.c @@ -13,13 +13,11 @@ #include #include "dds/dds.h" -#include "Space.h" -#include "RoundTrip.h" -#include "CUnit/Theory.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -83,16 +81,6 @@ static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; static dds_sample_info_t g_info[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static bool filter_init(const void * sample) { @@ -140,7 +128,7 @@ reader_iterator_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_read_iterator_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_read_iterator_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a writer that will not automatically dispose unregistered samples. */ @@ -459,7 +447,8 @@ CU_Test(ddsc_read_next_wl, reader, .init=reader_iterator_init, .fini=reader_iter CU_ASSERT_EQUAL_FATAL(cnt, RDR_NOT_READ_CNT); CU_ASSERT_EQUAL_FATAL(cntinv, RDR_INV_READ_CNT); - ret = dds_return_loan(g_reader, g_loans, ret); + /* return_loan 3rd arg should be in [highest count ever returned, read limit] */ + ret = dds_return_loan(g_reader, g_loans, 1); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* All samples should still be available. */ @@ -683,7 +672,8 @@ CU_Test(ddsc_take_next_wl, reader, .init=reader_iterator_init, .fini=reader_iter CU_ASSERT_EQUAL_FATAL(cnt, RDR_NOT_READ_CNT); CU_ASSERT_EQUAL_FATAL(cntinv, RDR_INV_READ_CNT); - ret = dds_return_loan(g_reader, g_loans, ret); + /* return_loan 3rd arg should be in [highest count ever returned, read limit] */ + ret = dds_return_loan(g_reader, g_loans, 1); CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); /* All samples should still be available. */ diff --git a/src/core/ddsc/tests/register.c b/src/core/ddsc/tests/register.c index b04d35f..05aec4f 100644 --- a/src/core/ddsc/tests/register.c +++ b/src/core/ddsc/tests/register.c @@ -12,14 +12,12 @@ #include #include "dds/dds.h" -#include "CUnit/Test.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -41,16 +39,6 @@ static dds_time_t g_present = 0; static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void registering_init(void) { @@ -69,7 +57,7 @@ registering_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_registering_test", name, sizeof name), qos, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_registering_test", name, sizeof name), qos, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps one sample on three instances. */ diff --git a/src/core/ddsc/tests/take_instance.c b/src/core/ddsc/tests/take_instance.c index e8cba48..809ffae 100644 --- a/src/core/ddsc/tests/take_instance.c +++ b/src/core/ddsc/tests/take_instance.c @@ -13,13 +13,11 @@ #include #include "dds/dds.h" -#include "Space.h" -#include "RoundTrip.h" -#include "CUnit/Theory.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -67,16 +65,6 @@ filter_mod2(const void * sample) return (s->long_2 % 2 == 0); } -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void take_instance_init(void) { @@ -101,7 +89,7 @@ take_instance_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_take_instance_test", name, sizeof name), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_take_instance_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a writer that will not automatically dispose unregistered samples. */ diff --git a/src/core/ddsc/tests/test-common.c b/src/core/ddsc/tests/test-common.c deleted file mode 100644 index 44b846f..0000000 --- a/src/core/ddsc/tests/test-common.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 "dds/dds.h" - -const char* -entity_kind_str(dds_entity_t ent) { - if(ent <= 0) { - return "(ERROR)"; - } - switch(ent & DDS_ENTITY_KIND_MASK) { - case DDS_KIND_TOPIC: return "Topic"; - case DDS_KIND_PARTICIPANT: return "Participant"; - case DDS_KIND_READER: return "Reader"; - case DDS_KIND_WRITER: return "Writer"; - case DDS_KIND_SUBSCRIBER: return "Subscriber"; - case DDS_KIND_PUBLISHER: return "Publisher"; - case DDS_KIND_COND_READ: return "ReadCondition"; - case DDS_KIND_COND_QUERY: return "QueryCondition"; - case DDS_KIND_WAITSET: return "WaitSet"; - default: return "(INVALID_ENTITY)"; - } -} diff --git a/src/core/ddsc/tests/test_common.c b/src/core/ddsc/tests/test_common.c new file mode 100644 index 0000000..531322b --- /dev/null +++ b/src/core/ddsc/tests/test_common.c @@ -0,0 +1,26 @@ +/* + * 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 "dds/dds.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/threads.h" +#include "test_common.h" + +char *create_unique_topic_name (const char *prefix, char *name, size_t size) +{ + static ddsrt_atomic_uint32_t count = DDSRT_ATOMIC_UINT64_INIT (0); + const ddsrt_pid_t pid = ddsrt_getpid(); + const ddsrt_tid_t tid = ddsrt_gettid(); + const uint32_t nr = ddsrt_atomic_inc32_nv (&count); + (void) snprintf (name, size, "%s%"PRIu32"_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); + return name; +} diff --git a/src/core/ddsc/tests/test-common.h b/src/core/ddsc/tests/test_common.h similarity index 58% rename from src/core/ddsc/tests/test-common.h rename to src/core/ddsc/tests/test_common.h index 917e4b9..6672d93 100644 --- a/src/core/ddsc/tests/test-common.h +++ b/src/core/ddsc/tests/test_common.h @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2006 to 2020 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 @@ -12,6 +12,16 @@ #ifndef _TEST_COMMON_H_ #define _TEST_COMMON_H_ -const char *entity_kind_str(dds_entity_t ent); +#include +#include + +#include "CUnit/Test.h" +#include "CUnit/Theory.h" + +#include "Space.h" +#include "RoundTrip.h" + +/* Get unique g_topic name on each invocation. */ +char *create_unique_topic_name (const char *prefix, char *name, size_t size); #endif /* _TEST_COMMON_H_ */ diff --git a/src/core/ddsc/tests/topic.c b/src/core/ddsc/tests/topic.c index 0142a4d..ee90a12 100644 --- a/src/core/ddsc/tests/topic.c +++ b/src/core/ddsc/tests/topic.c @@ -10,13 +10,12 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include "dds/dds.h" -#include "RoundTrip.h" -#include "CUnit/Theory.h" - #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -36,21 +35,11 @@ char g_topicRtmAddressName[MAX_NAME_SIZE]; char g_topicRtmDataTypeName[MAX_NAME_SIZE]; char g_nameBuffer[MAX_NAME_SIZE]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void ddsc_topic_init(void) { - create_topic_name("ddsc_topic_test_rtm_address", g_topicRtmAddressName, MAX_NAME_SIZE); - create_topic_name("ddsc_topic_test_rtm_datatype", g_topicRtmDataTypeName, MAX_NAME_SIZE); + create_unique_topic_name("ddsc_topic_test_rtm_address", g_topicRtmAddressName, MAX_NAME_SIZE); + create_unique_topic_name("ddsc_topic_test_rtm_datatype", g_topicRtmDataTypeName, MAX_NAME_SIZE); g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(g_participant > 0); diff --git a/src/core/ddsc/tests/unregister.c b/src/core/ddsc/tests/unregister.c index 538c661..e3dcf00 100644 --- a/src/core/ddsc/tests/unregister.c +++ b/src/core/ddsc/tests/unregister.c @@ -13,13 +13,11 @@ #include #include "dds/dds.h" -#include "CUnit/Test.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" +#include "test_common.h" + /************************************************************************************************** * * Test fixtures @@ -41,16 +39,6 @@ static void* g_samples[MAX_SAMPLES]; static Space_Type1 g_data[MAX_SAMPLES]; static dds_sample_info_t g_info[MAX_SAMPLES]; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - static void unregistering_init(void) { @@ -69,7 +57,7 @@ unregistering_init(void) g_waitset = dds_create_waitset(g_participant); CU_ASSERT_FATAL(g_waitset > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_unregistering_test", name, 100), qos, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_unregistering_test", name, 100), qos, NULL); CU_ASSERT_FATAL(g_topic > 0); /* Create a reader that keeps one sample on three instances. */ @@ -616,7 +604,7 @@ CU_Test(ddsc_unregister_instance_ih_ts, unregistering_instance) /* Create a writer that WILL automatically dispose unregistered samples. */ g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); CU_ASSERT_FATAL(g_participant > 0); - g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_topic_name("ddsc_unregistering_instance_test", name, 100), NULL, NULL); + g_topic = dds_create_topic(g_participant, &Space_Type1_desc, create_unique_topic_name("ddsc_unregistering_instance_test", name, 100), NULL, NULL); CU_ASSERT_FATAL(g_topic > 0); g_writer = dds_create_writer(g_participant, g_topic, NULL, NULL); CU_ASSERT_FATAL(g_writer > 0); diff --git a/src/core/ddsc/tests/unsupported.c b/src/core/ddsc/tests/unsupported.c index 9c538ce..6ec39cc 100644 --- a/src/core/ddsc/tests/unsupported.c +++ b/src/core/ddsc/tests/unsupported.c @@ -15,7 +15,7 @@ #include "dds/dds.h" #include "RoundTrip.h" -#include "test-common.h" +#include "test_common.h" static dds_entity_t e[8]; diff --git a/src/core/ddsc/tests/waitset.c b/src/core/ddsc/tests/waitset.c index 1f6e0b5..0f69025 100644 --- a/src/core/ddsc/tests/waitset.c +++ b/src/core/ddsc/tests/waitset.c @@ -13,9 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "RoundTrip.h" - #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/misc.h" #include "dds/ddsrt/process.h" @@ -23,6 +20,8 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/time.h" +#include "test_common.h" + /************************************************************************************************** * * Some thread related convenience stuff. @@ -63,17 +62,6 @@ static dds_entity_t subscriber = 0; static dds_entity_t readcond = 0; -static char* -create_topic_name(const char *prefix, char *name, size_t size) -{ - /* Get semi random g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid(); - ddsrt_tid_t tid = ddsrt_gettid(); - (void) snprintf(name, size, "%s_pid%"PRIdPID"_tid%"PRIdTID"", prefix, pid, tid); - return name; -} - - static void ddsc_waitset_basic_init(void) { @@ -109,7 +97,7 @@ ddsc_waitset_init(void) subscriber = dds_create_subscriber(participant, NULL, NULL); CU_ASSERT_FATAL(subscriber > 0); - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_topic_name("ddsc_waitset_test", name, sizeof name), NULL, NULL); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_waitset_test", name, sizeof name), NULL, NULL); CU_ASSERT_FATAL(topic > 0); reader = dds_create_reader(subscriber, topic, NULL, NULL); diff --git a/src/core/ddsc/tests/whc.c b/src/core/ddsc/tests/whc.c index cdade5e..93fda9e 100644 --- a/src/core/ddsc/tests/whc.c +++ b/src/core/ddsc/tests/whc.c @@ -13,9 +13,6 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "Space.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" #include "dds/ddsrt/environ.h" @@ -24,6 +21,8 @@ #include "dds/ddsi/q_whc.h" #include "dds__entity.h" +#include "test_common.h" + #define DDS_DOMAINID_PUB 0 #define DDS_DOMAINID_SUB 1 #define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" @@ -32,7 +31,6 @@ #define SAMPLE_COUNT 5 #define DEADLINE_DURATION DDS_MSECS(1) -static uint32_t g_topic_nr = 0; static dds_entity_t g_domain = 0; static dds_entity_t g_participant = 0; static dds_entity_t g_subscriber = 0; @@ -42,15 +40,6 @@ static dds_entity_t g_remote_domain = 0; static dds_entity_t g_remote_participant = 0; static dds_entity_t g_remote_subscriber = 0; -static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) -{ - /* Get unique g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid (); - ddsrt_tid_t tid = ddsrt_gettid (); - (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); - return name; -} - static void whc_init(void) { /* Domains for pub and sub use a different domain id, but the portgain setting @@ -177,7 +166,7 @@ static void test_whc_end_state(dds_durability_kind_t d, dds_reliability_kind_t r dds_qset_deadline (g_qos, dl ? DEADLINE_DURATION : DDS_INFINITY); dds_qset_durability_service (g_qos, 0, dh, dh == KA ? 0 : dhd, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED, DDS_LENGTH_UNLIMITED); - create_topic_name ("ddsc_whc_end_state_test", g_topic_nr++, name, sizeof name); + create_unique_topic_name ("ddsc_whc_end_state_test", name, sizeof name); topic = dds_create_topic (g_participant, k ? &Space_Type1_desc : &Space_Type3_desc, name, NULL, NULL); CU_ASSERT_FATAL(topic > 0); remote_topic = dds_create_topic (g_remote_participant, k ? &Space_Type1_desc : &Space_Type3_desc, name, NULL, NULL); diff --git a/src/core/ddsc/tests/write_various_types.c b/src/core/ddsc/tests/write_various_types.c index 861a627..b1f05c3 100644 --- a/src/core/ddsc/tests/write_various_types.c +++ b/src/core/ddsc/tests/write_various_types.c @@ -13,19 +13,18 @@ #include #include "dds/dds.h" -#include "CUnit/Theory.h" -#include "WriteTypes.h" - #include "dds/ddsrt/process.h" #include "dds/ddsrt/threads.h" #include "dds/ddsrt/environ.h" +#include "test_common.h" +#include "WriteTypes.h" + #define DDS_DOMAINID_PUB 0 #define DDS_DOMAINID_SUB 1 #define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0" #define DDS_CONFIG_NO_PORT_GAIN_LOG "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}cyclonedds_writetypes_various.${CYCLONEDDS_DOMAIN_ID}.${CYCLONEDDS_PID}.logfinest0" -static uint32_t g_topic_nr = 0; static dds_entity_t g_pub_domain = 0; static dds_entity_t g_pub_participant = 0; static dds_entity_t g_pub_publisher = 0; @@ -34,15 +33,6 @@ static dds_entity_t g_sub_domain = 0; static dds_entity_t g_sub_participant = 0; static dds_entity_t g_sub_subscriber = 0; -static char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) -{ - /* Get unique g_topic name. */ - ddsrt_pid_t pid = ddsrt_getpid (); - ddsrt_tid_t tid = ddsrt_gettid (); - (void) snprintf (name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); - return name; -} - static void writetypes_init(void) { /* Domains for pub and sub use a different domain id, but the portgain setting @@ -152,7 +142,7 @@ CU_Theory((const dds_topic_descriptor_t *desc, compare_fn_t cmp, size_t nsamples CU_ASSERT_FATAL (qos != NULL); dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (1)); dds_qset_writer_data_lifecycle (qos, false); - create_topic_name ("ddsc_writetypes_various", g_topic_nr++, name, sizeof name); + create_unique_topic_name ("ddsc_writetypes_various", name, sizeof name); pub_topic = dds_create_topic (g_pub_participant, desc, name, qos, NULL); CU_ASSERT_FATAL (pub_topic > 0); sub_topic = dds_create_topic (g_sub_participant, desc, name, qos, NULL); From 5d53e740296873b2a70ee62536b2fe513526678c Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Tue, 24 Mar 2020 18:51:29 +0100 Subject: [PATCH 4/6] Fix read/take/return_loan edge cases * read/take failed to restore the null pointer in the first entry of the sample pointer array it gets passed, in the case no "loan" had been allocated yet and it returned an empty set. The consequence is that on a subsequence read it will reuse the address without marking at as in use, so that a *second* read using with a null pointer in that first entry will overwrite the first result. (Introduced by d16264fd82.) * return_loan failed to free all memory if its argument wasn't actually a loan. There are many good arguments why the read/take/return_loan interface is messed up, but in the context of the existing interface this is a perfectly reasonable case: there is at most one "loan" for each reader, but one can keep calling read/take and return_loan as if there's an infinite number of "loans". It's just that the first gets cached and the others don't. Signed-off-by: Erik Boasson --- src/core/ddsc/src/dds_read.c | 54 +++-- src/core/ddsc/tests/CMakeLists.txt | 2 +- src/core/ddsc/tests/loan.c | 321 +++++++++++++++++++++++++++++ src/core/ddsc/tests/return_loan.c | 140 ------------- 4 files changed, 363 insertions(+), 154 deletions(-) create mode 100644 src/core/ddsc/tests/loan.c delete mode 100644 src/core/ddsc/tests/return_loan.c diff --git a/src/core/ddsc/src/dds_read.c b/src/core/ddsc/src/dds_read.c index 394b7e4..701f50d 100644 --- a/src/core/ddsc/src/dds_read.c +++ b/src/core/ddsc/src/dds_read.c @@ -94,7 +94,6 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, rd->m_loan = buf[0]; rd->m_loan_size = maxs; } - nodata_cleanups = NC_RESET_BUF; } else { @@ -103,7 +102,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, rd->m_loan_size = maxs; } rd->m_loan_out = true; - nodata_cleanups |= NC_CLEAR_LOAN_OUT; + nodata_cleanups = NC_RESET_BUF | NC_CLEAR_LOAN_OUT; } ddsrt_mutex_unlock (&rd->m_entity.m_mutex); } @@ -457,12 +456,11 @@ dds_return_t dds_take_next_wl (dds_entity_t reader, void **buf, dds_sample_info_ dds_return_t dds_return_loan (dds_entity_t reader_or_condition, void **buf, int32_t bufsz) { - const struct ddsi_sertopic *st; dds_reader *rd; dds_entity *entity; - dds_return_t ret = DDS_RETCODE_OK; + dds_return_t ret; - if (buf == NULL || (*buf == NULL && bufsz > 0)) + if (buf == NULL || (buf[0] == NULL && bufsz > 0) || (buf[0] != NULL && bufsz <= 0)) return DDS_RETCODE_BAD_PARAMETER; if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { @@ -476,16 +474,46 @@ dds_return_t dds_return_loan (dds_entity_t reader_or_condition, void **buf, int3 rd = (dds_reader *) entity->m_parent; } - st = rd->m_topic->m_stopic; - for (int32_t i = 0; i < bufsz; i++) - ddsi_sertopic_free_sample (st, buf[i], DDS_FREE_CONTENTS); - - /* If possible return loan buffer to reader */ - ddsrt_mutex_lock (&rd->m_entity.m_mutex); - if (rd->m_loan != 0 && (buf[0] == rd->m_loan)) + if (bufsz <= 0) { - rd->m_loan_out = false; + /* No data whatsoever, or an invocation following a failed read/take call. Read/take + already take care of restoring the state prior to their invocation if they return + no data. Return late so invalid handles can be detected. */ + dds_entity_unpin (entity); + return DDS_RETCODE_OK; + } + assert (buf[0] != NULL); + + const struct ddsi_sertopic *st = rd->m_topic->m_stopic; + + /* The potentially time consuming part of what happens here (freeing samples) + can safely be done without holding the reader lock, but that particular + lock is not used during insertion of data & triggering waitsets (that's + the observer_lock), so holding it for a bit longer in return for simpler + code is a fair trade-off. */ + ddsrt_mutex_lock (&rd->m_entity.m_mutex); + if (buf[0] != rd->m_loan) + { + /* Not so much a loan as a buffer allocated by the middleware on behalf of the + application. So it really is no more than a sophisticated variant of "free". */ + ddsi_sertopic_free_samples (st, buf, (size_t) bufsz, DDS_FREE_ALL); + buf[0] = NULL; + } + else if (!rd->m_loan_out) + { + /* Trying to return a loan that has been returned already */ + ddsrt_mutex_unlock (&rd->m_entity.m_mutex); + dds_entity_unpin (entity); + return DDS_RETCODE_PRECONDITION_NOT_MET; + } + else + { + /* Free only the memory referenced from the samples, not the samples themselves. + Zero them to guarantee the absence of dangling pointers that might cause + trouble on a following operation. FIXME: there's got to be a better way */ + ddsi_sertopic_free_samples (st, buf, (size_t) bufsz, DDS_FREE_CONTENTS); ddsi_sertopic_zero_samples (st, rd->m_loan, rd->m_loan_size); + rd->m_loan_out = false; buf[0] = NULL; } ddsrt_mutex_unlock (&rd->m_entity.m_mutex); diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index e0ed9f1..b2728b9 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -30,6 +30,7 @@ set(ddsc_test_sources "instance_get_key.c" "listener.c" "liveliness.c" + "loan.c" "multi_sertopic.c" "participant.c" "publisher.c" @@ -41,7 +42,6 @@ set(ddsc_test_sources "reader_iterator.c" "read_instance.c" "register.c" - "return_loan.c" "subscriber.c" "take_instance.c" "time.c" diff --git a/src/core/ddsc/tests/loan.c b/src/core/ddsc/tests/loan.c new file mode 100644 index 0000000..5e12d84 --- /dev/null +++ b/src/core/ddsc/tests/loan.c @@ -0,0 +1,321 @@ +/* + * Copyright(c) 2006 to 2020 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 +#include "dds/dds.h" +#include "test_common.h" + +static dds_entity_t participant, topic, reader, writer, read_condition, read_condition_unread; + +static void create_entities (void) +{ + char topicname[100]; + struct dds_qos *qos; + + create_unique_topic_name ("ddsc_return_loan_test", topicname, sizeof topicname); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL (participant > 0); + + qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, 0); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 1); + topic = dds_create_topic (participant, &RoundTripModule_DataType_desc, topicname, qos, NULL); + CU_ASSERT_FATAL (topic > 0); + dds_delete_qos (qos); + + writer = dds_create_writer (participant, topic, NULL, NULL); + CU_ASSERT_FATAL (writer > 0); + reader = dds_create_reader (participant, topic, NULL, NULL); + CU_ASSERT_FATAL (reader > 0); + read_condition = dds_create_readcondition (reader, DDS_ANY_STATE); + CU_ASSERT_FATAL (read_condition > 0); + read_condition_unread = dds_create_readcondition (reader, DDS_ANY_INSTANCE_STATE | DDS_ANY_VIEW_STATE | DDS_NOT_READ_SAMPLE_STATE); + CU_ASSERT_FATAL (read_condition > 0); +} + +static void delete_entities (void) +{ + dds_return_t result; + result = dds_delete (participant); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); +} + +CU_Test (ddsc_loan, bad_params, .init = create_entities, .fini = delete_entities) +{ + dds_return_t result; + + /* buf = NULL */ + result = dds_return_loan (reader, NULL, -1); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + result = dds_return_loan (reader, NULL, 0); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + result = dds_return_loan (reader, NULL, 1); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + + /* buf[0] = NULL, size > 0 */ + void *buf = NULL; + result = dds_return_loan (reader, &buf, 1); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + /* buf[0] != NULL, size <= 0 */ + char dummy = 0; + buf = &dummy; + result = dds_return_loan (reader, &buf, 0); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + result = dds_return_loan (reader, &buf, -1); + CU_ASSERT (result == DDS_RETCODE_BAD_PARAMETER); + + /* not a reader or condition (checking only the ones we have at hand) */ + result = dds_return_loan (participant, &buf, 1); + CU_ASSERT (result == DDS_RETCODE_ILLEGAL_OPERATION); + result = dds_return_loan (topic, &buf, 1); + CU_ASSERT (result == DDS_RETCODE_ILLEGAL_OPERATION); +} + +CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities) +{ + const RoundTripModule_DataType s = { + .payload = { + ._length = 1, + ._buffer = (uint8_t[]) { 'a' } + } + }; + const unsigned char zeros[3 * sizeof (s)] = { 0 }; + dds_return_t result; + for (size_t i = 0; i < 3; i++) + { + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + } + + /* rely on things like address sanitizer, valgrind for detecting double frees and leaks */ + int32_t n; + void *ptrs[3] = { NULL }; + void *ptr0copy, *ptr1copy; + dds_sample_info_t si[3]; + + /* read 1, return: this should cause memory to be allocated for 1 sample only */ + n = dds_read (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] != NULL && ptrs[1] == NULL); + ptr0copy = ptrs[0]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + /* return resets buf[0] (so that it picks up the loan the next time) and zeros the data */ + CU_ASSERT_FATAL (ptrs[0] == NULL); + CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); + + /* read 3, return: should work fine, causes realloc */ + n = dds_read (reader, ptrs, si, 3, 3); + CU_ASSERT_FATAL (n == 3); + CU_ASSERT_FATAL (ptrs[0] != NULL && ptrs[1] != NULL && ptrs[2] != NULL); + ptr0copy = ptrs[0]; + ptr1copy = ptrs[1]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + CU_ASSERT_FATAL (ptrs[0] == NULL); + CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, 3 * sizeof (s)) == 0); + + /* read 1 using loan, expecting to get the same address (no realloc needed), defer return. + Expect ptrs[1] to remain unchanged, although that probably is really an implementation + detail rather than something one might want to rely on */ + n = dds_read (read_condition, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == ptr1copy); + + /* read 3, letting read allocate */ + int32_t n2; + void *ptrs2[3] = { NULL }; + n2 = dds_read (read_condition, ptrs2, si, 3, 3); + CU_ASSERT_FATAL (n2 == 3); + CU_ASSERT_FATAL (ptrs2[0] != NULL && ptrs2[1] != NULL && ptrs2[2] != NULL); + CU_ASSERT_FATAL (ptrs2[0] != ptrs[0]); + + /* contents of first sample should be the same; the point of comparing them + is that valgrind/address sanitizer will get angry with us if one of them + has been freed; can't use memcmp because the sequence buffers should be + at different addresses */ + { + const struct RoundTripModule_DataType *a = ptrs[0]; + const struct RoundTripModule_DataType *b = ptrs2[0]; + CU_ASSERT_FATAL (a->payload._length == b->payload._length); + CU_ASSERT_FATAL (a->payload._buffer != b->payload._buffer); + CU_ASSERT_FATAL (a->payload._buffer[0] == b->payload._buffer[0]); + } + + /* return loan -- to be freed when we delete the reader */ + result = dds_return_loan (read_condition, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + CU_ASSERT_FATAL (ptrs[0] == NULL); + + /* use "dds_return_loan" to free the second result immediately, there's no + easy way to check this happens short of using a custom sertopic */ + ptr0copy = ptrs2[0]; + result = dds_return_loan (read_condition, ptrs2, n2); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + CU_ASSERT_FATAL (ptrs2[0] == NULL); + + //This should be a use-after-free + //CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); +} + +CU_Test (ddsc_loan, take_cleanup, .init = create_entities, .fini = delete_entities) +{ + const RoundTripModule_DataType s = { + .payload = { + ._length = 1, + ._buffer = (uint8_t[]) { 'a' } + } + }; + dds_return_t result; + + /* rely on things like address sanitizer, valgrind for detecting double frees and leaks */ + int32_t n; + void *ptrs[3] = { NULL }; + void *ptr0copy; + dds_sample_info_t si[3]; + + /* take 1 from an empty reader: this should cause memory to be allocated for + 1 sample only, be stored as the loan, but not become visisble to the + application */ + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 0); + CU_ASSERT_FATAL (ptrs[0] == NULL && ptrs[1] == NULL); + + /* take 1 that's present: allocates a loan */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] != NULL && ptrs[1] == NULL); + ptr0copy = ptrs[0]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + + /* if it really got handled as a loan, the same address must come out again + (rely on address sanitizer allocating at a different address each time) */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + ptr0copy = ptrs[0]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + + /* take that fails (for lack of data in this case) must reuse the loan, but + hand it back and restore the null pointer */ + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 0); + CU_ASSERT_FATAL (ptrs[0] == NULL && ptrs[1] == NULL); + + /* take that succeeds again must therefore still be using the same address */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + + /* take that fails (with the loan still out) must allocate new memory and + free it */ + int32_t n2; + void *ptrs2[3] = { NULL }; + n2 = dds_take (reader, ptrs2, si, 1, 1); + CU_ASSERT_FATAL (n2 == 0); + CU_ASSERT_FATAL (ptrs2[0] == NULL && ptrs2[1] == NULL); + + /* return the loan and the next take should reuse the memory */ + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); +} + +CU_Test (ddsc_loan, read_cleanup, .init = create_entities, .fini = delete_entities) +{ + const RoundTripModule_DataType s = { + .payload = { + ._length = 1, + ._buffer = (uint8_t[]) { 'a' } + } + }; + dds_return_t result; + + /* rely on things like address sanitizer, valgrind for detecting double frees and leaks */ + int32_t n; + void *ptrs[3] = { NULL }; + void *ptr0copy; + dds_sample_info_t si[3]; + + /* read 1 from an empty reader: this should cause memory to be allocated for + 1 sample only, be stored as the loan, but not become visisble to the + application */ + n = dds_read (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 0); + CU_ASSERT_FATAL (ptrs[0] == NULL && ptrs[1] == NULL); + + /* read 1 that's present: allocates a loan */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_take (reader, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] != NULL && ptrs[1] == NULL); + ptr0copy = ptrs[0]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + + /* if it really got handled as a loan, the same address must come out again + (rely on address sanitizer allocating at a different address each time) */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_read (read_condition_unread, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + ptr0copy = ptrs[0]; + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + + /* take that fails (for lack of data in this case) must reuse the loan, but + hand it back and restore the null pointer */ + n = dds_read (read_condition_unread, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 0); + CU_ASSERT_FATAL (ptrs[0] == NULL && ptrs[1] == NULL); + + /* take that succeeds again must therefore still be using the same address */ + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_read (read_condition_unread, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + + /* take that fails (with the loan still out) must allocate new memory and + free it */ + int32_t n2; + void *ptrs2[3] = { NULL }; + n2 = dds_read (read_condition_unread, ptrs2, si, 1, 1); + CU_ASSERT_FATAL (n2 == 0); + CU_ASSERT_FATAL (ptrs2[0] == NULL && ptrs2[1] == NULL); + + /* return the loan and the next take should reuse the memory */ + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); + result = dds_write (writer, &s); + CU_ASSERT_FATAL (result == 0); + n = dds_read (read_condition_unread, ptrs, si, 1, 1); + CU_ASSERT_FATAL (n == 1); + CU_ASSERT_FATAL (ptrs[0] == ptr0copy && ptrs[1] == NULL); + result = dds_return_loan (reader, ptrs, n); + CU_ASSERT_FATAL (result == DDS_RETCODE_OK); +} diff --git a/src/core/ddsc/tests/return_loan.c b/src/core/ddsc/tests/return_loan.c deleted file mode 100644 index 812e024..0000000 --- a/src/core/ddsc/tests/return_loan.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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 "dds/dds.h" -#include "RoundTrip.h" - -#include -#include "CUnit/Test.h" - -static dds_entity_t participant = 0, topic = 0, reader = 0, read_condition = 0; - -static void create_entities(void) -{ - participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); - CU_ASSERT_FATAL(participant > 0); - - topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_reader_return_loan_RoundTrip", NULL, NULL); - CU_ASSERT_FATAL(topic > 0); - - reader = dds_create_reader(participant, topic, NULL, NULL); - CU_ASSERT_FATAL(reader > 0); - - read_condition = dds_create_readcondition(reader, DDS_ANY_STATE); - CU_ASSERT_FATAL(read_condition > 0); -} - -static void delete_entities(void) -{ - dds_return_t result; - result = dds_delete(participant); - CU_ASSERT_EQUAL_FATAL(result, DDS_RETCODE_OK); - dds_delete(read_condition); -} - -static void** create_loan_buf(size_t sz, bool empty) -{ - size_t i; - void **buf = NULL; - buf = dds_alloc(sz * sizeof(*buf)); - for (i = 0; i < sz; i++) { - buf[i] = dds_alloc(sizeof(RoundTripModule_DataType)); - if (empty) { - memset(buf[i], 0, sizeof(RoundTripModule_DataType)); - } else { - RoundTripModule_DataType *s = buf[i]; - s->payload._maximum = 0; - s->payload._length = 25; - s->payload._buffer = dds_alloc(25); - memset(s->payload._buffer, 'z', 25); - s->payload._release = true; - } - } - return buf; -} - -static void delete_loan_buf(void **buf, size_t sz, bool empty) -{ - size_t i; - for (i = 0; i < sz; i++) { - RoundTripModule_DataType *s = buf[i]; - if (!empty) { - CU_ASSERT(s->payload._length > 0); - if (s->payload._length > 0) { - /* Freed by a successful dds_return_loan */ - dds_free(s->payload._buffer); - } - } - /* dds_return_loan only free's sample contents */ - dds_free(s); - } - dds_free(buf); -} - -/* Verify DDS_RETCODE_BAD_PARAMETER is returned */ -CU_Test(ddsc_reader, return_loan_bad_params, .init = create_entities, .fini = delete_entities) -{ - dds_return_t result; - void **buf = NULL; - - result = dds_return_loan(reader, NULL, 0); - CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 6387) -#endif - result = dds_return_loan(reader, buf, 10); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); - - buf = create_loan_buf(10, false); -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 28020) -#endif - result = dds_return_loan(0, buf, 10); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - CU_ASSERT_EQUAL(result, DDS_RETCODE_BAD_PARAMETER); - - result = dds_return_loan(participant, buf, 0); - CU_ASSERT_EQUAL(result, DDS_RETCODE_ILLEGAL_OPERATION); - - delete_loan_buf(buf, 10, false); -} - -/* Verify DDS_RETCODE_OK is returned */ -CU_Test(ddsc_reader, return_loan_success, .init = create_entities, .fini = delete_entities) -{ - void **buf; - void *buf2 = NULL; - dds_return_t result; - - buf = create_loan_buf(10, false); - result = dds_return_loan(reader, buf, 10); - CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); - - result = dds_return_loan(reader, &buf2, 0); - CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); - delete_loan_buf(buf, 10, true); - - buf = create_loan_buf(10, false); - result = dds_return_loan(read_condition, buf, 10); - CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); - - result = dds_return_loan(read_condition, &buf2, 0); - CU_ASSERT_EQUAL(result, DDS_RETCODE_OK); - delete_loan_buf(buf, 10, true); -} From 1c31fba043e9ce801024c1d5d88384893893916f Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Fri, 27 Mar 2020 10:31:42 +0100 Subject: [PATCH 5/6] Fix race in deleting lingering writers Deleting a writer with unacknowledged data present in its WHC causes it to linger for a configurable duration. Once it is lingering, there are two routes to actually deleting the writer: because the samples get acknowledged, or because the linger duration elapses. When these two happen roughly concurrently, there was a possibility of both succeeding in looking up the writer by its GUID, in which case one of them then asserts on removing it from the entity index (if assertions are enabled, if not, things are worse). This fixes that by ensuring only one of the two actually does something, as was always the intent. Signed-off-by: Erik Boasson --- src/core/ddsi/src/q_entity.c | 17 ++++++++++++++++- src/core/ddsi/src/q_xevent.c | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index e9f9e8e..d2ecf93 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -3393,8 +3393,23 @@ dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout) dds_return_t delete_writer_nolinger_locked (struct writer *wr) { - ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid)); ASSERT_MUTEX_HELD (&wr->e.lock); + + /* We can get here via multiple paths in parallel, in particular: because all data got + ACK'd while lingering, and because the linger timeout elapses. Those two race each + other, the first calling this function directly, the second calling from + handle_xevk_delete_writer via delete_writer_nolinger. + + There are two practical options to decide whether to ignore the call: one is to check + whether the writer is still in the GUID hashes, the second to check whether the state + is WRST_DELETING. The latter seems a bit less surprising. */ + if (wr->state == WRST_DELETING) + { + ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") already done\n", PGUID (wr->e.guid)); + return 0; + } + + ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid)); builtintopic_write (wr->e.gv->builtin_topic_interface, &wr->e, ddsrt_time_wallclock(), false); local_reader_ary_setinvalid (&wr->rdary); entidx_remove_writer_guid (wr->e.gv->entity_index, wr); diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c index 54bdb22..f5c9da8 100644 --- a/src/core/ddsi/src/q_xevent.c +++ b/src/core/ddsi/src/q_xevent.c @@ -1149,7 +1149,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_ static void handle_xevk_delete_writer (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, UNUSED_ARG (ddsrt_mtime_t tnow)) { - /* don't worry if the writer is already gone by the time we get here. */ + /* don't worry if the writer is already gone by the time we get here, delete_writer_nolinger checks for that. */ struct ddsi_domaingv * const gv = ev->evq->gv; GVTRACE ("handle_xevk_delete_writer: "PGUIDFMT"\n", PGUID (ev->u.delete_writer.guid)); delete_writer_nolinger (gv, &ev->u.delete_writer.guid); From 6413d71599aec646eaa427655a0b48bdfaeb4393 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Fri, 27 Mar 2020 13:51:04 +0100 Subject: [PATCH 6/6] Workaround for false positive from clang-tidy (#452) Signed-off-by: Erik Boasson --- src/tools/ddsperf/netload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/ddsperf/netload.c b/src/tools/ddsperf/netload.c index ae716a5..f186e44 100644 --- a/src/tools/ddsperf/netload.c +++ b/src/tools/ddsperf/netload.c @@ -78,7 +78,7 @@ struct record_netload_state *record_netload_new (const char *dev, double bw) st->bw = bw; st->data_valid = false; st->errored = false; - record_netload (st, NULL, dds_time ()); + record_netload (st, "", dds_time ()); return st; }