From 57ac8a457b8205ef4f704d71ae3493d2a5970b49 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Wed, 23 Oct 2019 17:38:55 +0200
Subject: [PATCH 01/55] Skip irrelevant buckets in hopscotch lookup (#270)
When scanning buckets while looking for a specific element, it is faster
to only inspect those buckets for which the corresponding bit in
"hopinfo" is set. Sadly, simple scanning is faster than the far more
elegant perfect hash based on a De Bruijn sequence.
Add a simple test/performance measurement.
Signed-off-by: Erik Boasson
---
src/ddsrt/src/hopscotch.c | 20 ++--
src/ddsrt/tests/CMakeLists.txt | 1 +
src/ddsrt/tests/hopscotch.c | 209 +++++++++++++++++++++++++++++++++
3 files changed, 222 insertions(+), 8 deletions(-)
create mode 100644 src/ddsrt/tests/hopscotch.c
diff --git a/src/ddsrt/src/hopscotch.c b/src/ddsrt/src/hopscotch.c
index b6869b1..46522bc 100644
--- a/src/ddsrt/src/hopscotch.c
+++ b/src/ddsrt/src/hopscotch.c
@@ -84,10 +84,12 @@ static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t
uint32_t hopinfo = rt->buckets[bucket].hopinfo;
uint32_t idx;
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
- const uint32_t bidx = (bucket + idx) & idxmask;
- void *data = rt->buckets[bidx].data;
- if (data && rt->equals (data, template))
- return data;
+ if (hopinfo & 1) {
+ const uint32_t bidx = (bucket + idx) & idxmask;
+ void *data = rt->buckets[bidx].data;
+ if (data && rt->equals (data, template))
+ return data;
+ }
}
return NULL;
}
@@ -453,10 +455,12 @@ static void *ddsrt_chh_lookup_internal (struct ddsrt_chh_bucket_array const * co
ddsrt_atomic_fence_ldld ();
hopinfo = ddsrt_atomic_ld32 (&bs[bucket].hopinfo);
for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
- const uint32_t bidx = (bucket + idx) & idxmask;
- void *data = ddsrt_atomic_ldvoidp (&bs[bidx].data);
- if (ddsrt_chh_data_valid_p (data) && equals (data, template)) {
- return data;
+ if (hopinfo & 1) {
+ const uint32_t bidx = (bucket + idx) & idxmask;
+ void *data = ddsrt_atomic_ldvoidp (&bs[bidx].data);
+ if (ddsrt_chh_data_valid_p (data) && equals (data, template)) {
+ return data;
+ }
}
}
ddsrt_atomic_fence_ldld ();
diff --git a/src/ddsrt/tests/CMakeLists.txt b/src/ddsrt/tests/CMakeLists.txt
index 780a521..0a40ee3 100644
--- a/src/ddsrt/tests/CMakeLists.txt
+++ b/src/ddsrt/tests/CMakeLists.txt
@@ -23,6 +23,7 @@ list(APPEND sources
"thread_cleanup.c"
"string.c"
"log.c"
+ "hopscotch.c"
"random.c"
"retcode.c"
"strlcpy.c"
diff --git a/src/ddsrt/tests/hopscotch.c b/src/ddsrt/tests/hopscotch.c
new file mode 100644
index 0000000..fdb0f0c
--- /dev/null
+++ b/src/ddsrt/tests/hopscotch.c
@@ -0,0 +1,209 @@
+/*
+* Copyright(c) 2019 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
+#include
+#include
+#include "CUnit/Test.h"
+#include "CUnit/Theory.h"
+
+#include "dds/ddsrt/random.h"
+#include "dds/ddsrt/heap.h"
+#include "dds/ddsrt/time.h"
+#include "dds/ddsrt/hopscotch.h"
+
+#define MAX_NKEYS 10000
+#define MAX_ITERS 1000000
+
+static int nkeys_hist[MAX_NKEYS+1];
+static uint32_t objs[MAX_NKEYS], keys[MAX_NKEYS];
+static uint32_t next_v;
+static ddsrt_prng_t prng;
+
+static uint32_t hash_uint32 (const void *v)
+{
+ const uint64_t m = UINT64_C (10242350189706880077);
+ const uint32_t h = (uint32_t) ((*((uint32_t *) v) * m) >> 32);
+ return h;
+}
+
+static int equals_uint32 (const void *a, const void *b)
+{
+ return *((uint32_t *) a) == *((uint32_t *) b);
+}
+
+static int compare_uint32 (const void *va, const void *vb)
+{
+ const uint32_t *a = va;
+ const uint32_t *b = vb;
+ return (*a == *b) ? 0 : (*a < *b) ? -1 : 1;
+}
+
+static void swap (uint32_t *a, uint32_t *b)
+{
+ uint32_t t = *a;
+ *a = *b;
+ *b = t;
+}
+
+static void init (bool random)
+{
+ uint32_t i;
+ ddsrt_prng_init_simple (&prng, ddsrt_random ());
+ next_v = MAX_NKEYS;
+ for (i = 0; i < MAX_NKEYS; i++)
+ {
+ nkeys_hist[i] = 0;
+ keys[i] = i;
+ }
+ if (random)
+ {
+ /* Generate MAX_NKEYS unique random ints by repeatedly replacing
+ duplicates with other random numbers (this'll take more time the
+ larger MAX_NKEYS is, but for practical values, it is nearly
+ instantaneous) */
+ for (i = 0; i < MAX_NKEYS - 1; i++)
+ objs[i] = ddsrt_prng_random (&prng);
+ do {
+ objs[i] = ddsrt_prng_random (&prng);
+ qsort (objs, MAX_NKEYS, sizeof (*objs), compare_uint32);
+ for (i = 1; i < MAX_NKEYS && objs[i-1] != objs[i]; i++)
+ ;
+ } while (i < MAX_NKEYS);
+ }
+ else
+ {
+ for (i = 0; i < MAX_NKEYS; i++)
+ objs[i] = i;
+ }
+}
+
+struct ops {
+ const char *name;
+ void * (*new) (void);
+ void (*free) (void *h);
+ void * (*lookup) (void *h, const void *v);
+ int (*add) (void *h, const void *v);
+ int (*remove) (void *h, const void *v);
+};
+
+#define WRAP(ret_, f_) static ret_ f_##_w (void *h, const void *v) { return f_ (h, v); }
+WRAP(void *, ddsrt_hh_lookup);
+WRAP(int, ddsrt_hh_add);
+WRAP(int, ddsrt_hh_remove);
+WRAP(void *, ddsrt_chh_lookup);
+WRAP(int, ddsrt_chh_add);
+WRAP(int, ddsrt_chh_remove);
+WRAP(void *, ddsrt_ehh_lookup);
+WRAP(int, ddsrt_ehh_add);
+WRAP(int, ddsrt_ehh_remove);
+#undef WRAP
+
+static void free_buckets (void *bs, void *arg)
+{
+ /* nothing to worry about because this is single threaded */
+ (void) arg;
+ ddsrt_free (bs);
+}
+
+static void *hhnew (void) { return ddsrt_hh_new (1, hash_uint32, equals_uint32); }
+static void hhfree (void *h) { ddsrt_hh_free (h); }
+static void *chhnew (void) { return ddsrt_chh_new (1, hash_uint32, equals_uint32, free_buckets, NULL); }
+static void chhfree (void *h) { ddsrt_chh_free (h); }
+static void *ehhnew (void) { return ddsrt_ehh_new (sizeof (uint32_t), 1, hash_uint32, equals_uint32); }
+static void ehhfree (void *h) { ddsrt_ehh_free (h); }
+
+static const struct ops hhops = {
+ .name = "hh",
+ .new = hhnew,
+ .free = hhfree,
+ .lookup = ddsrt_hh_lookup_w,
+ .add = ddsrt_hh_add_w,
+ .remove = ddsrt_hh_remove_w
+};
+static const struct ops chhops = {
+ .name = "chh",
+ .new = chhnew,
+ .free = chhfree,
+ .lookup = ddsrt_chh_lookup_w,
+ .add = ddsrt_chh_add_w,
+ .remove = ddsrt_chh_remove_w
+};
+static const struct ops ehhops = {
+ .name = "ehh",
+ .new = ehhnew,
+ .free = ehhfree,
+ .lookup = ddsrt_ehh_lookup_w,
+ .add = ddsrt_ehh_add_w,
+ .remove = ddsrt_ehh_remove_w
+};
+
+static void adj_nop (uint32_t *v) { (void) v; }
+static void adj_seq (uint32_t *v) { *v = next_v++; }
+
+typedef void (*adj_fun_t) (uint32_t *v);
+
+CU_TheoryDataPoints (ddsrt_hopscotch, random) = {
+ CU_DataPoints (const struct ops *, &hhops, &chhops, &ehhops, &hhops, &chhops, &ehhops),
+ CU_DataPoints (bool, true, true, true, false, false, false),
+ CU_DataPoints (adj_fun_t, adj_nop, adj_nop, adj_nop, adj_seq, adj_seq, adj_seq),
+ CU_DataPoints (const char *, "nop", "nop", "nop", "seq", "seq", "seq")
+};
+
+CU_Theory ((const struct ops *ops, bool random, adj_fun_t adj, const char *adjname), ddsrt_hopscotch, random)
+{
+ printf ("%s random=%d adj=%s", ops->name, random, adjname);
+ fflush (stdout);
+ init (random);
+ void *h = ops->new ();
+ uint32_t i, nk = 0;
+ uint64_t nn = 0;
+ dds_time_t t0, t1;
+ t0 = ddsrt_time_monotonic ();
+ for (uint32_t iter = 0; iter < MAX_ITERS; iter++)
+ {
+ int r;
+ assert (nk <= MAX_NKEYS);
+ nkeys_hist[nk]++;
+ if (nk == MAX_NKEYS || (nk > 0 && (ddsrt_prng_random (&prng) & 1)))
+ {
+ i = ddsrt_prng_random (&prng) % nk;
+ if (!ops->lookup (h, &objs[keys[i]]))
+ CU_FAIL_FATAL ("key not present\n");
+ r = ops->remove (h, &objs[keys[i]]);
+ if (!r)
+ CU_FAIL_FATAL ("remove failed\n");
+ if (ops->lookup (h, &objs[keys[i]]))
+ CU_FAIL_FATAL ("key still present\n");
+ adj (&objs[keys[i]]);
+ swap (&keys[i], &keys[nk-1]);
+ nk--;
+ }
+ else
+ {
+ i = nk + (ddsrt_prng_random (&prng) % (MAX_NKEYS - nk));
+ if (ops->lookup (h, &objs[keys[i]]))
+ CU_FAIL_FATAL ("key already present\n");
+ r = ops->add (h, &objs[keys[i]]);
+ if (!r)
+ CU_FAIL_FATAL ("add failed\n");
+ if (!ops->lookup (h, &objs[keys[i]]))
+ CU_FAIL_FATAL ("key still not present\n");
+ swap (&keys[i], &keys[nk]);
+ nk++;
+ }
+ nn++;
+ }
+ t1 = ddsrt_time_monotonic ();
+ ops->free (h);
+ printf (" %"PRIu64" %.0f ns/cycle\n", nn, (double) (t1 - t0) / (double) nn);
+}
From 151159a5eaa22af3a7fb2fc44dbcac6a15fb1527 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Wed, 23 Oct 2019 17:44:56 +0200
Subject: [PATCH 02/55] Clear sa_mask in sigaction for DDS_LC_FATAL test
Signed-off-by: Erik Boasson
---
src/ddsrt/tests/log.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/ddsrt/tests/log.c b/src/ddsrt/tests/log.c
index 5a0facd..9f5223b 100644
--- a/src/ddsrt/tests/log.c
+++ b/src/ddsrt/tests/log.c
@@ -462,6 +462,7 @@ CU_Theory((bool local, int mode, bool expect_in_trace), dds_log, fatal_aborts)
#if TEST_DDS_LC_FATAL
struct sigaction action, oldaction;
action.sa_flags = 0;
+ sigemptyset (&action.sa_mask);
action.sa_handler = abort_handler;
if (sigsetjmp (abort_jmpbuf, 0) != 0)
From d545551a60a4fa10d1657b36d5bc255081cf7274 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 4 Nov 2019 11:05:30 +0100
Subject: [PATCH 03/55] Fix input buffer allocation in XML parser (#270)
Signed-off-by: Erik Boasson
---
src/ddsrt/src/xmlparser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c
index cd3580f..c497624 100644
--- a/src/ddsrt/src/xmlparser.c
+++ b/src/ddsrt/src/xmlparser.c
@@ -198,7 +198,7 @@ static int make_chars_available (struct ddsrt_xmlp_state *st, size_t nmin)
}
}
/* buffer is owned by caller if fp = NULL, and by us if fp != NULL */
- if (st->cbufp + st->cbufmax < nmin) {
+ if (st->cbufmax < st->cbufp + nmin) {
st->cbufmax = st->cbufp + nmin;
st->cbuf = ddsrt_realloc (st->cbuf, st->cbufmax);
}
From 5883b96f6aa0cd728aa078d039143484b9fd7bb8 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 4 Nov 2019 11:06:32 +0100
Subject: [PATCH 04/55] Handle unterminated comment in XML parser (#270)
Signed-off-by: Erik Boasson
---
src/ddsrt/src/xmlparser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c
index c497624..828d40e 100644
--- a/src/ddsrt/src/xmlparser.c
+++ b/src/ddsrt/src/xmlparser.c
@@ -500,7 +500,7 @@ static int skip_comment (struct ddsrt_xmlp_state *st)
if (!peek_chars (st, "", 0)) {
+ while (peek_char (st) != TOK_EOF && (peek_char (st) != '-' || !peek_chars (st, "-->", 0))) {
next_char (st);
}
if (peek_chars (st, "-->", 1)) {
From 9e61bff9b9df564338a0d8c57442c372668719c0 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 4 Nov 2019 14:04:53 +0100
Subject: [PATCH 05/55] Use unsigned char for XML input
Sign extension causes some character values to be interpreted as special
tokens, potentially causing the parser to hang, pass a null pointer as
element name to the "elem_open" callback (which would crash the
configuration processing).
Signed-off-by: Erik Boasson
---
src/ddsrt/src/xmlparser.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c
index 828d40e..0096c88 100644
--- a/src/ddsrt/src/xmlparser.c
+++ b/src/ddsrt/src/xmlparser.c
@@ -36,7 +36,7 @@ struct ddsrt_xmlp_state {
size_t cbufmax; /* allocated size of cbuf (cbufn <= cbufmax) */
size_t cbufmark; /* NORMARKER or marker position (cbufmark <= cbufp) for rewinding */
int eof; /* fake EOF (for treating missing close tags as EOF) */
- char *cbuf; /* parser input buffer */
+ unsigned char *cbuf; /* parser input buffer */
FILE *fp; /* file to refill cbuf from, or NULL if parsing a string */
int line; /* current line number */
int prevline; /* line number at last token */
@@ -147,7 +147,7 @@ struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg,
st = ddsrt_malloc (sizeof (*st));
st->cbufn = strlen (string);
st->cbufmax = st->cbufn;
- st->cbuf = (char *) string;
+ st->cbuf = (unsigned char *) string;
st->fp = NULL;
ddsrt_xmlp_new_common (st);
ddsrt_xmlp_new_setCB (st, varg, cb);
@@ -239,7 +239,7 @@ static void rewind_to_input_marker (struct ddsrt_xmlp_state *st)
static int next_char (struct ddsrt_xmlp_state *st)
{
- char c;
+ unsigned char c;
if (!make_chars_available (st, 1)) {
return TOK_EOF;
}
From 389d6b1789c9c6ef781ca6407f88fed37f9741e4 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 31 Oct 2019 14:59:13 +0100
Subject: [PATCH 06/55] Remove repetitive debug print from "mpt_qosmatch"
Signed-off-by: Erik Boasson
---
src/mpt/tests/qos/procs/rw.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/mpt/tests/qos/procs/rw.c b/src/mpt/tests/qos/procs/rw.c
index abe6a64..f663db9 100644
--- a/src/mpt/tests/qos/procs/rw.c
+++ b/src/mpt/tests/qos/procs/rw.c
@@ -302,8 +302,6 @@ MPT_ProcessEntry (rw_publisher,
i, j, dds_strretcode (rc));
if (st.current_count)
{
- printf ("%zu %zu: %d\n", i, j, (int) st.current_count);
- fflush (stdout);
goto have_matches;
}
}
From 3652fe63306a3b073ccbb9631a0b2bfff7be1d38 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 31 Oct 2019 08:08:39 +0100
Subject: [PATCH 07/55] Update to Xcode 11.1 image on Travis CI
Signed-off-by: Erik Boasson
---
.travis.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index e60fe9a..3668783 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -68,9 +68,9 @@ linux_clang: &linux_clang
install:
- pip install conan --upgrade --user
-osx_xcode10_3: &osx_xcode10_3
+osx_xcode: &osx_xcode
os: osx
- osx_image: xcode10.3
+ osx_image: xcode11.1
compiler: clang
addons:
homebrew:
@@ -84,7 +84,7 @@ osx_xcode10_3: &osx_xcode10_3
- python3 -m pip install conan --upgrade --user
osx_xcode9: &osx_xcode9
- <<: *osx_xcode10_3
+ <<: *osx_xcode
osx_image: xcode9
cache:
directories:
@@ -165,9 +165,9 @@ jobs:
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode9
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, GENERATOR="Unix Makefiles" ]
- - <<: *osx_xcode10_3
+ - <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ]
- - <<: *osx_xcode10_3
+ - <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *windows_vs2017
env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Visual Studio 15 2017" ]
From b9e5e8cd7d4c9516450cab1f274a2c516269c1b4 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 5 Nov 2019 14:22:42 +0100
Subject: [PATCH 08/55] Xcode 11.1 for macOS 10.12 build, Xcode 9 via cron
The Xcode 9 builds often fail because of some nasty interaction between
it and the Travis build cache -- but not caching means they always take
forever because of homebrew updates. This commit changes the build to
use a new Xcode but with a deployment target of 10.12 instead.
This means that macOS version macros for versions later than 10.12 are
available and that the tests run on a later version of macOS as well.
Therefore, it doesn't prove that a "real" Xcode 9 / macOS 10.12 build
will work.
ROS2 relies on macOS 10.12 so this introduces a (small) risk of build
failures over there. To mitigate that, a pure Xcode 9 build is included
in the cron job.
Signed-off-by: Erik Boasson
---
.travis.yml | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 3668783..e25c289 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -86,10 +86,6 @@ osx_xcode: &osx_xcode
osx_xcode9: &osx_xcode9
<<: *osx_xcode
osx_image: xcode9
- cache:
- directories:
- - $HOME/Library/Caches/Homebrew
- - /usr/local/Homebrew
addons:
homebrew:
packages: [ python3 ]
@@ -99,11 +95,6 @@ osx_xcode9: &osx_xcode9
# used to ensure Homebrew is kept up-to-date and build times are kept to
# a minimum.
update: true
- before_cache:
- - brew cleanup
- - find /usr/local/Homebrew -type d -name .git |
- xargs -I {} dirname {} |
- xargs -I {} git --git-dir={}/.git --work-tree={} clean -f -d -x
windows_vs2017: &windows_vs2017
os: windows
@@ -165,6 +156,9 @@ jobs:
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode9
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, GENERATOR="Unix Makefiles" ]
+ if: type = cron
+ - <<: *osx_xcode
+ env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ]
- <<: *osx_xcode
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode
From a1aaa2808f726f538f0b2d752766ada4b062d2e6 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Wed, 6 Nov 2019 11:23:49 +0100
Subject: [PATCH 09/55] Check once for system-independent headers (#270)
Signed-off-by: Erik Boasson
---
src/ddsrt/CMakeLists.txt | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt
index 19b99df..b750b0c 100644
--- a/src/ddsrt/CMakeLists.txt
+++ b/src/ddsrt/CMakeLists.txt
@@ -183,6 +183,19 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
endif()
set(system_exists FALSE)
+ # Headers that must remain private but are required by other runtime
+ # source files must be located in src//dds/ddsrt.
+ if(IS_DIRECTORY "${source_path}/${feature}/include")
+ file(GLOB_RECURSE
+ files
+ CONFIGURE_DEPENDS
+ "${source_path}/${feature}/include/*.h")
+ list(APPEND headers ${files})
+ target_include_directories(
+ ddsrt INTERFACE
+ "$")
+ endif()
+
# Allow custom implementations for a feature. e.g. lwip as opposed to
# windows or posix.
set(_system_name "${system_name}")
@@ -191,18 +204,6 @@ foreach(feature atomics cdtors environ heap ifaddrs random rusage
endif()
foreach(system ${_system_name} posix)
- # Headers that must remain private but are required by other runtime
- # source files must be located in src//dds/ddsrt.
- if(IS_DIRECTORY "${source_path}/${feature}/include")
- file(GLOB_RECURSE
- files
- CONFIGURE_DEPENDS
- "${source_path}/${feature}/include/*.h")
- list(APPEND headers ${files})
- target_include_directories(
- ddsrt INTERFACE
- "$")
- endif()
if(IS_DIRECTORY "${source_path}/${feature}/${system}")
file(GLOB_RECURSE
files
From ae1a8130c705d945a6c158b4e4063e98c41442eb Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Fri, 18 Oct 2019 22:04:07 -0500
Subject: [PATCH 10/55] Namespace the schema and add references in xml files
Signed-off-by: Dan Rose
---
etc/cyclonedds.xsd | 6 +++++-
src/core/ddsc/tests/config_simple_udp.xml | 4 +++-
src/mpt/tests/basic/etc/config_any.xml | 5 ++++-
src/mpt/tests/basic/etc/config_specific.xml | 5 ++++-
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd
index 7e2beed..da6da80 100644
--- a/etc/cyclonedds.xsd
+++ b/etc/cyclonedds.xsd
@@ -1,5 +1,9 @@
-
+
+
diff --git a/src/core/ddsc/tests/config_simple_udp.xml b/src/core/ddsc/tests/config_simple_udp.xml
index c333d64..426fd10 100644
--- a/src/core/ddsc/tests/config_simple_udp.xml
+++ b/src/core/ddsc/tests/config_simple_udp.xml
@@ -1,4 +1,6 @@
+
-
+
diff --git a/src/mpt/tests/basic/etc/config_any.xml b/src/mpt/tests/basic/etc/config_any.xml
index 275eb4b..a00f45c 100644
--- a/src/mpt/tests/basic/etc/config_any.xml
+++ b/src/mpt/tests/basic/etc/config_any.xml
@@ -1,3 +1,6 @@
+
+
-
+
any
diff --git a/src/mpt/tests/basic/etc/config_specific.xml b/src/mpt/tests/basic/etc/config_specific.xml
index 0532aa0..2dbd678 100644
--- a/src/mpt/tests/basic/etc/config_specific.xml
+++ b/src/mpt/tests/basic/etc/config_specific.xml
@@ -1,3 +1,6 @@
+
+
-
+
${DOMAIN_ID}
From 4f2addef1a39c2a19b6147fcb59e073bea5ea9ae Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Thu, 31 Oct 2019 18:30:16 -0500
Subject: [PATCH 11/55] Allow xmlns attribute on the root element
Signed-off-by: Dan Rose
---
src/core/ddsi/src/q_config.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 2aec54c..7664e8d 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -830,6 +830,7 @@ static const struct cfgelem root_cfgelems[] = {
};
static const struct cfgelem root_cfgattrs[] = {
+ { ATTR("xmlns"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xmlns:xsi"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xsi:noNamespaceSchemaLocation"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
END_MARKER
From c5b22bf62956aed97e760bc07dc2897538f86bc6 Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Thu, 31 Oct 2019 18:52:08 -0500
Subject: [PATCH 12/55] Fix most of the validation problems
Signed-off-by: Dan Rose
---
src/core/ddsc/tests/config_simple_udp.xml | 4 ++--
src/mpt/tests/basic/etc/config_any.xml | 5 ++---
src/mpt/tests/basic/etc/config_specific.xml | 5 ++---
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/core/ddsc/tests/config_simple_udp.xml b/src/core/ddsc/tests/config_simple_udp.xml
index 426fd10..9367f80 100644
--- a/src/core/ddsc/tests/config_simple_udp.xml
+++ b/src/core/ddsc/tests/config_simple_udp.xml
@@ -30,8 +30,8 @@
${MAX_PARTICIPANTS}
- 100 ms
-
+ 100 ms
+ 10s
diff --git a/src/mpt/tests/basic/etc/config_any.xml b/src/mpt/tests/basic/etc/config_any.xml
index a00f45c..b9fa04c 100644
--- a/src/mpt/tests/basic/etc/config_any.xml
+++ b/src/mpt/tests/basic/etc/config_any.xml
@@ -13,9 +13,7 @@
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->
-
- any
-
+
true
true
@@ -27,4 +25,5 @@
finest
ddsi_${MPT_PROCESS_NAME}.log
+
diff --git a/src/mpt/tests/basic/etc/config_specific.xml b/src/mpt/tests/basic/etc/config_specific.xml
index 2dbd678..ea26cf1 100644
--- a/src/mpt/tests/basic/etc/config_specific.xml
+++ b/src/mpt/tests/basic/etc/config_specific.xml
@@ -13,9 +13,7 @@
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->
-
- ${DOMAIN_ID}
-
+
true
true
@@ -27,4 +25,5 @@
finest
ddsi_${MPT_PROCESS_NAME}.log
+
From c642f5676a4571a655428cdefdfb85c8b3d5617e Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 1 Nov 2019 14:48:37 +0100
Subject: [PATCH 13/55] Namespace generated XSD and add missing attributes
This adds two things to the XSD (and the RNC file and options.md):
* attributes previously missing because of a bug in the conversion
script
* a name space (https://cdds.io/config)
Adding the name spacing requires a different set of attributes at the
top of a configuration file, which in turn need to be ignored by the
configuration parser, and which should be reflected in the configuration
example in the README.
Signed-off-by: Erik Boasson
---
README.md | 2 +-
docs/makernc.pl | 35 +--
docs/manual/options.md | 90 ++++++++
etc/cyclonedds.rnc | 75 ++++++-
etc/cyclonedds.xsd | 419 +++++++++++++++++++++--------------
src/core/ddsi/src/q_config.c | 1 +
6 files changed, 439 insertions(+), 183 deletions(-)
diff --git a/README.md b/README.md
index c4352a4..8a549c5 100644
--- a/README.md
+++ b/README.md
@@ -186,7 +186,7 @@ point to it. E.g. (on Linux):
$ cat cyclonedds.xml
-
+
diff --git a/docs/makernc.pl b/docs/makernc.pl
index bf09371..42033d1 100644
--- a/docs/makernc.pl
+++ b/docs/makernc.pl
@@ -156,7 +156,8 @@ my %tables;
my @root = read_config ($input);
{
- open my $fh, ">", "$output_rnc" or die "can't open $output_rnc";
+ open my $fh, ">:unix", "$output_rnc" or die "can't open $output_rnc";
+ print $fh "default namespace = \"https://cdds.io/config\"\n";
print $fh "namespace a = \"http://relaxng.org/ns/compatibility/annotations/1.0\"\n";
print $fh "grammar {\n";
print $fh " start =\n";
@@ -170,7 +171,7 @@ my @root = read_config ($input);
}
{
- open my $fh, ">", "$output_md" or die "can't open $output_md";
+ open my $fh, ">:unix", "$output_md" or die "can't open $output_md";
my $sep_blurb = "";
conv_table($fh, \&conv_to_md, \@root, "/", " ", "", \$sep_blurb);
close $fh;
@@ -315,12 +316,14 @@ sub conv_to_rnc {
print_description_rnc ($fh, $fs->{description}, $indent);
printf $fh "${indent}%s %s {\n", ($fs->{kind} eq "ATTR" ? "attribute" : "element"), $name;
+ my $sub_isfirst = 1;
+ conv_table($fh, \&conv_to_rnc, $fs->{subtables}, $fqname, "${indent} ", $prefix, \$sub_isfirst);
+ my $sep = $sub_isfirst ? "" : "& ";
+
if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
- my $sub_isfirst = 1;
- conv_table($fh, \&conv_to_rnc, $fs->{subtables}, $fqname, "${indent} ", $prefix, \$sub_isfirst);
- printf $fh "${indent} empty\n" if $sub_isfirst;
+ printf $fh "${indent} ${sep}empty\n" if $sub_isfirst;
} elsif ($fs->{kstr} eq "Boolean") {
- printf $fh "${indent} xsd:boolean\n";
+ printf $fh "${indent} ${sep}xsd:boolean\n";
} elsif ($fs->{kstr} eq "Comma") {
die unless exists $comma_values{$fs->{typehint}};
my $pat = "";
@@ -337,13 +340,13 @@ sub conv_to_rnc {
}
}
$pat .= "|" if $allowempty;
- printf $fh "${indent} xsd:token { pattern = \"%s\" }\n", $pat;
+ printf $fh "${indent} ${sep}xsd:token { pattern = \"%s\" }\n", $pat;
} elsif ($fs->{kstr} eq "Enum") {
die unless exists $enum_values{$fs->{typehint}};
my @vs = split /;/, $enum_values{$fs->{typehint}};
- printf $fh "${indent} %s\n", (join '|', map { "\"$_\"" } @vs);
+ printf $fh "${indent} ${sep}%s\n", (join '|', map { "\"$_\"" } @vs);
} elsif ($fs->{kstr} eq "Int") {
- printf $fh "${indent} xsd:integer\n";
+ printf $fh "${indent} ${sep}xsd:integer\n";
#if (exists $range{$lctn} || exists $range{$fs->{typehint}}) {
# # integer with range
# my $rr = exists $range{$lctn} ? $range{$lctn} : $range{$fs->{typehint}};
@@ -351,9 +354,9 @@ sub conv_to_rnc {
#}
} elsif ($typehint2unit{$fs->{typehint}}) {
# number with unit
- printf $fh "${indent} $typehint2unit{$fs->{typehint}}\n";
+ printf $fh "${indent} ${sep}$typehint2unit{$fs->{typehint}}\n";
} elsif ($typehint2xmltype{$fs->{typehint}} =~ /String$/) {
- printf $fh "${indent} text\n";
+ printf $fh "${indent} ${sep}text\n";
} else {
die;
}
@@ -393,7 +396,7 @@ sub conv_to_md {
# Describe type (boolean, integer, &c.); for a group list its attributes and children as
# links to their descriptions
- if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
+ {
my %children = ("attributes" => [], "elements" => []);
conv_table($fh, \&list_children_md, $fs->{subtables}, "", "${indent} ", $prefix, \%children);
if (@{$children{attributes}} > 0) {
@@ -406,6 +409,10 @@ sub conv_to_md {
my @ys = map { my $lt = lc "$fqname\[\@$_]"; $lt =~ s/[^a-z0-9]//g; "[$_](#$lt)" } @xs;
printf $fh "Children: %s\n\n", (join ', ', @ys);
}
+ }
+
+ if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
+ # nothing to see here
} elsif ($fs->{kstr} eq "Boolean") {
printf $fh "Boolean\n";
} elsif ($fs->{kstr} eq "Comma") {
@@ -451,9 +458,7 @@ sub conv_to_md {
print_description_md ($fh, $fs->{description}, $indent);
# Generate attributes & children
- if ($fs->{kind} eq "GROUP" || $fs->{kind} eq "MGROUP") {
- conv_table($fh, \&conv_to_md, $fs->{subtables}, $fqname, "${indent} ", $prefix, $separator_blurb_ref);
- }
+ conv_table($fh, \&conv_to_md, $fs->{subtables}, $fqname, "${indent} ", $prefix, $separator_blurb_ref);
}
sub conv_table {
diff --git a/docs/manual/options.md b/docs/manual/options.md
index 7f375ef..25caaf6 100644
--- a/docs/manual/options.md
+++ b/docs/manual/options.md
@@ -672,6 +672,8 @@ The default value is: "false".
#### //CycloneDDS/Domain/Internal/HeartbeatInterval
+Attributes: [max](#cycloneddsdomaininternalheartbeatintervalmax), [min](#cycloneddsdomaininternalheartbeatintervalmin), [minsched](#cycloneddsdomaininternalheartbeatintervalminsched)
+
Number-with-unit
This elemnents allows configuring the base interval for sending writer
@@ -683,6 +685,42 @@ Valid values are finite durations with an explicit unit or the keyword
The default value is: "100 ms".
+#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@max]
+Number-with-unit
+
+This attribute sets the maximum interval for periodic heartbeats.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
+
+The default value is: "8 s".
+
+
+#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@min]
+Number-with-unit
+
+This attribute sets the minimum interval that must have passed since the
+most recent heartbeat from a writer, before another asynchronous (not
+directly related to writing) will be sent.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
+
+The default value is: "5 ms".
+
+
+#### //CycloneDDS/Domain/Internal/HeartbeatInterval[@minsched]
+Number-with-unit
+
+This attribute sets the minimum interval for periodic heartbeats. Other
+events may still cause heartbeats to go out.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day.
+
+The default value is: "20 ms".
+
+
#### //CycloneDDS/Domain/Internal/LateAckMode
Boolean
@@ -704,6 +742,8 @@ The default value is: "10 s".
#### //CycloneDDS/Domain/Internal/LivelinessMonitoring
+Attributes: [Interval](#cycloneddsdomaininternallivelinessmonitoringinterval), [StackTraces](#cycloneddsdomaininternallivelinessmonitoringstacktraces)
+
Boolean
This element controls whether or not implementation should internally
@@ -714,6 +754,28 @@ stopped making progress.
The default value is: "false".
+#### //CycloneDDS/Domain/Internal/LivelinessMonitoring[@Interval]
+Number-with-unit
+
+This element controls the interval at which to check whether threads have
+been making progress.
+
+The unit must be specified explicitly. Recognised units: ns, us, ms, s,
+min, hr, day.
+
+The default value is: "1s".
+
+
+#### //CycloneDDS/Domain/Internal/LivelinessMonitoring[@StackTraces]
+Boolean
+
+This element controls whether or not to write stack traces to the Cyclone
+DDS trace when a thread fails to make progress (on select platforms
+only).
+
+The default value is: "true".
+
+
#### //CycloneDDS/Domain/Internal/MaxParticipants
Integer
@@ -819,6 +881,8 @@ The default value is: "-1".
#### //CycloneDDS/Domain/Internal/MultipleReceiveThreads
+Attributes: [maxretries](#cycloneddsdomaininternalmultiplereceivethreadsmaxretries)
+
Boolean
This element controls whether all traffic is handled by a single receive
@@ -830,6 +894,18 @@ single (the default).
The default value is: "true".
+#### //CycloneDDS/Domain/Internal/MultipleReceiveThreads[@maxretries]
+Integer
+
+Receive threads dedicated to a single socket can only be triggered for
+termination by sending a packet. Reception of any packet will do, so
+termination failure due to packet loss is exceedingly unlikely, but to
+eliminate all risks, it will retry as many times as specified by this
+attribute before aborting.
+
+The default value is: "4294967295".
+
+
#### //CycloneDDS/Domain/Internal/NackDelay
Number-with-unit
@@ -880,6 +956,8 @@ The default value is: "true".
#### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration
+Attributes: [enforce](#cycloneddsdomaininternalrediscoveryblacklistdurationenforce)
+
Number-with-unit
This element controls for how long a remote participant that was
@@ -898,6 +976,18 @@ Valid values are finite durations with an explicit unit or the keyword
The default value is: "10s".
+#### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration[@enforce]
+Boolean
+
+This attribute controls whether the configured time during which recently
+deleted participants will not be rediscovered (i.e., "black listed") is
+enforced and following complete removal of the participant in Cyclone
+DDS, or whether it can be rediscovered earlier provided all traces of
+that participant have been removed already.
+
+The default value is: "false".
+
+
#### //CycloneDDS/Domain/Internal/RetransmitMerging
One of: never, adaptive, always
diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc
index de54eef..12444a9 100644
--- a/etc/cyclonedds.rnc
+++ b/etc/cyclonedds.rnc
@@ -1,3 +1,4 @@
+default namespace = "https://cdds.io/config"
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
grammar {
start =
@@ -558,7 +559,37 @@ heartbeats and the bounds within it can vary.
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.The default value is: "100 ms".
""" ] ]
element HeartbeatInterval {
- duration_inf
+ [ a:documentation [ xml:lang="en" """
+This attribute sets the maximum interval for periodic heartbeats.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.
The default value is: "8 s".
""" ] ]
+ attribute max {
+ duration_inf
+ }?
+ & [ a:documentation [ xml:lang="en" """
+This attribute sets the minimum interval that must have passed since
+the most recent heartbeat from a writer, before another asynchronous (not
+directly related to writing) will be sent.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.
The default value is: "5 ms".
""" ] ]
+ attribute min {
+ duration_inf
+ }?
+ & [ a:documentation [ xml:lang="en" """
+This attribute sets the minimum interval for periodic heartbeats.
+Other events may still cause heartbeats to go out.
+
+Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.
The default value is: "20 ms".
""" ] ]
+ attribute minsched {
+ duration_inf
+ }?
+ & duration_inf
}?
& [ a:documentation [ xml:lang="en" """
Ack a sample only when it has been delivered, instead of when
@@ -582,7 +613,23 @@ traces can be dumped automatically when some thread appears to have
stopped making progress.
The default value is:
"false".
""" ] ]
element LivelinessMonitoring {
- xsd:boolean
+ [ a:documentation [ xml:lang="en" """
+This element controls the interval at which to check whether threads
+have been making progress.
+
+The unit must be specified explicitly. Recognised units: ns, us, ms,
+s, min, hr, day.
The default value is: "1s".
""" ] ]
+ attribute Interval {
+ duration
+ }?
+ & [ a:documentation [ xml:lang="en" """
+This element controls whether or not to write stack traces to the
+Cyclone DDS trace when a thread fails to make progress (on select
+platforms only).
The default value is: "true".
""" ] ]
+ attribute StackTraces {
+ xsd:boolean
+ }?
+ & xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
This elements configures the maximum number of DCPS domain
@@ -678,7 +725,17 @@ latency. Currently multiple receive threads are only used for
connectionless transport (e.g., UDP) and ManySocketsMode not set to
single (the default).
The default value is: "true".
""" ] ]
element MultipleReceiveThreads {
- xsd:boolean
+ [ a:documentation [ xml:lang="en" """
+Receive threads dedicated to a single socket can only be triggered for
+termination by sending a packet. Reception of any packet will do, so
+termination failure due to packet loss is exceedingly unlikely, but to
+eliminate all risks, it will retry as many times as specified by this
+attribute before aborting.
The default value is:
+"4294967295".
""" ] ]
+ attribute maxretries {
+ xsd:integer
+ }?
+ & xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
This setting controls the delay between receipt of a HEARTBEAT
@@ -734,7 +791,17 @@ is therefore recommended to set it to at least several seconds.
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.The default value is: "10s".
""" ] ]
element RediscoveryBlacklistDuration {
- duration_inf
+ [ a:documentation [ xml:lang="en" """
+This attribute controls whether the configured time during which
+recently deleted participants will not be rediscovered (i.e., "black
+listed") is enforced and following complete removal of the participant in
+Cyclone DDS, or whether it can be rediscovered earlier provided all
+traces of that participant have been removed already.
The default
+value is: "false".
""" ] ]
+ attribute enforce {
+ xsd:boolean
+ }?
+ & duration_inf
}?
& [ a:documentation [ xml:lang="en" """
This elements controls the addressing and timing of retransmits.
diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd
index da6da80..4e31f2f 100644
--- a/etc/cyclonedds.xsd
+++ b/etc/cyclonedds.xsd
@@ -1,9 +1,5 @@
-
-
+
@@ -11,7 +7,7 @@ CycloneDDS configuration
-
+
@@ -22,15 +18,15 @@ CycloneDDS configuration
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -38,11 +34,11 @@ CycloneDDS configuration
-
+
-
+
@@ -61,10 +57,10 @@ to compatability with standards and with other DDSI implementations.</p>
-
-
-
-
+
+
+
+
@@ -158,19 +154,19 @@ the discovery of peers.</p>
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
<p>This setting controls for how long endpoints discovered via a Cloud
@@ -242,8 +238,8 @@ second be option be used.</p><p>The default value is:
-
-
+
+
@@ -256,7 +252,7 @@ succeeds.</p>
-
+
@@ -288,13 +284,13 @@ by the DDSI 2.1 specification and rarely need to be changed.</p>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -355,7 +351,7 @@ to the DDSI 2.1 specification, section 9.6.1, constant d1).</p><p>Th
default value is: "10".</p>
-
+
<p>This element specifies the interval between spontaneous transmissions
@@ -383,19 +379,19 @@ settings.</p>
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -481,7 +477,7 @@ address. This option is IPv4-only.</p><p>The default value is:
"0.0.0.0".</p>
-
+
<p>This element specifies the size of DDSI sample fragments generated by
@@ -497,7 +493,7 @@ of which the size is at least the minimum of 1025 and FragmentSize.</p>
B".</p>
-
+
<p>This element specifies the maximum size of the UDP payload that
@@ -620,51 +616,51 @@ reserved. This includes renaming or moving options.</p>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -688,7 +684,7 @@ wildcards) against which the interface names are matched.</p><p>The
default value is: "".</p>
-
+
<p>This setting controls the interval with which a reader will continue
@@ -798,7 +794,7 @@ checks.</p><p>The default value is: "".</p><
keys.</p><p>The default value is: "false".</p>
-
+
<p>This elemnents allows configuring the base interval for sending writer
@@ -808,6 +804,45 @@ heartbeats and the bounds within it can vary.</p>
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: "100 ms".</p>
+
+
+
+
+
+
+<p>This attribute sets the maximum interval for periodic heartbeats.</p>
+
+<p>Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.</p><p>The default value is: "8 s".</p>
+
+
+
+
+
+<p>This attribute sets the minimum interval that must have passed since
+the most recent heartbeat from a writer, before another asynchronous (not
+directly related to writing) will be sent.</p>
+
+<p>Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.</p><p>The default value is: "5 ms".</p>
+
+
+
+
+
+<p>This attribute sets the minimum interval for periodic heartbeats.
+Other events may still cause heartbeats to go out.</p>
+
+<p>Valid values are finite durations with an explicit unit or the keyword
+'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
+day.</p><p>The default value is: "20 ms".</p>
+
+
+
+
+
@@ -817,7 +852,7 @@ committed to delivering it.</p><p>The default value is:
"false".</p>
-
+
<p>This setting controls the default participant lease duration. <p>
@@ -826,7 +861,7 @@ committed to delivering it.</p><p>The default value is:
s, min, hr, day.</p><p>The default value is: "10 s".</p>
-
+
<p>This element controls whether or not implementation should internally
@@ -835,6 +870,30 @@ traces can be dumped automatically when some thread appears to have
stopped making progress.</p><p>The default value is:
"false".</p>
+
+
+
+
+
+
+<p>This element controls the interval at which to check whether threads
+have been making progress.</p>
+
+<p>The unit must be specified explicitly. Recognised units: ns, us, ms,
+s, min, hr, day.</p><p>The default value is: "1s".</p>
+
+
+
+
+
+<p>This element controls whether or not to write stack traces to the
+Cyclone DDS trace when a thread fails to make progress (on select
+platforms only).</p><p>The default value is: "true".</p>
+
+
+
+
+
@@ -844,7 +903,7 @@ participants this Cyclone DDS instance is willing to service. 0 is
unlimited.</p><p>The default value is: "0".</p>
-
+
<p>This setting limits the maximum number of bytes queued for
@@ -866,7 +925,7 @@ kB".</p>
retransmission.</p><p>The default value is: "200".</p>
-
+
<p>This setting controls the maximum (CDR) serialised size of samples
@@ -889,7 +948,7 @@ measured latencies are quite noisy and are currently not used
anywhere.</p><p>The default value is: "false".</p>
-
+
<p>This setting controls the minimum size of socket receive buffers. The
@@ -908,7 +967,7 @@ a smaller buffer should that attempt fail.</p>
"default".</p>
-
+
<p>This setting controls the minimum size of socket send buffers. This
@@ -931,7 +990,7 @@ positive number is used as the TCP port number.</p><p>The default va
is: "-1".</p>
-
+
<p>This element controls whether all traffic is handled by a single
@@ -940,8 +999,25 @@ latency. Currently multiple receive threads are only used for
connectionless transport (e.g., UDP) and ManySocketsMode not set to
single (the default).</p><p>The default value is: "true".</p>
+
+
+
+
+
+
+<p>Receive threads dedicated to a single socket can only be triggered for
+termination by sending a packet. Reception of any packet will do, so
+termination failure due to packet loss is exceedingly unlikely, but to
+eliminate all risks, it will retry as many times as specified by this
+attribute before aborting.</p><p>The default value is:
+"4294967295".</p>
+
+
+
+
+
-
+
<p>This setting controls the delay between receipt of a HEARTBEAT
@@ -954,7 +1030,7 @@ that NACK will incorporate the latest information.</p>
s, min, hr, day.</p><p>The default value is: "10 ms".</p>
-
+
<p>This setting controls the delay between the discovering a remote
@@ -984,7 +1060,7 @@ data, speeding up recovery.</p><p>The default value is:
"true".</p>
-
+
<p>This element controls for how long a remote participant that was
@@ -1001,6 +1077,23 @@ is therefore recommended to set it to at least several seconds.</p>
'inf' for infinity. Recognised units: ns, us, ms, s, min, hr,
day.</p><p>The default value is: "10s".</p>
+
+
+
+
+
+
+<p>This attribute controls whether the configured time during which
+recently deleted participants will not be rediscovered (i.e., "black
+listed") is enforced and following complete removal of the participant in
+Cyclone DDS, or whether it can be rediscovered earlier provided all
+traces of that participant have been removed already.</p><p>The default
+value is: "false".</p>
+
+
+
+
+
@@ -1029,7 +1122,7 @@ Internal/RetransmitMergingPeriod.</p><p>The default value is:
-
+
<p>This setting determines the size of the time window in which a NACK of
@@ -1051,7 +1144,7 @@ into the reader caches when resource limits are reached.</p><p>The
default value is: "false".</p>
-
+
<p>Maximum pseudo-random delay in milliseconds between discovering a
@@ -1061,7 +1154,7 @@ remote participant and responding to it.</p>
s, min, hr, day.</p><p>The default value is: "0 ms".</p>
-
+
<p>This setting allows the timing of scheduled events to be rounded up so
@@ -1103,7 +1196,7 @@ by setting Internal/BuiltinEndpointSet to "minimal" but with less loss of
information).</p><p>The default value is: "false".</p>
-
+
<p>This element controls whether samples sent by a writer with QoS
@@ -1137,7 +1230,7 @@ the expense of aggregate bandwidth.</p><p>The default value is:
-
+
@@ -1171,10 +1264,10 @@ to <i>false</i>.</p><p>The default value is: "t
-
-
-
-
+
+
+
+
@@ -1186,7 +1279,7 @@ mark to current traffic conditions, based on retransmit requests and
transmit pressure.</p><p>The default value is: "true".</p>
-
+
<p>This element sets the maximum allowed high-water mark for the Cyclone
@@ -1199,7 +1292,7 @@ this size.</p>
kB".</p>
-
+
<p>This element sets the initial level of the high-water mark for the
@@ -1211,7 +1304,7 @@ Cyclone DDS WHCs, expressed in bytes.</p>
kB".</p>
-
+
<p>This element sets the low-water mark for the Cyclone DDS WHCs,
@@ -1237,7 +1330,7 @@ dds_write_flush function to ensure thta all samples are
written.</p><p>The default value is: "false".</p>
-
+
<p>This setting controls the maximum duration for which actual deletion
@@ -1257,9 +1350,9 @@ partitions.</p>
-
-
-
+
+
+
@@ -1271,7 +1364,7 @@ combinations that are not distributed over the network.</p>
-
+
@@ -1306,7 +1399,7 @@ partitions.</p>
-
+
@@ -1351,7 +1444,7 @@ partition/topic combinations to Cyclone DDS network partitions.</p>
-
+
@@ -1394,8 +1487,8 @@ SSL/TLS for DDSI over TCP.</p>
-
-
+
+
@@ -1403,12 +1496,12 @@ SSL/TLS for DDSI over TCP.</p>
"false".</p>
-
-
-
-
-
-
+
+
+
+
+
+
@@ -1477,12 +1570,12 @@ dealing with expected system sizes, buffer sizes, &c.</p>
-
-
+
+
-
+
<p>This element specifies the size of one allocation unit in the receive
@@ -1496,7 +1589,7 @@ after processing a message, or freed straightaway.</p>
KiB".</p>
-
+
<p>This element sets the size of a single receive buffer. Many receive
@@ -1518,7 +1611,7 @@ running DDSI over TCP.</p>
-
+
@@ -1534,10 +1627,10 @@ General/Transport instead.</p><p>The default value is:
-
-
-
-
+
+
+
+
@@ -1571,7 +1664,7 @@ by establishing connections to other services.</p><p>The default val
is: "-1".</p>
-
+
<p>This element specifies the timeout for blocking TCP read operations.
@@ -1581,7 +1674,7 @@ If this timeout expires then the connection is closed.</p>
s, min, hr, day.</p><p>The default value is: "2 s".</p>
-
+
<p>This element specifies the timeout for blocking TCP write operations.
@@ -1607,7 +1700,7 @@ using a thread pool to send DDSI messages to multiple unicast addresses
is: "false".</p>
-
+
@@ -1632,8 +1725,8 @@ pool.</p><p>The default value is: "8".</p>
-
-
+
+
@@ -1671,8 +1764,8 @@ discovery;</li>
-
-
+
+
@@ -1704,7 +1797,7 @@ assign some of the privileged priorities.</p><p>The default value is
"default".</p>
-
+
<p>This element configures the stack size for this thread. The default
@@ -1726,11 +1819,11 @@ track the DDSI service during application development.</p>
-
-
-
-
-
+
+
+
+
+
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 7664e8d..75ca4fe 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -832,6 +832,7 @@ static const struct cfgelem root_cfgelems[] = {
static const struct cfgelem root_cfgattrs[] = {
{ ATTR("xmlns"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xmlns:xsi"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
+ { ATTR("xsi:schemaLocation"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
{ ATTR("xsi:noNamespaceSchemaLocation"), 0, "", 0, 0, 0, uf_nop, 0, pf_nop, NULL },
END_MARKER
};
From ff79941aeb2fdeee9f833aedc6adebb8a6e3ef72 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 1 Nov 2019 14:54:27 +0100
Subject: [PATCH 14/55] If possible, fail build on option doc mismatch
This adds a bunch of steps to the build process that verify
cyclonedds.xsd, cyclonedds.rnc and options.md as committed match the
configuration tables in the source.
The cyclonedds.rnc and options.md depend on having perl available,
cyclonedds.xsd on having Java and the "trang" conversion tool. Not
having these tools simply means some of the checks are skipped.
Signed-off-by: Erik Boasson
makernc: more forgiving of line endings input
Signed-off-by: Erik Boasson
Ignore line endings comparing cyclonedds XSD, RNC
Signed-off-by: Erik Boasson
---
docs/CMakeLists.txt | 40 +++++++++++++++++++++++++++++++++++++++-
docs/compare.pl | 8 ++++++++
docs/makernc.pl | 2 +-
3 files changed, 48 insertions(+), 2 deletions(-)
create mode 100644 docs/compare.pl
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index fa1b946..0cf8b26 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -8,5 +8,43 @@
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-add_subdirectory(manual)
+include(FindPerl)
+if(PERL_FOUND)
+ add_custom_command(
+ OUTPUT
+ options.md cyclonedds.rnc
+ COMMAND
+ ${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/makernc.pl" "${CMAKE_CURRENT_SOURCE_DIR}/../src/core/ddsi/src/q_config.c" options.md cyclonedds.rnc
+ COMMAND
+ ${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" options.md "${CMAKE_CURRENT_SOURCE_DIR}/manual/options.md"
+ COMMAND
+ ${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" cyclonedds.rnc "${CMAKE_CURRENT_SOURCE_DIR}/../etc/cyclonedds.rnc"
+ DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/makernc.pl"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../src/core/ddsi/src/q_config.c")
+ add_custom_target(options_doc ALL DEPENDS "options.md" "cyclonedds.rnc")
+ find_package(Java COMPONENTS Runtime)
+ if(JAVA_FOUND AND EXISTS "${TRANG_PATH}" OR EXISTS "$ENV{TRANG}")
+ if(NOT EXISTS "${TRANG_PATH}" AND EXISTS "$ENV{TRANG}")
+ message(STATUS "Setting TRANG_PATH to $ENV{TRANG}")
+ set(TRANG_PATH "$ENV{TRANG}" CACHE FILEPATH "Location of 'trang' for converting XML schemas" FORCE)
+ endif()
+ add_custom_command(
+ OUTPUT
+ cyclonedds.xsd
+ COMMAND
+ ${Java_JAVA_EXECUTABLE} -jar "${TRANG_PATH}" -I rnc -O xsd cyclonedds.rnc cyclonedds.xsd
+ COMMAND
+ ${PERL_EXECUTABLE} -w "${CMAKE_CURRENT_SOURCE_DIR}/compare.pl" cyclonedds.xsd "${CMAKE_CURRENT_SOURCE_DIR}/../etc/cyclonedds.xsd"
+ DEPENDS
+ "cyclonedds.rnc")
+ add_custom_target(options_xsd ALL DEPENDS "cyclonedds.xsd")
+ else()
+ message(STATUS "Java or not trang not found: not converting/checking RNC to XSD")
+ endif()
+else()
+ message(STATUS "perl not found: not generating/checking options documentation and RNC")
+endif()
+
+add_subdirectory(manual)
diff --git a/docs/compare.pl b/docs/compare.pl
new file mode 100644
index 0000000..a8451a1
--- /dev/null
+++ b/docs/compare.pl
@@ -0,0 +1,8 @@
+open A, "< $ARGV[0]" or die "can't open $ARGV[0]";
+open B, "< $ARGV[1]" or die "can't open $ARGV[1]";
+while (defined ($a = ) && defined ($b = )) {
+ $a =~ s/[\r\n]+$//s;
+ $b =~ s/[\r\n]+$//s;
+ exit 1 unless $a eq $b;
+}
+exit 0;
diff --git a/docs/makernc.pl b/docs/makernc.pl
index 42033d1..07a67db 100644
--- a/docs/makernc.pl
+++ b/docs/makernc.pl
@@ -495,7 +495,7 @@ sub read_config {
my @stk = (); # stack of conditional nesting, for each: copy/discard/ignore
open FH, "<", $input or die "can't open $input\n";
while () {
- chomp;
+ s/[\r\n]+$//s;
# ignore parts guarded by #if/#ifdef/#if!/#ifndef if $incl says so
if (/^\s*\#\s*if(n?def|\s*!)?\s*([A-Za-z_][A-Za-z_0-9]*)\s*(?:\/(?:\/.*|\*.*?\*\/)\s*)?$/) {
From 94524bfd76cad2cf8b8fffdf2f08f1b4b338bee6 Mon Sep 17 00:00:00 2001
From: Scott K Logan
Date: Tue, 12 Nov 2019 15:26:35 -0800
Subject: [PATCH 15/55] Set default BUILD_IDLC based on presence of Maven
This will modify the default behavior to select BUILD_IDLC based on
whether Maven is discovered or not.
The behavior when `-DBUILD_IDLC` is specified on the command line remains
unchanged - the build will maintain the current behavior of failing to
configure if `BUILD_IDLC=ON` and Maven was later not found.
This reverts (part of) commit 860a6aadae5c6e31456454496d5b918892434d18.
Signed-off-by: Scott K Logan
---
CMakeLists.txt | 11 ++++++-----
colcon.pkg | 3 ---
package.xml | 2 ++
3 files changed, 8 insertions(+), 8 deletions(-)
delete mode 100644 colcon.pkg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7aaa38..9de873b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,11 +23,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
-# By default the Java-based components get built, but make it possible to disable that: if only the
-# core library is required, there's no need to build them, and that in turn eliminates the Maven and
-# JDK dependency.
-option(BUILD_IDLC "Build IDL preprocessor" ON)
-
# By default don't treat warnings as errors, else anyone building it with a different compiler that
# just happens to generate a warning, as well as anyone adding or modifying something and making a
# small mistake would run into errors. CI builds can be configured differently.
@@ -50,6 +45,12 @@ string(REPLACE " " "-" PROJECT_NAME_DASHED "${PROJECT_NAME_FULL}")
string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_CAPS)
string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_SMALL)
+# By default the Java-based components get built, but make it possible to disable that: if only the
+# core library is required, there's no need to build them, and that in turn eliminates the Maven and
+# JDK dependency.
+find_package(Maven 3.0 QUIET)
+option(BUILD_IDLC "Build IDL preprocessor" ${Maven_FOUND})
+
set(CMAKE_C_STANDARD 99)
if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks")
add_definitions(-std=c99)
diff --git a/colcon.pkg b/colcon.pkg
deleted file mode 100644
index 2d2a3ae..0000000
--- a/colcon.pkg
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "cmake-args": [ "-DBUILD_IDLC=OFF" ]
-}
diff --git a/package.xml b/package.xml
index 9d0980d..5b4b661 100644
--- a/package.xml
+++ b/package.xml
@@ -12,6 +12,8 @@
https://github.com/eclipse-cyclonedds/cyclonedds
cmake
+ java
+ maven
openssl
libcunit-dev
python3-sphinx
From 9260464be8db16f2d1ddc7b29f402dfdb6e36b6d Mon Sep 17 00:00:00 2001
From: Scott K Logan
Date: Tue, 12 Nov 2019 15:37:54 -0800
Subject: [PATCH 16/55] fixup! Set default BUILD_IDLC based on presence of
Maven
Signed-off-by: Scott K Logan
---
package.xml | 2 --
1 file changed, 2 deletions(-)
diff --git a/package.xml b/package.xml
index 5b4b661..9d0980d 100644
--- a/package.xml
+++ b/package.xml
@@ -12,8 +12,6 @@
https://github.com/eclipse-cyclonedds/cyclonedds
cmake
- java
- maven
openssl
libcunit-dev
python3-sphinx
From 7b428f14b9fb4af38ba89b04875b34cb3bcfa384 Mon Sep 17 00:00:00 2001
From: Scott K Logan
Date: Wed, 13 Nov 2019 16:19:40 -0800
Subject: [PATCH 17/55] Allow BUILD_IDLC to be 'AUTO' based on Maven presence
Signed-off-by: Scott K Logan
---
CMakeLists.txt | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9de873b..b679c09 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,8 +48,11 @@ string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_SMALL)
# By default the Java-based components get built, but make it possible to disable that: if only the
# core library is required, there's no need to build them, and that in turn eliminates the Maven and
# JDK dependency.
-find_package(Maven 3.0 QUIET)
-option(BUILD_IDLC "Build IDL preprocessor" ${Maven_FOUND})
+option(BUILD_IDLC "Build IDL preprocessor" ON)
+if(BUILD_IDLC STREQUAL "AUTO")
+ find_package(Maven 3.0 QUIET)
+ set(BUILD_IDLC ${Maven_FOUND})
+endif()
set(CMAKE_C_STANDARD 99)
if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks")
From eeeea486c8d1073501b124bffce1d0b54482637a Mon Sep 17 00:00:00 2001
From: Scott K Logan
Date: Wed, 13 Nov 2019 16:23:51 -0800
Subject: [PATCH 18/55] fixup! Allow BUILD_IDLC to be 'AUTO' based on Maven
presence
Signed-off-by: Scott K Logan
---
colcon.pkg | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 colcon.pkg
diff --git a/colcon.pkg b/colcon.pkg
new file mode 100644
index 0000000..b7468da
--- /dev/null
+++ b/colcon.pkg
@@ -0,0 +1,3 @@
+{
+ "cmake-args": [ "-DBUILD_IDLC=AUTO" ]
+}
From d12b926ff1269e3f22de65a23fe14aa27649a154 Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Mon, 28 Oct 2019 13:47:10 -0500
Subject: [PATCH 19/55] Move IDLC to its own install component
This allows you to express a dependency on it as `find_package(CycloneDDS REQUIRED COMPONENTS idlc)`
Also added a warning if CycloneDDS was built with IDLC but IDLC is not requested.
Signed-off-by: Dan Rose
---
cmake/Modules/Packaging.cmake | 15 +++--------
.../Modules/Packaging/PackageConfig.cmake.in | 25 ++++++++++++++++++-
.../Packaging/PackageConfigNoIdlc.cmake.in | 14 -----------
src/idlc/CMakeLists.txt | 6 ++---
4 files changed, 31 insertions(+), 29 deletions(-)
delete mode 100644 cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in
diff --git a/cmake/Modules/Packaging.cmake b/cmake/Modules/Packaging.cmake
index b2d647c..560e8f4 100644
--- a/cmake/Modules/Packaging.cmake
+++ b/cmake/Modules/Packaging.cmake
@@ -21,17 +21,10 @@ set(PACKAGING_MODULE_DIR "${PROJECT_SOURCE_DIR}/cmake/Modules/Packaging")
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}")
# Generates Config.cmake.
-if(BUILD_IDLC)
- configure_package_config_file(
- "${PACKAGING_MODULE_DIR}/PackageConfig.cmake.in"
- "${PROJECT_NAME}Config.cmake"
- INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
-else()
- configure_package_config_file(
- "${PACKAGING_MODULE_DIR}/PackageConfigNoIdlc.cmake.in"
- "${PROJECT_NAME}Config.cmake"
- INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
-endif()
+configure_package_config_file(
+ "${PACKAGING_MODULE_DIR}/PackageConfig.cmake.in"
+ "${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
# Generates Version.cmake.
write_basic_package_version_file(
diff --git a/cmake/Modules/Packaging/PackageConfig.cmake.in b/cmake/Modules/Packaging/PackageConfig.cmake.in
index c8d6d78..31d8f9b 100644
--- a/cmake/Modules/Packaging/PackageConfig.cmake.in
+++ b/cmake/Modules/Packaging/PackageConfig.cmake.in
@@ -12,4 +12,27 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake")
+option("@PROJECT_NAME@_IDLC_ALWAYS" "Should we include idlc even if the user didn't request the idlc component?" ON)
+
+set("@PROJECT_NAME@_idlc_FOUND" FALSE)
+if ("idlc" IN_LIST "@PROJECT_NAME@_FIND_COMPONENTS" OR "@PROJECT_NAME@_IDLC_ALWAYS")
+ include("${CMAKE_CURRENT_LIST_DIR}/idlc/IdlcGenerate.cmake" OPTIONAL RESULT_VARIABLE _IdlcGenerate)
+ if(NOT _IdlcGenerate STREQUAL "NOTFOUND")
+ set("@PROJECT_NAME@_idlc_FOUND" TRUE)
+ endif()
+endif()
+
+if ("${@PROJECT_NAME@_IDLC_ALWAYS}"
+ AND "${@PROJECT_NAME@_idlc_FOUND}"
+ AND (NOT "idlc" IN_LIST "@PROJECT_NAME@_FIND_COMPONENTS")
+)
+ message(AUTHOR_WARNING "\
+The IDL Compiler 'idlc' has not been requested but has been built is automatically included. \
+This will change in a future release. \
+If you need the idlc compiler, please add idlc to the COMPONENTS or OPTIONAL_COMPONENTS list in \
+find_package(@PROJECT_NAME@ ...). \
+If you don't need it, set the @PROJECT_NAME@_IDLC_ALWAYS=OFF to suppress this message .\
+")
+endif()
+
+check_required_components("@PROJECT_NAME@")
diff --git a/cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in b/cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in
deleted file mode 100644
index 038e6f9..0000000
--- a/cmake/Modules/Packaging/PackageConfigNoIdlc.cmake.in
+++ /dev/null
@@ -1,14 +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
-#
-@PACKAGE_INIT@
-
-include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
diff --git a/src/idlc/CMakeLists.txt b/src/idlc/CMakeLists.txt
index 5616658..ae210c3 100644
--- a/src/idlc/CMakeLists.txt
+++ b/src/idlc/CMakeLists.txt
@@ -46,16 +46,16 @@ include(cmake/IdlcGenerate.cmake)
install(
FILES "cmake/IdlcGenerate.cmake"
DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
- COMPONENT dev)
+ COMPONENT idlc)
install(
FILES "${IDLC_SCRIPT_IN}"
DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
- COMPONENT dev)
+ COMPONENT idlc)
install(
FILES "${IDLC_JAR}"
DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
- COMPONENT dev)
+ COMPONENT idlc)
From bd858ea97f601bfc339a94972da2a82d0e0c752f Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Thu, 31 Oct 2019 17:35:57 -0500
Subject: [PATCH 20/55] Add idlc to packaging and examples
Signed-off-by: Dan Rose
---
cmake/Modules/Packaging.cmake | 4 +++-
examples/helloworld/CMakeLists.export | 2 +-
examples/roundtrip/CMakeLists.export | 2 +-
examples/throughput/CMakeLists.export | 2 +-
4 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/cmake/Modules/Packaging.cmake b/cmake/Modules/Packaging.cmake
index 560e8f4..a635869 100644
--- a/cmake/Modules/Packaging.cmake
+++ b/cmake/Modules/Packaging.cmake
@@ -76,11 +76,13 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/license.txt")
# Although that does not make sense from a technical point-of-view, it
# does help to clearify which settings are required for a platform.
-set(CPACK_COMPONENTS_ALL dev lib)
+set(CPACK_COMPONENTS_ALL dev lib idlc)
set(CPACK_COMPONENT_LIB_DISPLAY_NAME "${PROJECT_NAME_FULL} library")
set(CPACK_COMPONENT_LIB_DESCRIPTION "Library used to run programs with ${PROJECT_NAME_FULL}")
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "${PROJECT_NAME_FULL} development")
set(CPACK_COMPONENT_DEV_DESCRIPTION "Development files for use with ${PROJECT_NAME_FULL}")
+set(CPACK_COMPONENT_IDLC_DISPLAY_NAME "${PROJECT_NAME_FULL} IDL Compiler")
+set(CPACK_COMPONENT_IDLC_DESCRIPTION "Utility for turning IDL files into C++ source for ${PROJECT_NAME_FULL}")
if(WIN32 AND NOT UNIX)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
diff --git a/examples/helloworld/CMakeLists.export b/examples/helloworld/CMakeLists.export
index 5712559..3e24d44 100644
--- a/examples/helloworld/CMakeLists.export
+++ b/examples/helloworld/CMakeLists.export
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
+ find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
diff --git a/examples/roundtrip/CMakeLists.export b/examples/roundtrip/CMakeLists.export
index 9554013..a95a615 100644
--- a/examples/roundtrip/CMakeLists.export
+++ b/examples/roundtrip/CMakeLists.export
@@ -14,7 +14,7 @@ cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
+ find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
diff --git a/examples/throughput/CMakeLists.export b/examples/throughput/CMakeLists.export
index 52415e0..b037bf6 100644
--- a/examples/throughput/CMakeLists.export
+++ b/examples/throughput/CMakeLists.export
@@ -14,7 +14,7 @@ cmake_minimum_required(VERSION 3.5)
if (NOT TARGET CycloneDDS::ddsc)
# Find the CycloneDDS package. If it is not in a default location, try
# finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
+ find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
endif()
# This is a convenience function, provided by the CycloneDDS package,
From 33ba9111924a8edd9097aa539d7e98fb059451f3 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Wed, 30 Oct 2019 14:57:55 +0100
Subject: [PATCH 21/55] Fix dds_create_domain return and error handling
Signed-off-by: Erik Boasson
---
src/core/ddsc/include/dds/dds.h | 7 +-
src/core/ddsc/src/dds__domain.h | 2 +-
src/core/ddsc/src/dds__entity.h | 9 +
src/core/ddsc/src/dds__handles.h | 22 ++-
src/core/ddsc/src/dds__publisher.h | 7 +
src/core/ddsc/src/dds__subscriber.h | 1 +
src/core/ddsc/src/dds__types.h | 4 +-
src/core/ddsc/src/dds_builtin.c | 2 +-
src/core/ddsc/src/dds_domain.c | 123 +++++++------
src/core/ddsc/src/dds_entity.c | 130 ++++++++-----
src/core/ddsc/src/dds_guardcond.c | 6 +-
src/core/ddsc/src/dds_handles.c | 245 ++++++++++++++++++++++---
src/core/ddsc/src/dds_init.c | 3 +-
src/core/ddsc/src/dds_participant.c | 12 +-
src/core/ddsc/src/dds_publisher.c | 19 +-
src/core/ddsc/src/dds_readcond.c | 2 +-
src/core/ddsc/src/dds_reader.c | 50 +++--
src/core/ddsc/src/dds_subscriber.c | 6 +-
src/core/ddsc/src/dds_topic.c | 27 +--
src/core/ddsc/src/dds_waitset.c | 6 +-
src/core/ddsc/src/dds_writer.c | 35 ++--
src/core/ddsc/tests/config.c | 142 +++++++-------
src/core/ddsc/tests/entity_hierarchy.c | 4 +
23 files changed, 562 insertions(+), 302 deletions(-)
diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h
index 6c9ae53..a6f7f73 100644
--- a/src/core/ddsc/include/dds/dds.h
+++ b/src/core/ddsc/include/dds/dds.h
@@ -755,11 +755,8 @@ dds_create_participant(
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
* @param[in] config A configuration string containing file names and/or XML fragments representing the configuration.
*
- * @returns A return code
+ * @returns A valid entity handle or an error code.
*
- * @retval DDS_RETCODE_OK
- * The domain with the domain identifier has been created from
- * given configuration string.
* @retval DDS_RETCODE_BAD_PARAMETER
* Illegal value for domain id or the configfile parameter is NULL.
* @retval DDS_PRECONDITION_NOT_MET
@@ -767,7 +764,7 @@ dds_create_participant(
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
*/
-DDS_EXPORT dds_return_t
+DDS_EXPORT dds_entity_t
dds_create_domain(const dds_domainid_t domain, const char *config);
/**
diff --git a/src/core/ddsc/src/dds__domain.h b/src/core/ddsc/src/dds__domain.h
index db5d7bc..4719440 100644
--- a/src/core/ddsc/src/dds__domain.h
+++ b/src/core/ddsc/src/dds__domain.h
@@ -18,7 +18,7 @@
extern "C" {
#endif
-DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
+DDS_EXPORT dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config) ddsrt_nonnull((1,4));
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
#if defined (__cplusplus)
diff --git a/src/core/ddsc/src/dds__entity.h b/src/core/ddsc/src/dds__entity.h
index 8f4e34c..3725d83 100644
--- a/src/core/ddsc/src/dds__entity.h
+++ b/src/core/ddsc/src/dds__entity.h
@@ -24,6 +24,7 @@ dds_entity_init(
dds_entity * e,
dds_entity * parent,
dds_entity_kind_t kind,
+ bool implicit,
dds_qos_t * qos,
const dds_listener_t *listener,
status_mask_t mask);
@@ -38,6 +39,12 @@ dds_entity_register_child (
DDS_EXPORT void
dds_entity_add_ref_locked(dds_entity *e);
+DDS_EXPORT void
+dds_entity_drop_ref(dds_entity *e);
+
+DDS_EXPORT void
+dds_entity_unpin_and_drop_ref (dds_entity *e);
+
#define DEFINE_ENTITY_LOCK_UNLOCK(qualifier_, type_, kind_) \
qualifier_ dds_return_t type_##_lock (dds_entity_t hdl, type_ **x) \
{ \
@@ -96,6 +103,8 @@ dds_entity_pin (
dds_entity_t hdl,
dds_entity **eptr);
+DDS_EXPORT dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr);
+
DDS_EXPORT void dds_entity_unpin (
dds_entity *e);
diff --git a/src/core/ddsc/src/dds__handles.h b/src/core/ddsc/src/dds__handles.h
index de7d2cd..db85ce7 100644
--- a/src/core/ddsc/src/dds__handles.h
+++ b/src/core/ddsc/src/dds__handles.h
@@ -72,9 +72,11 @@ typedef int32_t dds_handle_t;
/* Closing & closed can be combined, but having two gives a means for enforcing
that close() be called first, then close_wait(), and then delete(). */
-#define HDL_FLAG_CLOSING (0x80000000u)
-#define HDL_FLAG_CLOSED (0x40000000u)
-#define HDL_FLAG_PENDING (0x20000000u)
+#define HDL_FLAG_CLOSING (0x80000000u)
+#define HDL_FLAG_DELETE_DEFERRED (0x40000000u)
+#define HDL_FLAG_PENDING (0x20000000u)
+#define HDL_FLAG_IMPLICIT (0x10000000u)
+#define HDL_FLAG_ALLOW_CHILDREN (0x08000000u) /* refc counts children */
struct dds_handle_link {
dds_handle_t hdl;
@@ -116,7 +118,9 @@ dds_handle_server_fini(void);
*/
DDS_EXPORT dds_handle_t
dds_handle_create(
- struct dds_handle_link *link);
+ struct dds_handle_link *link,
+ bool implicit,
+ bool allow_children);
/*
@@ -124,7 +128,7 @@ dds_handle_create(
*/
DDS_EXPORT dds_return_t
dds_handle_register_special (
- struct dds_handle_link *link, dds_handle_t handle);
+ struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle);
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
@@ -181,6 +185,8 @@ DDS_EXPORT void
dds_handle_unpin(
struct dds_handle_link *link);
+int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link);
+bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent);
/*
* Check if the handle is closed.
@@ -195,11 +201,15 @@ dds_handle_unpin(
DDS_EXPORT void dds_handle_add_ref (struct dds_handle_link *link);
DDS_EXPORT bool dds_handle_drop_ref (struct dds_handle_link *link);
+DDS_EXPORT bool dds_handle_close (struct dds_handle_link *link);
+DDS_EXPORT bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link);
DDS_EXPORT inline bool dds_handle_is_closed (struct dds_handle_link *link) {
- return (ddsrt_atomic_ld32 (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING)) != 0;
+ return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSING) != 0;
}
+DDS_EXPORT bool dds_handle_is_not_refd (struct dds_handle_link *link);
+
#if defined (__cplusplus)
}
#endif
diff --git a/src/core/ddsc/src/dds__publisher.h b/src/core/ddsc/src/dds__publisher.h
index 517abff..d1be193 100644
--- a/src/core/ddsc/src/dds__publisher.h
+++ b/src/core/ddsc/src/dds__publisher.h
@@ -21,6 +21,13 @@ extern "C" {
DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_publisher, DDS_KIND_PUBLISHER)
+dds_entity_t
+dds__create_publisher_l(
+ struct dds_participant *participant, /* entity-lock must be held */
+ bool implicit,
+ const dds_qos_t *qos,
+ const dds_listener_t *listener);
+
dds_return_t dds_publisher_begin_coherent (dds_entity_t e);
dds_return_t dds_publisher_end_coherent (dds_entity_t e);
diff --git a/src/core/ddsc/src/dds__subscriber.h b/src/core/ddsc/src/dds__subscriber.h
index 966f43e..f713dda 100644
--- a/src/core/ddsc/src/dds__subscriber.h
+++ b/src/core/ddsc/src/dds__subscriber.h
@@ -24,6 +24,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_subscriber, DDS_KIND_SUBSCRIBER)
dds_entity_t
dds__create_subscriber_l(
struct dds_participant *participant, /* entity-lock must be held */
+ bool implicit,
const dds_qos_t *qos,
const dds_listener_t *listener);
diff --git a/src/core/ddsc/src/dds__types.h b/src/core/ddsc/src/dds__types.h
index 7d65792..4b9eec5 100644
--- a/src/core/ddsc/src/dds__types.h
+++ b/src/core/ddsc/src/dds__types.h
@@ -245,7 +245,7 @@ typedef struct dds_participant {
typedef struct dds_reader {
struct dds_entity m_entity;
- const struct dds_topic *m_topic;
+ struct dds_topic *m_topic;
struct dds_rhc *m_rhc; /* aliases m_rd->rhc with a wider interface, FIXME: but m_rd owns it for resource management */
struct reader *m_rd;
bool m_data_on_readers;
@@ -265,7 +265,7 @@ typedef struct dds_reader {
typedef struct dds_writer {
struct dds_entity m_entity;
- const struct dds_topic *m_topic;
+ struct dds_topic *m_topic;
struct nn_xpack *m_xp;
struct writer *m_wr;
struct whc *m_whc; /* FIXME: ownership still with underlying DDSI writer (cos of DDSI built-in writers )*/
diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c
index 5720f7d..5b1c71c 100644
--- a/src/core/ddsc/src/dds_builtin.c
+++ b/src/core/ddsc/src/dds_builtin.c
@@ -131,7 +131,7 @@ bool dds__validate_builtin_reader_qos (const dds_domain *dom, dds_entity_t topic
static dds_entity_t dds__create_builtin_subscriber (dds_participant *participant)
{
dds_qos_t *qos = dds__create_builtin_qos ();
- dds_entity_t sub = dds__create_subscriber_l (participant, qos, NULL);
+ dds_entity_t sub = dds__create_subscriber_l (participant, false, qos, NULL);
dds_delete_qos (qos);
return sub;
}
diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c
index feaed61..78028af 100644
--- a/src/core/ddsc/src/dds_domain.c
+++ b/src/core/ddsc/src/dds_domain.c
@@ -48,16 +48,14 @@ static int dds_domain_compare (const void *va, const void *vb)
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
-static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
+static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
{
- dds_return_t ret = DDS_RETCODE_OK;
+ dds_entity_t domh;
uint32_t len;
- dds_entity_t domain_handle;
- if ((domain_handle = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, NULL, NULL, 0)) < 0)
- return domain_handle;
+ if ((domh = dds_entity_init (&domain->m_entity, &dds_global.m_entity, DDS_KIND_DOMAIN, implicit, NULL, NULL, 0)) < 0)
+ return domh;
domain->m_entity.m_domain = domain;
- domain->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
domain->m_entity.m_iid = ddsi_iid_gen ();
domain->gv.tstart = now ();
@@ -90,7 +88,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (domain->cfgst == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration\n");
- ret = DDS_RETCODE_ERROR;
+ domh = DDS_RETCODE_ERROR;
goto fail_config;
}
@@ -100,14 +98,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (rtps_config_prep (&domain->gv, domain->cfgst) != 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to configure RTPS\n");
- ret = DDS_RETCODE_ERROR;
+ domh = DDS_RETCODE_ERROR;
goto fail_rtps_config;
}
if (rtps_init (&domain->gv) < 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to initialize RTPS\n");
- ret = DDS_RETCODE_ERROR;
+ domh = DDS_RETCODE_ERROR;
goto fail_rtps_init;
}
@@ -122,14 +120,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (dds_global.threadmon == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to create a thread liveliness monitor\n");
- ret = DDS_RETCODE_OUT_OF_RESOURCES;
+ domh = DDS_RETCODE_OUT_OF_RESOURCES;
goto fail_threadmon_new;
}
/* FIXME: thread properties */
if (ddsi_threadmon_start (dds_global.threadmon, "threadmon") < 0)
{
DDS_ILOG (DDS_LC_ERROR, domain->m_id, "Failed to start the thread liveliness monitor\n");
- ret = DDS_RETCODE_ERROR;
+ domh = DDS_RETCODE_ERROR;
goto fail_threadmon_start;
}
}
@@ -159,14 +157,14 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
if (rtps_start (&domain->gv) < 0)
{
DDS_ILOG (DDS_LC_CONFIG, domain->m_id, "Failed to start RTPS\n");
- ret = DDS_RETCODE_ERROR;
+ domh = DDS_RETCODE_ERROR;
goto fail_rtps_start;
}
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_register_domain (dds_global.threadmon, &domain->gv);
dds_entity_init_complete (&domain->m_entity);
- return DDS_RETCODE_OK;
+ return domh;
fail_rtps_start:
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
@@ -184,7 +182,7 @@ fail_rtps_config:
config_fini (domain->cfgst);
fail_config:
dds_handle_delete (&domain->m_entity.m_hdllink);
- return ret;
+ return domh;
}
dds_domain *dds_domain_find_locked (dds_domainid_t id)
@@ -192,10 +190,10 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
}
-dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
+dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config)
{
struct dds_domain *dom;
- dds_return_t ret;
+ dds_entity_t domh;
/* FIXME: should perhaps lock parent object just like everywhere */
ddsrt_mutex_lock (&dds_global.m_mutex);
@@ -203,60 +201,71 @@ dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t
if (id != DDS_DOMAIN_DEFAULT)
{
if ((dom = dds_domain_find_locked (id)) == NULL)
- ret = DDS_RETCODE_NOT_FOUND;
+ domh = DDS_RETCODE_NOT_FOUND;
else
- ret = DDS_RETCODE_OK;
+ domh = dom->m_entity.m_hdllink.hdl;
}
else
{
if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL)
- ret = DDS_RETCODE_OK;
+ domh = dom->m_entity.m_hdllink.hdl;
else
- ret = DDS_RETCODE_NOT_FOUND;
+ domh = DDS_RETCODE_NOT_FOUND;
}
- switch (ret)
+ if (domh == DDS_RETCODE_NOT_FOUND)
{
- case DDS_RETCODE_OK:
- if (!use_existing)
- {
- ret = DDS_RETCODE_PRECONDITION_NOT_MET;
- break;
- }
+ dom = dds_alloc (sizeof (*dom));
+ if ((domh = dds_domain_init (dom, id, config, implicit)) < 0)
+ dds_free (dom);
+ else
+ {
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
- if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
- {
- ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
- ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
- goto retry;
- }
- else
+ ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
+ dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
+ if (implicit)
{
dds_entity_add_ref_locked (&dom->m_entity);
- ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
- *domain_out = dom;
+ dds_handle_repin (&dom->m_entity.m_hdllink);
}
- break;
- case DDS_RETCODE_NOT_FOUND:
- dom = dds_alloc (sizeof (*dom));
- if ((ret = dds_domain_init (dom, id, config)) < 0)
- dds_free (dom);
- else
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
+ *domain_out = dom;
+ }
+ }
+ else if (domh <= DDS_RETCODE_OK)
+ {
+ assert (0);
+ domh = DDS_RETCODE_ERROR;
+ }
+ else if (!implicit)
+ {
+ domh = DDS_RETCODE_PRECONDITION_NOT_MET;
+ }
+ else
+ {
+ ddsrt_mutex_lock (&dom->m_entity.m_mutex);
+ if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
+ {
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
+ ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
+ goto retry;
+ }
+ else
+ {
+ if (implicit)
{
- ddsrt_mutex_lock (&dom->m_entity.m_mutex);
- ddsrt_avl_insert (&dds_domaintree_def, &dds_global.m_domains, dom);
- dds_entity_register_child (&dds_global.m_entity, &dom->m_entity);
dds_entity_add_ref_locked (&dom->m_entity);
- ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
- *domain_out = dom;
+ dds_handle_repin (&dom->m_entity.m_hdllink);
}
- break;
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
+ *domain_out = dom;
+ }
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
- return ret;
+ return domh;
}
-dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
+dds_entity_t dds_create_domain (const dds_domainid_t domain, const char *config)
{
dds_domain *dom;
dds_entity_t ret;
@@ -266,16 +275,10 @@ dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
- goto err_dds_init;
+ return ret;
- if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
- goto err_domain_create;
-
- return DDS_RETCODE_OK;
-
-err_domain_create:
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
-err_dds_init:
+ ret = dds_domain_create_internal (&dom, domain, false, config);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
}
@@ -368,5 +371,5 @@ void dds_write_set_batch (bool enable)
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
}
diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c
index 56a5ce4..4288f4b 100644
--- a/src/core/ddsc/src/dds_entity.c
+++ b/src/core/ddsc/src/dds_entity.c
@@ -80,11 +80,40 @@ const ddsrt_avl_treedef_t dds_entity_children_td = DDSRT_AVL_TREEDEF_INITIALIZER
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status);
static void dds_entity_observers_signal_delete (dds_entity *observed);
+static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
+static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate);
+
void dds_entity_add_ref_locked (dds_entity *e)
{
dds_handle_add_ref (&e->m_hdllink);
}
+void dds_entity_drop_ref (dds_entity *e)
+{
+ if (dds_handle_drop_ref (&e->m_hdllink))
+ {
+ /* increment pin count unconditionally to satisfy the "pinned" requirement */
+ dds_handle_repin (&e->m_hdllink);
+ ddsrt_mutex_lock (&e->m_mutex);
+ dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
+ assert (ret == DDS_RETCODE_OK);
+ (void) ret;
+ }
+}
+
+void dds_entity_unpin_and_drop_ref (dds_entity *e)
+{
+ if (dds_handle_unpin_and_drop_ref (&e->m_hdllink))
+ {
+ /* increment pin count unconditionally to satisfy the "pinned" requirement */
+ dds_handle_repin (&e->m_hdllink);
+ ddsrt_mutex_lock (&e->m_mutex);
+ dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
+ assert (ret == DDS_RETCODE_OK);
+ (void) ret;
+ }
+}
+
static bool entity_has_status (const dds_entity *e)
{
switch (e->m_kind)
@@ -110,7 +139,7 @@ static bool entity_has_status (const dds_entity *e)
return false;
}
-dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
+dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask)
{
dds_handle_t handle;
@@ -125,6 +154,8 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
e->m_flags |= DDS_ENTITY_ENABLED;
+ if (implicit)
+ e->m_flags |= DDS_ENTITY_IMPLICIT;
/* set the status enable based on kind */
if (entity_has_status (e))
@@ -162,12 +193,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
if (kind == DDS_KIND_CYCLONEDDS)
{
- if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
+ if ((handle = dds_handle_register_special (&e->m_hdllink, implicit, true, DDS_CYCLONEDDS_HANDLE)) <= 0)
return (dds_entity_t) handle;
}
else
{
- if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
+ /* for topics, refc counts readers/writers, for all others, it counts children (this we can get away with
+ as long as topics can't have children) */
+ if ((handle = dds_handle_create (&e->m_hdllink, implicit, (kind != DDS_KIND_TOPIC))) <= 0)
return (dds_entity_t) handle;
}
@@ -182,9 +215,12 @@ void dds_entity_init_complete (dds_entity *entity)
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
{
+ /* parent must be tracking children in its refc, or children can't be added */
+ assert (ddsrt_atomic_ld32 (&parent->m_hdllink.cnt_flags) & HDL_FLAG_ALLOW_CHILDREN);
assert (child->m_iid != 0);
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &child->m_iid) == NULL);
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
+ dds_entity_add_ref_locked (parent);
}
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
@@ -227,13 +263,11 @@ static void print_delete (const dds_entity *e, enum delete_impl_state delstate ,
printf ("delete(%p, delstate %s, iid %"PRIx64"): %s%s %d pin %u refc %u %s %s\n",
(void *) e, (delstate == DIS_IMPLICIT) ? "implicit" : (delstate == DIS_EXPLICIT) ? "explicit" : "from_parent", iid,
entity_kindstr (e->m_kind), (e->m_flags & DDS_ENTITY_IMPLICIT) ? " [implicit]" : "",
- e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0xffff, (cm & 0x80000000) ? "closed" : "open",
+ e->m_hdllink.hdl, cm & 0xfff, (cm >> 12) & 0x7fff, (cm & 0x80000000) ? "closed" : "open",
ddsrt_avl_is_empty (&e->m_children) ? "childless" : "has-children");
}
#endif
-static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate);
-
dds_return_t dds_delete (dds_entity_t entity)
{
return dds_delete_impl (entity, DIS_EXPLICIT);
@@ -252,53 +286,34 @@ static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state
{
dds_entity *e;
dds_return_t ret;
- if ((ret = dds_entity_pin (entity, &e)) < 0)
- return ret;
- else
+ if ((ret = dds_entity_pin_for_delete (entity, (delstate != DIS_IMPLICIT), &e)) == DDS_RETCODE_OK)
return dds_delete_impl_pinned (e, delstate);
+ else if (ret == DDS_RETCODE_TRY_AGAIN) /* non-child refs exist */
+ return DDS_RETCODE_OK;
+ else
+ return ret;
}
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
{
- dds_entity *child;
- dds_return_t ret;
-
/* Any number of threads pinning it, possibly in delete, or having pinned it and
trying to acquire m_mutex */
ddsrt_mutex_lock (&e->m_mutex);
#if TRACE_DELETE
- print_delete (e, delstate, iid);
+ print_delete (e, delstate, e->m_iid);
#endif
/* If another thread was racing us in delete, it will have set the CLOSING flag
while holding m_mutex and we had better bail out. */
- if (dds_handle_is_closed (&e->m_hdllink))
- {
- dds_entity_unlock (e);
- return DDS_RETCODE_OK;
- }
+ assert (dds_handle_is_closed (&e->m_hdllink));
+ return really_delete_pinned_closed_locked (e, delstate);
+}
- /* Ignore children calling up to delete an implicit parent if there are still
- (or again) children */
- if (delstate == DIS_IMPLICIT)
- {
- if (!((e->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&e->m_children)))
- {
- dds_entity_unlock (e);
- return DDS_RETCODE_OK;
- }
- }
-
- /* Drop reference, atomically setting CLOSING if no other references remain.
- FIXME: that's not quite right: this is really only for topics. After a call
- to delete, the handle ought to become invalid even if the topic stays (and
- should perhaps even be revivable via find_topic). */
- if (! dds_handle_drop_ref (&e->m_hdllink))
- {
- dds_entity_unlock (e);
- return DDS_RETCODE_OK;
- }
+static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate)
+{
+ dds_entity *child;
+ dds_return_t ret;
/* No threads pinning it anymore, no need to worry about other threads deleting
it, but there can still be plenty of threads that have it pinned and are
@@ -360,15 +375,23 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
/* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
dds_entity_t child_handle = child->m_hdllink.hdl;
ddsrt_mutex_unlock (&e->m_mutex);
- (void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
+ ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
+ assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
+ (void) ret;
ddsrt_mutex_lock (&e->m_mutex);
+ if (ret == DDS_RETCODE_BAD_PARAMETER && child == next_non_topic_child (&e->m_children))
+ {
+ ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
+ }
}
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
{
assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
dds_entity_t child_handle = child->m_hdllink.hdl;
ddsrt_mutex_unlock (&e->m_mutex);
- (void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
+ ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
+ assert (ret == DDS_RETCODE_OK);
+ (void) ret;
ddsrt_mutex_lock (&e->m_mutex);
}
ddsrt_mutex_unlock (&e->m_mutex);
@@ -391,15 +414,15 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
ddsrt_mutex_lock (&p->m_mutex);
assert (ddsrt_avl_lookup (&dds_entity_children_td, &p->m_children, &e->m_iid) != NULL);
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
+ if (dds_handle_drop_childref_and_pin (&p->m_hdllink, delstate != DIS_FROM_PARENT))
+ {
+ assert (dds_handle_is_closed (&p->m_hdllink));
+ assert (dds_handle_is_not_refd (&p->m_hdllink));
+ assert (ddsrt_avl_is_empty (&p->m_children));
+ parent_to_delete = p;
+ }
/* trigger parent in case it is waiting in delete */
ddsrt_cond_broadcast (&p->m_cond);
-
- if (delstate != DIS_FROM_PARENT && (p->m_flags & DDS_ENTITY_IMPLICIT) && ddsrt_avl_is_empty (&p->m_children))
- {
- if ((ret = dds_entity_pin (p->m_hdllink.hdl, &parent_to_delete)) < 0)
- parent_to_delete = NULL;
- }
-
ddsrt_mutex_unlock (&p->m_mutex);
}
@@ -1121,6 +1144,19 @@ dds_return_t dds_entity_pin (dds_entity_t hdl, dds_entity **eptr)
}
}
+dds_return_t dds_entity_pin_for_delete (dds_entity_t hdl, bool explicit, dds_entity **eptr)
+{
+ dds_return_t hres;
+ struct dds_handle_link *hdllink;
+ if ((hres = dds_handle_pin_for_delete (hdl, explicit, &hdllink)) < 0)
+ return hres;
+ else
+ {
+ *eptr = dds_entity_from_handle_link (hdllink);
+ return DDS_RETCODE_OK;
+ }
+}
+
void dds_entity_unpin (dds_entity *e)
{
dds_handle_unpin (&e->m_hdllink);
diff --git a/src/core/ddsc/src/dds_guardcond.c b/src/core/ddsc/src/dds_guardcond.c
index 0549d52..b78dd1a 100644
--- a/src/core/ddsc/src/dds_guardcond.c
+++ b/src/core/ddsc/src/dds_guardcond.c
@@ -57,18 +57,18 @@ dds_entity_t dds_create_guardcondition (dds_entity_t owner)
}
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
- dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, NULL, NULL, 0);
+ dds_entity_t hdl = dds_entity_init (&gcond->m_entity, e, DDS_KIND_COND_GUARD, false, NULL, NULL, 0);
gcond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (e, &gcond->m_entity);
dds_entity_init_complete (&gcond->m_entity);
dds_entity_unlock (e);
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return rc;
}
diff --git a/src/core/ddsc/src/dds_handles.c b/src/core/ddsc/src/dds_handles.c
index c4f1f6c..4e22e4e 100644
--- a/src/core/ddsc/src/dds_handles.c
+++ b/src/core/ddsc/src/dds_handles.c
@@ -20,11 +20,36 @@
#include "dds__handles.h"
#include "dds__types.h"
-#define HDL_REFCOUNT_MASK (0x0ffff000u)
+#define HDL_REFCOUNT_MASK (0x07fff000u)
#define HDL_REFCOUNT_UNIT (0x00001000u)
#define HDL_REFCOUNT_SHIFT 12
#define HDL_PINCOUNT_MASK (0x00000fffu)
+/*
+"regular" entities other than topics:
+ - create makes it
+ - delete deletes it and its children immediately
+ - explicit domain: additional protection for bootstrapping complications need extra care
+
+implicit entities other than topics (pub, sub, domain, cyclonedds):
+ - created "spontaneously" as a consequence of creating the writer/reader/participant
+ - delete of last child causes it to disappear
+ - explicit delete treated like a delete of a "regular" entity
+ - domain, cyclonedds: bootstrapping complications require additional protection
+
+topics:
+ - create makes it
+ - never has children (so the handle's cnt_flags can have a different meaning)
+ - readers, writers keep it in existence
+ - delete deferred until no readers/writers exist
+ - an attempt at deleting it fails if in "deferred delete" state (or should it simply
+ return ok while doing nothing?), other operations keep going so, e.g., listeners
+ remain useful
+
+built-in topics:
+ - implicit variant of a topic
+*/
+
/* Maximum number of handles is INT32_MAX - 1, but as the allocator relies on a
random generator for finding a free one, the time spent in the dds_handle_create
increases with an increasing number of handles. 16M handles seems likely to be
@@ -82,7 +107,7 @@ void dds_handle_server_fini (void)
cf & HDL_PINCOUNT_MASK, (cf & HDL_REFCOUNT_MASK) >> HDL_REFCOUNT_SHIFT,
cf & HDL_FLAG_PENDING ? " pending" : "",
cf & HDL_FLAG_CLOSING ? " closing" : "",
- cf & HDL_FLAG_CLOSED ? " closed" : "");
+ cf & HDL_FLAG_DELETE_DEFERRED ? " delete-deferred" : "");
}
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
#endif
@@ -94,9 +119,9 @@ void dds_handle_server_fini (void)
}
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
-static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
+static dds_handle_t dds_handle_create_int (struct dds_handle_link *link, bool implicit, bool refc_counts_children)
{
- ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
+ ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (refc_counts_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
do {
do {
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
@@ -105,7 +130,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
return link->hdl;
}
-dds_handle_t dds_handle_create (struct dds_handle_link *link)
+dds_handle_t dds_handle_create (struct dds_handle_link *link, bool implicit, bool allow_children)
{
dds_handle_t ret;
ddsrt_mutex_lock (&handles.lock);
@@ -117,14 +142,14 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
else
{
handles.count++;
- ret = dds_handle_create_int (link);
+ ret = dds_handle_create_int (link, implicit, allow_children);
ddsrt_mutex_unlock (&handles.lock);
assert (ret > 0);
}
return ret;
}
-dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
+dds_return_t dds_handle_register_special (struct dds_handle_link *link, bool implicit, bool allow_children, dds_handle_t handle)
{
dds_return_t ret;
if (handle <= 0)
@@ -138,7 +163,7 @@ dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_hand
else
{
handles.count++;
- ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
+ ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | (implicit ? HDL_FLAG_IMPLICIT : HDL_REFCOUNT_UNIT) | (allow_children ? HDL_FLAG_ALLOW_CHILDREN : 0) | 1u);
link->hdl = handle;
if (hhadd (handles.ht, link))
ret = handle;
@@ -155,9 +180,9 @@ void dds_handle_unpend (struct dds_handle_link *link)
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((cf & HDL_FLAG_PENDING));
- assert (!(cf & HDL_FLAG_CLOSED));
+ assert (!(cf & HDL_FLAG_DELETE_DEFERRED));
assert (!(cf & HDL_FLAG_CLOSING));
- assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
+ assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT || (cf & HDL_FLAG_IMPLICIT));
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
@@ -171,7 +196,6 @@ int32_t dds_handle_delete (struct dds_handle_link *link)
if (!(cf & HDL_FLAG_PENDING))
{
assert (cf & HDL_FLAG_CLOSING);
- assert (cf & HDL_FLAG_CLOSED);
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
}
assert ((cf & HDL_PINCOUNT_MASK) == 1u);
@@ -213,7 +237,7 @@ static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_
rc = DDS_RETCODE_OK;
do {
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
- if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
+ if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
{
rc = DDS_RETCODE_BAD_PARAMETER;
break;
@@ -229,6 +253,149 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
return dds_handle_pin_int (hdl, 1u, link);
}
+int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_handle_link **link)
+{
+ struct dds_handle_link dummy = { .hdl = hdl };
+ int32_t rc;
+ /* it makes sense to check here for initialization: the first thing any operation
+ (other than create_participant) does is to call dds_handle_pin on the supplied
+ entity, so checking here whether the library has been initialised helps avoid
+ crashes if someone forgets to create a participant (or allows a program to
+ continue after failing to create one).
+
+ One could check that the handle is > 0, but that would catch fewer errors
+ without any advantages. */
+ if (handles.ht == NULL)
+ return DDS_RETCODE_PRECONDITION_NOT_MET;
+
+ ddsrt_mutex_lock (&handles.lock);
+ *link = ddsrt_hh_lookup (handles.ht, &dummy);
+ if (*link == NULL)
+ rc = DDS_RETCODE_BAD_PARAMETER;
+ else
+ {
+ uint32_t cf, cf1;
+ /* Assume success; bail out if the object turns out to be in the process of
+ being deleted */
+ rc = DDS_RETCODE_OK;
+ do {
+ cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
+
+ if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
+ {
+ /* Only one can succeed (and if closing is already set, the handle's reference has
+ already been dropped) */
+ rc = DDS_RETCODE_BAD_PARAMETER;
+ break;
+ }
+ else if (cf & HDL_FLAG_DELETE_DEFERRED)
+ {
+ /* Someone already called delete, but the operation was deferred becauses there are still
+ outstanding references. This implies that there are no children, because then the
+ entire hierarchy would simply have been deleted. */
+ assert (!(cf & HDL_FLAG_ALLOW_CHILDREN));
+ rc = DDS_RETCODE_ALREADY_DELETED;
+ break;
+ }
+ else if (explicit)
+ {
+ /* Explicit call to dds_delete (either by application or by parent deleting its children) */
+ if (cf & HDL_FLAG_IMPLICIT)
+ {
+ /* Entity is implicit, so handle doesn't hold a reference */
+ cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
+ }
+ else if (cf & HDL_FLAG_ALLOW_CHILDREN)
+ {
+ /* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ }
+ else
+ {
+ /* Entity is explicit, so handle held a reference, refc counts non-children, refc > 1 means drop ref and error (so don't pin) */
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ else
+ {
+ cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
+ }
+ }
+ }
+ else
+ {
+ /* Implicit call to dds_delete (child invoking delete on its parent) */
+ if (cf & HDL_FLAG_IMPLICIT)
+ {
+ if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ else
+ {
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ cf1 = (cf - HDL_REFCOUNT_UNIT);
+ }
+ }
+ else
+ {
+ /* Child can't delete an explicit parent */
+ rc = DDS_RETCODE_ILLEGAL_OPERATION;
+ break;
+ }
+ }
+
+ rc = ((cf1 & HDL_REFCOUNT_MASK) == 0 || (cf1 & HDL_FLAG_ALLOW_CHILDREN)) ? DDS_RETCODE_OK : DDS_RETCODE_TRY_AGAIN;
+ } while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf1));
+ }
+ ddsrt_mutex_unlock (&handles.lock);
+ return rc;
+}
+
+bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_delete_parent)
+{
+ bool del_parent = false;
+ ddsrt_mutex_lock (&handles.lock);
+ uint32_t cf, cf1;
+ do {
+ cf = ddsrt_atomic_ld32 (&link->cnt_flags);
+
+ if (cf & (HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
+ {
+ /* Only one can succeed; child ref still to be removed */
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ cf1 = (cf - HDL_REFCOUNT_UNIT);
+ del_parent = false;
+ }
+ else
+ {
+ if (cf & HDL_FLAG_IMPLICIT)
+ {
+ /* Implicit parent: delete if last ref */
+ if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && may_delete_parent)
+ {
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ del_parent = true;
+ }
+ else
+ {
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ cf1 = (cf - HDL_REFCOUNT_UNIT);
+ del_parent = false;
+ }
+ }
+ else
+ {
+ /* Child can't delete an explicit parent; child ref still to be removed */
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ cf1 = (cf - HDL_REFCOUNT_UNIT);
+ del_parent = false;
+ }
+ }
+ } while (!ddsrt_atomic_cas32 (&link->cnt_flags, cf, cf1));
+ ddsrt_mutex_unlock (&handles.lock);
+ return del_parent;
+}
+
int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
{
return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
@@ -237,7 +404,6 @@ int32_t dds_handle_pin_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
void dds_handle_repin (struct dds_handle_link *link)
{
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
- assert (!(x & HDL_FLAG_CLOSED));
(void) x;
}
@@ -245,7 +411,6 @@ void dds_handle_unpin (struct dds_handle_link *link)
{
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
- assert (!(cf & HDL_FLAG_CLOSED));
if (cf & HDL_FLAG_CLOSING)
assert ((cf & HDL_PINCOUNT_MASK) > 1u);
else
@@ -266,16 +431,47 @@ void dds_handle_add_ref (struct dds_handle_link *link)
bool dds_handle_drop_ref (struct dds_handle_link *link)
{
- assert ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) != 0);
uint32_t old, new;
do {
old = ddsrt_atomic_ld32 (&link->cnt_flags);
- if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
- new = old - HDL_REFCOUNT_UNIT;
- else
- new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
+ assert ((old & HDL_REFCOUNT_MASK) > 0);
+ new = old - HDL_REFCOUNT_UNIT;
+ if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
+ new |= HDL_FLAG_CLOSING;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
- return (new & HDL_REFCOUNT_MASK) == 0;
+ ddsrt_mutex_lock (&handles.lock);
+ if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
+ {
+ ddsrt_cond_broadcast (&handles.cond);
+ }
+ ddsrt_mutex_unlock (&handles.lock);
+ return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
+}
+
+bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
+{
+ uint32_t old, new;
+ do {
+ old = ddsrt_atomic_ld32 (&link->cnt_flags);
+ assert ((old & HDL_REFCOUNT_MASK) > 0);
+ assert ((old & HDL_PINCOUNT_MASK) > 0);
+ new = old - HDL_REFCOUNT_UNIT - 1u;
+ if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && (old & HDL_FLAG_IMPLICIT))
+ new |= HDL_FLAG_CLOSING;
+ } while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
+ ddsrt_mutex_lock (&handles.lock);
+ if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
+ {
+ ddsrt_cond_broadcast (&handles.cond);
+ }
+ ddsrt_mutex_unlock (&handles.lock);
+ return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
+}
+
+bool dds_handle_close (struct dds_handle_link *link)
+{
+ uint32_t old = ddsrt_atomic_or32_ov (&link->cnt_flags, HDL_FLAG_CLOSING);
+ return (old & HDL_REFCOUNT_MASK) == 0;
}
void dds_handle_close_wait (struct dds_handle_link *link)
@@ -283,17 +479,18 @@ void dds_handle_close_wait (struct dds_handle_link *link)
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((cf & HDL_FLAG_CLOSING));
- assert (!(cf & HDL_FLAG_CLOSED));
- assert ((cf & HDL_REFCOUNT_MASK) == 0u);
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_mutex_lock (&handles.lock);
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 1u)
ddsrt_cond_wait (&handles.cond, &handles.lock);
/* only one thread may call close_wait on a given handle */
- assert (!(ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED));
- ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
ddsrt_mutex_unlock (&handles.lock);
}
+bool dds_handle_is_not_refd (struct dds_handle_link *link)
+{
+ return ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_REFCOUNT_MASK) == 0);
+}
+
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);
diff --git a/src/core/ddsc/src/dds_init.c b/src/core/ddsc/src/dds_init.c
index 9ad0299..7444a26 100644
--- a/src/core/ddsc/src/dds_init.c
+++ b/src/core/ddsc/src/dds_init.c
@@ -119,9 +119,8 @@ dds_return_t dds_init (void)
goto fail_handleserver;
}
- dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, NULL, NULL, 0);
+ dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, true, NULL, NULL, 0);
dds_global.m_entity.m_iid = ddsi_iid_gen ();
- dds_global.m_entity.m_flags = DDS_ENTITY_IMPLICIT;
dds_handle_repin (&dds_global.m_entity.m_hdllink);
dds_entity_add_ref_locked (&dds_global.m_entity);
dds_entity_init_complete (&dds_global.m_entity);
diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c
index 4825f23..cafa6f9 100644
--- a/src/core/ddsc/src/dds_participant.c
+++ b/src/core/ddsc/src/dds_participant.c
@@ -117,7 +117,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
}
pp = dds_alloc (sizeof (*pp));
- if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
+ if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, false, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
goto err_entity_init;
pp->m_entity.m_guid = guid;
@@ -132,8 +132,8 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
dds_entity_init_complete (&pp->m_entity);
/* drop temporary extra ref to domain, dds_init */
- dds_delete (dom->m_entity.m_hdllink.hdl);
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dom->m_entity);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
err_entity_init:
@@ -141,9 +141,9 @@ err_entity_init:
err_new_participant:
err_qos_validation:
dds_delete_qos (new_qos);
- dds_delete (dom->m_entity.m_hdllink.hdl);
+ dds_entity_unpin_and_drop_ref (&dom->m_entity);
err_domain_create:
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
err_dds_init:
return ret;
}
@@ -175,6 +175,6 @@ dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *par
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return ret;
}
diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c
index dc059af..ae20658 100644
--- a/src/core/ddsc/src/dds_publisher.c
+++ b/src/core/ddsc/src/dds_publisher.c
@@ -45,17 +45,13 @@ const struct dds_entity_deriver dds_entity_deriver_publisher = {
.validate_status = dds_publisher_status_validate
};
-dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
+dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
{
- dds_participant *par;
dds_publisher *pub;
dds_entity_t hdl;
dds_qos_t *new_qos;
dds_return_t ret;
- if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
- return ret;
-
new_qos = dds_create_qos ();
if (qos)
nn_xqos_mergein_missing (new_qos, qos, DDS_PUBLISHER_QOS_MASK);
@@ -67,10 +63,21 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
}
pub = dds_alloc (sizeof (*pub));
- hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
+ hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, implicit, new_qos, listener, DDS_PUBLISHER_STATUS_MASK);
pub->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &pub->m_entity);
dds_entity_init_complete (&pub->m_entity);
+ return hdl;
+}
+
+dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener)
+{
+ dds_participant *par;
+ dds_entity_t hdl;
+ dds_return_t ret;
+ if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
+ return ret;
+ hdl = dds__create_publisher_l (par, false, qos, listener);
dds_participant_unlock (par);
return hdl;
}
diff --git a/src/core/ddsc/src/dds_readcond.c b/src/core/ddsc/src/dds_readcond.c
index 806f913..8028a1d 100644
--- a/src/core/ddsc/src/dds_readcond.c
+++ b/src/core/ddsc/src/dds_readcond.c
@@ -41,7 +41,7 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
{
dds_readcond *cond = dds_alloc (sizeof (*cond));
assert ((kind == DDS_KIND_COND_READ && filter == 0) || (kind == DDS_KIND_COND_QUERY && filter != 0));
- (void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
+ (void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, false, NULL, NULL, 0);
cond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&rd->m_entity, &cond->m_entity);
cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;
diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c
index 4fcf222..22e118b 100644
--- a/src/core/ddsc/src/dds_reader.c
+++ b/src/core/ddsc/src/dds_reader.c
@@ -62,11 +62,11 @@ static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_reader_delete (dds_entity *e)
{
dds_reader * const rd = (dds_reader *) e;
- (void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
dds_free (rd->m_loan);
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
dds_rhc_free (rd->m_rhc);
thread_state_asleep (lookup_thread_state ());
+ dds_entity_drop_ref (&rd->m_topic->m_entity);
return DDS_RETCODE_OK;
}
@@ -332,36 +332,37 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
case DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION:
internal_topic = true;
subscriber = dds__get_builtin_subscriber (participant_or_subscriber);
+ if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
+ return ret;
t = dds__get_builtin_topic (subscriber, topic);
break;
default: {
dds_entity *p_or_s;
- if ((ret = dds_entity_pin (participant_or_subscriber, &p_or_s)) != DDS_RETCODE_OK)
+ if ((ret = dds_entity_lock (participant_or_subscriber, DDS_KIND_DONTCARE, &p_or_s)) != DDS_RETCODE_OK)
return ret;
- if (dds_entity_kind (p_or_s) == DDS_KIND_PARTICIPANT)
- subscriber = dds_create_subscriber (participant_or_subscriber, qos, NULL);
- else
- subscriber = participant_or_subscriber;
- dds_entity_unpin (p_or_s);
+ switch (dds_entity_kind (p_or_s))
+ {
+ case DDS_KIND_SUBSCRIBER:
+ subscriber = participant_or_subscriber;
+ sub = (dds_subscriber *) p_or_s;
+ break;
+ case DDS_KIND_PARTICIPANT:
+ subscriber = dds__create_subscriber_l ((dds_participant *) p_or_s, true, qos, NULL);
+ dds_entity_unlock (p_or_s);
+ if ((ret = dds_subscriber_lock (subscriber, &sub)) < 0)
+ return ret;
+ break;
+ default:
+ dds_entity_unlock (p_or_s);
+ return DDS_RETCODE_ILLEGAL_OPERATION;
+ }
internal_topic = false;
t = topic;
break;
}
}
- if ((ret = dds_subscriber_lock (subscriber, &sub)) != DDS_RETCODE_OK)
- {
- reader = ret;
- goto err_sub_lock;
- }
-
- if (subscriber != participant_or_subscriber && !internal_topic)
- {
- /* Delete implicit subscriber if reader creation fails */
- sub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
- }
-
if ((ret = dds_topic_lock (t, &tp)) != DDS_RETCODE_OK)
{
reader = ret;
@@ -405,7 +406,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
/* Create reader and associated read cache (if not provided by caller) */
rd = dds_alloc (sizeof (*rd));
- reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, rqos, listener, DDS_READER_STATUS_MASK);
+ reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK);
rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
rd->m_topic = tp;
rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
@@ -431,12 +432,6 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
dds_topic_unlock (tp);
dds_subscriber_unlock (sub);
-
- if (internal_topic)
- {
- /* If topic is builtin, then the topic entity is local and should be deleted because the application won't. */
- dds_delete (t);
- }
return reader;
err_bad_qos:
@@ -446,9 +441,6 @@ err_tp_lock:
dds_subscriber_unlock (sub);
if ((sub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
(void) dds_delete (subscriber);
-err_sub_lock:
- if (internal_topic)
- dds_delete (t);
return reader;
}
diff --git a/src/core/ddsc/src/dds_subscriber.c b/src/core/ddsc/src/dds_subscriber.c
index 9fe13bc..0729064 100644
--- a/src/core/ddsc/src/dds_subscriber.c
+++ b/src/core/ddsc/src/dds_subscriber.c
@@ -45,7 +45,7 @@ const struct dds_entity_deriver dds_entity_deriver_subscriber = {
.validate_status = dds_subscriber_status_validate
};
-dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_qos_t *qos, const dds_listener_t *listener)
+dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener)
{
/* participant entity lock must be held */
dds_subscriber *sub;
@@ -64,7 +64,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
}
sub = dds_alloc (sizeof (*sub));
- subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
+ subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, implicit, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK);
sub->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&participant->m_entity, &sub->m_entity);
dds_entity_init_complete (&sub->m_entity);
@@ -78,7 +78,7 @@ dds_entity_t dds_create_subscriber (dds_entity_t participant, const dds_qos_t *q
dds_return_t ret;
if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
return ret;
- hdl = dds__create_subscriber_l (par, qos, listener);
+ hdl = dds__create_subscriber_l (par, false, qos, listener);
dds_participant_unlock (par);
return hdl;
}
diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c
index 6101b79..4630336 100644
--- a/src/core/ddsc/src/dds_topic.c
+++ b/src/core/ddsc/src/dds_topic.c
@@ -31,6 +31,7 @@
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_globals.h"
+#include "dds__serdata_builtintopic.h"
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic)
@@ -135,12 +136,16 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
ret = false;
else
{
- /* FIXME: calling addref is wrong because the Cyclone library has no
- knowledge of the reference and hence simply deleting the participant
- won't make the ref count drop to 0. On the other hand, the DDS spec
- says find_topic (and a second call to create_topic) return a new
- proxy that must separately be deleted. */
- dds_entity_add_ref_locked (&tp->m_entity);
+ /* Simply return the same topic, though that is different to the spirit
+ of the DDS specification, which gives you a unique copy. Giving that
+ unique copy means there potentially many versions of exactly the same
+ topic around, and that two entities can be dealing with the same data
+ even though they have different topics objects (though with the same
+ name). That I find a confusing model.
+
+ As far as I can tell, the only benefit is the ability to set different
+ listeners on the various copies of the topic. And that seems to be a
+ really small benefit. */
ret = true;
}
dds_topic_unlock (tp);
@@ -259,12 +264,7 @@ static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t pa
ret = DDS_RETCODE_INCONSISTENT_POLICY;
else
{
- /* FIXME: calling addref is wrong because the Cyclone library has no
- knowledge of the reference and hence simply deleting the participant
- won't make the ref count drop to 0. On the other hand, the DDS spec
- says find_topic (and a second call to create_topic) return a new
- proxy that must separately be deleted. */
- dds_entity_add_ref_locked (&tp->m_entity);
+ /* See dds_find_topic_check_and_add_ref */
ret = DDS_RETCODE_OK;
}
dds_topic_unlock (tp);
@@ -429,7 +429,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
/* Create topic */
top = dds_alloc (sizeof (*top));
- hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, new_qos, listener, DDS_TOPIC_STATUS_MASK);
+ /* FIXME: setting "implicit" based on sertopic->ops is a hack */
+ hdl = dds_entity_init (&top->m_entity, &par->m_entity, DDS_KIND_TOPIC, (sertopic->ops == &ddsi_sertopic_ops_builtintopic), new_qos, listener, DDS_TOPIC_STATUS_MASK);
top->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &top->m_entity);
top->m_stopic = sertopic;
diff --git a/src/core/ddsc/src/dds_waitset.c b/src/core/ddsc/src/dds_waitset.c
index a0ae00c..64e15d6 100644
--- a/src/core/ddsc/src/dds_waitset.c
+++ b/src/core/ddsc/src/dds_waitset.c
@@ -166,7 +166,7 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
}
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
- dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
+ dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, false, NULL, NULL, 0);
ddsrt_mutex_init (&waitset->wait_lock);
ddsrt_cond_init (&waitset->wait_cond);
waitset->m_entity.m_iid = ddsi_iid_gen ();
@@ -176,13 +176,13 @@ dds_entity_t dds_create_waitset (dds_entity_t owner)
waitset->entities = NULL;
dds_entity_init_complete (&waitset->m_entity);
dds_entity_unlock (e);
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
- dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
+ dds_entity_unpin_and_drop_ref (&dds_global.m_entity);
return rc;
}
diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c
index 4f829ae..f0c0bc4 100644
--- a/src/core/ddsc/src/dds_writer.c
+++ b/src/core/ddsc/src/dds_writer.c
@@ -209,13 +209,12 @@ static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_writer_delete (dds_entity *e)
{
dds_writer * const wr = (dds_writer *) e;
- dds_return_t ret;
/* FIXME: not freeing WHC here because it is owned by the DDSI entity */
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_free (wr->m_xp);
thread_state_asleep (lookup_thread_state ());
- ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
- return ret;
+ dds_entity_drop_ref (&wr->m_topic->m_entity);
+ return DDS_RETCODE_OK;
}
static dds_return_t dds_writer_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
@@ -277,21 +276,27 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
{
dds_entity *p_or_p;
- if ((rc = dds_entity_pin (participant_or_publisher, &p_or_p)) != DDS_RETCODE_OK)
+ if ((rc = dds_entity_lock (participant_or_publisher, DDS_KIND_DONTCARE, &p_or_p)) != DDS_RETCODE_OK)
return rc;
- if (dds_entity_kind (p_or_p) == DDS_KIND_PARTICIPANT)
- publisher = dds_create_publisher (participant_or_publisher, qos, NULL);
- else
- publisher = participant_or_publisher;
- dds_entity_unpin (p_or_p);
+ switch (dds_entity_kind (p_or_p))
+ {
+ case DDS_KIND_PUBLISHER:
+ publisher = participant_or_publisher;
+ pub = (dds_publisher *) p_or_p;
+ break;
+ case DDS_KIND_PARTICIPANT:
+ publisher = dds__create_publisher_l ((dds_participant *) p_or_p, true, qos, NULL);
+ dds_entity_unlock (p_or_p);
+ if ((rc = dds_publisher_lock (publisher, &pub)) < 0)
+ return rc;
+ break;
+ default:
+ dds_entity_unlock (p_or_p);
+ return DDS_RETCODE_ILLEGAL_OPERATION;
+ }
}
- if ((rc = dds_publisher_lock (publisher, &pub)) != DDS_RETCODE_OK)
- return rc;
-
ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.data_conn_uc;
- if (publisher != participant_or_publisher)
- pub->m_entity.m_flags |= DDS_ENTITY_IMPLICIT;
if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
goto err_tp_lock;
@@ -322,7 +327,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
/* Create writer */
wr = dds_alloc (sizeof (*wr));
- writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, wqos, listener, DDS_WRITER_STATUS_MASK);
+ writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK);
wr->m_topic = tp;
dds_entity_add_ref_locked (&tp->m_entity);
diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c
index 3c9acb0..6f5789c 100644
--- a/src/core/ddsc/tests/config.c
+++ b/src/core/ddsc/tests/config.c
@@ -25,96 +25,88 @@
#define URI_VARIABLE DDS_PROJECT_NAME_NOSPACE_CAPS"_URI"
#define MAX_PARTICIPANTS_VARIABLE "MAX_PARTICIPANTS"
-static void config__check_env(
- const char * env_variable,
- const char * expected_value)
+static void config__check_env (const char *env_variable, const char *expected_value)
{
- char * env_uri = NULL;
- ddsrt_getenv(env_variable, &env_uri);
-#if 0
- const char * const env_not_set = "Environment variable '%s' isn't set. This needs to be set to '%s' for this test to run.";
- const char * const env_not_as_expected = "Environment variable '%s' has an unexpected value: '%s' (expected: '%s')";
-#endif
-
+ char *env_uri = NULL;
+ ddsrt_getenv (env_variable, &env_uri);
#ifdef FORCE_ENV
+ {
+ bool env_ok;
+
+ if (env_uri == NULL)
+ env_ok = false;
+ else if (strncmp (env_uri, expected_value, strlen (expected_value)) != 0)
+ env_ok = false;
+ else
+ env_ok = true;
+
+ if (!env_ok)
{
- bool env_ok;
-
- if ( env_uri == NULL ) {
- env_ok = false;
- } else if ( strncmp(env_uri, expected_value, strlen(expected_value)) != 0 ) {
- env_ok = false;
- } else {
- env_ok = true;
- }
-
- if ( !env_ok ) {
- dds_return_t r;
-
- r = ddsrt_setenv(env_variable, expected_value);
- CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK);
- }
+ dds_return_t r = ddsrt_setenv (env_variable, expected_value);
+ CU_ASSERT_EQUAL_FATAL (r, DDS_RETCODE_OK);
}
+ }
#else
- CU_ASSERT_PTR_NOT_NULL_FATAL(env_uri);
- CU_ASSERT_STRING_EQUAL_FATAL(env_uri, expected_value);
+ CU_ASSERT_PTR_NOT_NULL_FATAL (env_uri);
+ CU_ASSERT_STRING_EQUAL_FATAL (env_uri, expected_value);
#endif /* FORCE_ENV */
-
}
-CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
-
- dds_entity_t participant;
-
- config__check_env(URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
- config__check_env(MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
-
- participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
-
- CU_ASSERT_FATAL(participant> 0);
-
- dds_delete(participant);
+CU_Test (ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini)
+{
+ dds_entity_t participant;
+ config__check_env (URI_VARIABLE, CONFIG_ENV_SIMPLE_UDP);
+ config__check_env (MAX_PARTICIPANTS_VARIABLE, CONFIG_ENV_MAX_PARTICIPANTS);
+ participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
+ CU_ASSERT_FATAL (participant> 0);
+ dds_delete (participant);
}
-CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
+CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini)
+{
+ dds_entity_t domain;
+ domain = dds_create_domain (1,
+ "<"DDS_PROJECT_NAME">any"
+ "2"
+ ""DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL (domain > 0);
- CU_ASSERT_FATAL(dds_create_domain(1,
- "<"DDS_PROJECT_NAME">any"
- "2"
- ""DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
+ dds_entity_t participant_1 = dds_create_participant (1, NULL, NULL);
+ CU_ASSERT_FATAL(participant_1 > 0);
- dds_entity_t participant_1;
- dds_entity_t participant_2;
- dds_entity_t participant_3;
+ dds_entity_t participant_2 = dds_create_participant (1, NULL, NULL);
+ CU_ASSERT_FATAL(participant_2 > 0);
- participant_1 = dds_create_participant(1, NULL, NULL);
+ dds_entity_t participant_3 = dds_create_participant (1, NULL, NULL);
+ CU_ASSERT(participant_3 < 0);
- CU_ASSERT_FATAL(participant_1 > 0);
-
- participant_2 = dds_create_participant(1, NULL, NULL);
-
- CU_ASSERT_FATAL(participant_2 > 0);
-
- participant_3 = dds_create_participant(1, NULL, NULL);
-
- CU_ASSERT(participant_3 <= 0);
-
- dds_delete(participant_3);
- dds_delete(participant_2);
- dds_delete(participant_1);
+ dds_delete (domain);
}
-CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
+CU_Test (ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini)
+{
+ dds_entity_t dom;
- CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
- CU_ASSERT_FATAL(dds_create_domain(1, "any"
- "2"
- ""DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
- CU_ASSERT_FATAL(dds_create_domain(2,
- "<"DDS_PROJECT_NAME">any"
- "2"
- ""DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
- CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
+ dom = dds_create_domain (1, NULL);
+ CU_ASSERT_FATAL (dom == DDS_RETCODE_BAD_PARAMETER);
+
+ dom = dds_create_domain (1, "any"
+ "2"
+ ""DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL (dom == DDS_RETCODE_BAD_PARAMETER);
+
+ dom = dds_create_domain (2,
+ "<"DDS_PROJECT_NAME">any"
+ "2"
+ ""DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL (dom > 0);
+
+ /* 2nd attempt at creating the same domain should fail */
+ CU_ASSERT_FATAL (dds_create_domain (2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
+
+ dds_delete (dom);
}
diff --git a/src/core/ddsc/tests/entity_hierarchy.c b/src/core/ddsc/tests/entity_hierarchy.c
index 7983011..04f7f96 100644
--- a/src/core/ddsc/tests/entity_hierarchy.c
+++ b/src/core/ddsc/tests/entity_hierarchy.c
@@ -192,6 +192,10 @@ CU_Test(ddsc_entity_delete, recursive_with_deleted_topic)
ret = dds_delete(g_topic);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
+ /* Second call to delete a topic must fail */
+ ret = dds_delete(g_topic);
+ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_ALREADY_DELETED);
+
/* Third, deleting the participant should delete all children of which
* the writer with the last topic reference is one. */
ret = dds_delete(g_participant);
From 40973d8e29e9d6db2f9a3dc49464df345ad52993 Mon Sep 17 00:00:00 2001
From: Martin Bremmer
Date: Thu, 31 Oct 2019 16:43:34 +0100
Subject: [PATCH 22/55] Update function headers and added dds_create_domain()
tests.
Signed-off-by: Martin Bremmer
---
src/core/ddsc/include/dds/dds.h | 65 +++++++----
src/core/ddsc/src/dds_domain.c | 5 +-
src/core/ddsc/tests/config.c | 27 -----
src/core/ddsc/tests/domain.c | 154 +++++++++++++++++++++++++
src/core/ddsc/tests/entity_hierarchy.c | 64 ++++++++++
5 files changed, 264 insertions(+), 51 deletions(-)
diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h
index a6f7f73..a2bdb5c 100644
--- a/src/core/ddsc/include/dds/dds.h
+++ b/src/core/ddsc/include/dds/dds.h
@@ -747,9 +747,35 @@ dds_create_participant(
* @brief Creates a domain with a given configuration
*
* To explicitly create a domain based on a configuration passed as a string.
- * Normally, the domain is created implicitly on the first call to
- * dds_create_particiant based on the configuration specified throught
- * the environment. This function allows to by-pass this behaviour.
+ *
+ * It will not be created if a domain with the given domain id already exists.
+ * This could have been created implicitly by a dds_create_participant().
+ *
+ * Please be aware that the given domain_id always takes precedence over the
+ * configuration.
+ *
+ * | domain_id | domain id in config | result
+ * +-----------+---------------------+----------
+ * | n | any (or absent) | n, config is used
+ * | n | m == n | n, config is used
+ * | n | m != n | n, config is ignored: default
+ *
+ * Config models:
+ * 1:
+ * ...
+ *
+ *
+ * where ... is all that can today be set in children of CycloneDDS
+ * with the exception of the id
+ * 2:
+ * X
+ * ...
+ *
+ * legacy form, domain id must be the first element in the file with
+ * a value (if nothing has been set previously, it a warning is good
+ * enough)
+ *
+ * Using NULL or "" as config will create a domain with default settings.
*
*
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
@@ -759,7 +785,7 @@ dds_create_participant(
*
* @retval DDS_RETCODE_BAD_PARAMETER
* Illegal value for domain id or the configfile parameter is NULL.
- * @retval DDS_PRECONDITION_NOT_MET
+ * @retval DDS_RETCODE_PRECONDITION_NOT_MET
* The domain already existed and cannot be created again.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
@@ -774,15 +800,10 @@ dds_create_domain(const dds_domainid_t domain, const char *config);
* For instance, it will return the Participant that was used when
* creating a Publisher (when that Publisher was provided here).
*
- * When a reader or a writer are created with a partition, then a
- * subscriber or publisher respectively are created implicitly. These
- * implicit subscribers or publishers will be deleted automatically
- * when the reader or writer is deleted. However, when this function
- * returns such an implicit entity, it is from there on out considered
- * 'explicit'. This means that it isn't deleted automatically anymore.
- * The application should explicitly call dds_delete on those entities
- * now (or delete the parent participant which will delete all entities
- * within its hierarchy).
+ * When a reader or a writer are created with a participant, then a
+ * subscriber or publisher are created implicitly.
+ * This function will return the implicit parent and not the used
+ * participant.
*
* @param[in] entity Entity from which to get its parent.
*
@@ -849,15 +870,10 @@ dds_get_participant(dds_entity_t entity);
* When supplying NULL as list and 0 as size, you can use this to acquire
* the number of children without having to pre-allocate a list.
*
- * When a reader or a writer are created with a partition, then a
- * subscriber or publisher respectively are created implicitly. These
- * implicit subscribers or publishers will be deleted automatically
- * when the reader or writer is deleted. However, when this function
- * returns such an implicit entity, it is from there on out considered
- * 'explicit'. This means that it isn't deleted automatically anymore.
- * The application should explicitly call dds_delete on those entities
- * now (or delete the parent participant which will delete all entities
- * within its hierarchy).
+ * When a reader or a writer are created with a participant, then a
+ * subscriber or publisher are created implicitly.
+ * When used on the participant, this function will return the implicit
+ * subscriber and/or publisher and not the related reader/writer.
*
* @param[in] entity Entity from which to get its children.
* @param[out] children Pre-allocated array to contain the found children.
@@ -866,7 +882,7 @@ dds_get_participant(dds_entity_t entity);
* @returns Number of children or an error code.
*
* @retval >=0
- * Number of childer found children (can be larger than 'size').
+ * Number of found children (can be larger than 'size').
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
* @retval DDS_RETCODE_BAD_PARAMETER
@@ -1197,6 +1213,7 @@ dds_wait_for_acks(dds_entity_t publisher_or_writer, dds_duration_t timeout);
/**
* @brief Creates a new instance of a DDS reader.
*
+ * When a participant is used to create a reader, an implicit subscriber is created.
* This implicit subscriber will be deleted automatically when the created reader
* is deleted.
*
@@ -1223,6 +1240,7 @@ dds_create_reader(
/**
* @brief Creates a new instance of a DDS reader with a custom history cache.
*
+ * When a participant is used to create a reader, an implicit subscriber is created.
* This implicit subscriber will be deleted automatically when the created reader
* is deleted.
*
@@ -1270,6 +1288,7 @@ dds_reader_wait_for_historical_data(
/**
* @brief Creates a new instance of a DDS writer.
*
+ * When a participant is used to create a writer, an implicit publisher is created.
* This implicit publisher will be deleted automatically when the created writer
* is deleted.
*
diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c
index 78028af..686ffce 100644
--- a/src/core/ddsc/src/dds_domain.c
+++ b/src/core/ddsc/src/dds_domain.c
@@ -270,9 +270,12 @@ dds_entity_t dds_create_domain (const dds_domainid_t domain, const char *config)
dds_domain *dom;
dds_entity_t ret;
- if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
+ if (domain > 230)
return DDS_RETCODE_BAD_PARAMETER;
+ if (config == NULL)
+ config = "";
+
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
return ret;
diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c
index 6f5789c..82eda1b 100644
--- a/src/core/ddsc/tests/config.c
+++ b/src/core/ddsc/tests/config.c
@@ -83,30 +83,3 @@ CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini)
dds_delete (domain);
}
-CU_Test (ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini)
-{
- dds_entity_t dom;
-
- dom = dds_create_domain (1, NULL);
- CU_ASSERT_FATAL (dom == DDS_RETCODE_BAD_PARAMETER);
-
- dom = dds_create_domain (1, "any"
- "2"
- ""DDS_PROJECT_NAME">");
- CU_ASSERT_FATAL (dom == DDS_RETCODE_BAD_PARAMETER);
-
- dom = dds_create_domain (2,
- "<"DDS_PROJECT_NAME">any"
- "2"
- ""DDS_PROJECT_NAME">");
- CU_ASSERT_FATAL (dom > 0);
-
- /* 2nd attempt at creating the same domain should fail */
- CU_ASSERT_FATAL (dds_create_domain (2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
-
- dds_delete (dom);
-}
diff --git a/src/core/ddsc/tests/domain.c b/src/core/ddsc/tests/domain.c
index ea4f4cf..4f10beb 100644
--- a/src/core/ddsc/tests/domain.c
+++ b/src/core/ddsc/tests/domain.c
@@ -140,3 +140,157 @@ CU_Test(ddsc_domain, delete_cyclonedds)
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
+
+CU_Test(ddsc_domain_create, valid)
+{
+ dds_return_t ret;
+ dds_domainid_t did;
+ dds_entity_t domain;
+
+ domain = dds_create_domain(1, "<"DDS_PROJECT_NAME">1"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain > 0);
+
+ ret = dds_get_domainid (domain, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 1);
+
+ ret = dds_delete(domain);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ ret = dds_delete(domain);
+ CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
+}
+
+CU_Test(ddsc_domain_create, mismatch)
+{
+ dds_return_t ret;
+ dds_domainid_t did;
+ dds_entity_t domain;
+
+ /* The config should have been ignored. */
+ domain = dds_create_domain(2, "<"DDS_PROJECT_NAME">3"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain > 0);
+
+ ret = dds_get_domainid (domain, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 2);
+
+ ret = dds_delete(domain);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+}
+
+CU_Test(ddsc_domain_create, empty)
+{
+ dds_return_t ret;
+ dds_domainid_t did;
+ dds_entity_t domain;
+
+ /* This should create a domain with default settings. */
+ domain = dds_create_domain(3, "");
+ CU_ASSERT_FATAL(domain > 0);
+
+ ret = dds_get_domainid (domain, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 3);
+
+ ret = dds_delete(domain);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+}
+
+CU_Test(ddsc_domain_create, null)
+{
+ dds_return_t ret;
+ dds_domainid_t did;
+ dds_entity_t domain;
+
+ /* This should start create a domain with default settings. */
+ domain = dds_create_domain(5, NULL);
+ CU_ASSERT_FATAL(domain > 0);
+
+ ret = dds_get_domainid (domain, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 5);
+
+ ret = dds_delete(domain);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+}
+
+CU_Test(ddsc_domain_create, after_domain)
+{
+ dds_entity_t domain1;
+ dds_entity_t domain2;
+
+ domain1 = dds_create_domain(4, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain1 > 0);
+
+ domain2 = dds_create_domain(4, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain2 == DDS_RETCODE_PRECONDITION_NOT_MET);
+
+ dds_delete(domain1);
+}
+
+CU_Test(ddsc_domain_create, after_participant)
+{
+ dds_entity_t domain;
+ dds_entity_t participant;
+
+ participant = dds_create_participant (5, NULL, NULL);
+ CU_ASSERT_FATAL(participant > 0);
+
+ domain = dds_create_domain(5, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain == DDS_RETCODE_PRECONDITION_NOT_MET);
+
+ dds_delete(participant);
+}
+
+CU_Test(ddsc_domain_create, diff)
+{
+ dds_return_t ret;
+ dds_domainid_t did;
+ dds_entity_t domain1;
+ dds_entity_t domain2;
+
+ domain1 = dds_create_domain(1, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain1 > 0);
+
+ domain2 = dds_create_domain(2, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain2 > 0);
+
+ ret = dds_get_domainid (domain1, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 1);
+
+ ret = dds_get_domainid (domain2, &did);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(did == 2);
+
+ ret = dds_delete(domain1);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+ ret = dds_delete(domain2);
+ CU_ASSERT_FATAL(ret == DDS_RETCODE_OK);
+
+ ret = dds_delete(domain1);
+ CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
+ ret = dds_delete(domain2);
+ CU_ASSERT_FATAL(ret != DDS_RETCODE_OK);
+}
+
+CU_Test(ddsc_domain_create, domain_default)
+{
+ dds_entity_t domain;
+ domain = dds_create_domain(DDS_DOMAIN_DEFAULT, "<"DDS_PROJECT_NAME">any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain == DDS_RETCODE_BAD_PARAMETER);
+}
+
+CU_Test(ddsc_domain_create, invalid_xml)
+{
+ dds_entity_t domain;
+ domain = dds_create_domain(1, "any"DDS_PROJECT_NAME">");
+ CU_ASSERT_FATAL(domain == DDS_RETCODE_BAD_PARAMETER);
+}
diff --git a/src/core/ddsc/tests/entity_hierarchy.c b/src/core/ddsc/tests/entity_hierarchy.c
index 04f7f96..44d5917 100644
--- a/src/core/ddsc/tests/entity_hierarchy.c
+++ b/src/core/ddsc/tests/entity_hierarchy.c
@@ -992,6 +992,70 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
}
/*************************************************************************************************/
+/*************************************************************************************************/
+CU_Test(ddsc_entity_implicit, delete_publisher)
+{
+ dds_entity_t participant;
+ dds_entity_t writer;
+ dds_entity_t parent;
+ dds_entity_t topic;
+ dds_return_t ret;
+ char name[100];
+
+ 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);
+ CU_ASSERT_FATAL(topic > 0);
+
+ writer = dds_create_writer(participant, topic, NULL, NULL);
+ CU_ASSERT_FATAL(writer > 0);
+
+ parent = dds_get_parent(writer);
+ CU_ASSERT_FATAL(parent > 0);
+
+ ret = dds_delete(parent);
+ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
+
+ ret = dds_delete(writer);
+ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
+
+ dds_delete(participant);
+}
+/*************************************************************************************************/
+
+/*************************************************************************************************/
+CU_Test(ddsc_entity_implicit, delete_subscriber)
+{
+ dds_entity_t participant;
+ dds_entity_t reader;
+ dds_entity_t parent;
+ dds_entity_t topic;
+ dds_return_t ret;
+ char name[100];
+
+ 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);
+ CU_ASSERT_FATAL(topic > 0);
+
+ reader = dds_create_reader(participant, topic, NULL, NULL);
+ CU_ASSERT_FATAL(reader > 0);
+
+ parent = dds_get_parent(reader);
+ CU_ASSERT_FATAL(parent > 0);
+
+ ret = dds_delete(parent);
+ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
+
+ ret = dds_delete(reader);
+ CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
+
+ dds_delete(participant);
+}
+/*************************************************************************************************/
+
/*************************************************************************************************/
#endif
From fc8b8fef3a72cf240dcf7c519789a853881779e3 Mon Sep 17 00:00:00 2001
From: Martin Bremmer
Date: Mon, 4 Nov 2019 16:24:47 +0100
Subject: [PATCH 23/55] Small entity deletion wip refactoring.
Signed-off-by: Martin Bremmer
---
src/core/ddsc/src/dds_domain.c | 64 +++++++++++------------------
src/core/ddsc/src/dds_entity.c | 72 ++++++++++++++++-----------------
src/core/ddsc/src/dds_handles.c | 53 +++++++++++++++---------
3 files changed, 93 insertions(+), 96 deletions(-)
diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c
index 686ffce..cc66198 100644
--- a/src/core/ddsc/src/dds_domain.c
+++ b/src/core/ddsc/src/dds_domain.c
@@ -48,7 +48,7 @@ static int dds_domain_compare (const void *va, const void *vb)
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
-static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
+static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config, bool implicit)
{
dds_entity_t domh;
uint32_t len;
@@ -193,27 +193,37 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool implicit, const char *config)
{
struct dds_domain *dom;
- dds_entity_t domh;
+ dds_entity_t domh = DDS_RETCODE_ERROR;
/* FIXME: should perhaps lock parent object just like everywhere */
ddsrt_mutex_lock (&dds_global.m_mutex);
retry:
if (id != DDS_DOMAIN_DEFAULT)
+ dom = dds_domain_find_locked (id);
+ else
+ dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains);
+
+ if (dom)
{
- if ((dom = dds_domain_find_locked (id)) == NULL)
- domh = DDS_RETCODE_NOT_FOUND;
+ if (!implicit)
+ domh = DDS_RETCODE_PRECONDITION_NOT_MET;
else
+ {
+ ddsrt_mutex_lock (&dom->m_entity.m_mutex);
+ if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
+ {
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
+ ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
+ goto retry;
+ }
+ dds_entity_add_ref_locked (&dom->m_entity);
+ dds_handle_repin (&dom->m_entity.m_hdllink);
domh = dom->m_entity.m_hdllink.hdl;
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
+ *domain_out = dom;
+ }
}
else
- {
- if ((dom = ddsrt_avl_find_min (&dds_domaintree_def, &dds_global.m_domains)) != NULL)
- domh = dom->m_entity.m_hdllink.hdl;
- else
- domh = DDS_RETCODE_NOT_FOUND;
- }
-
- if (domh == DDS_RETCODE_NOT_FOUND)
{
dom = dds_alloc (sizeof (*dom));
if ((domh = dds_domain_init (dom, id, config, implicit)) < 0)
@@ -228,35 +238,7 @@ dds_entity_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t
dds_entity_add_ref_locked (&dom->m_entity);
dds_handle_repin (&dom->m_entity.m_hdllink);
}
- ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
- *domain_out = dom;
- }
- }
- else if (domh <= DDS_RETCODE_OK)
- {
- assert (0);
- domh = DDS_RETCODE_ERROR;
- }
- else if (!implicit)
- {
- domh = DDS_RETCODE_PRECONDITION_NOT_MET;
- }
- else
- {
- ddsrt_mutex_lock (&dom->m_entity.m_mutex);
- if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
- {
- ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
- ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
- goto retry;
- }
- else
- {
- if (implicit)
- {
- dds_entity_add_ref_locked (&dom->m_entity);
- dds_handle_repin (&dom->m_entity.m_hdllink);
- }
+ domh = dom->m_entity.m_hdllink.hdl;
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
*domain_out = dom;
}
diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c
index 4288f4b..e1166fb 100644
--- a/src/core/ddsc/src/dds_entity.c
+++ b/src/core/ddsc/src/dds_entity.c
@@ -92,10 +92,7 @@ void dds_entity_drop_ref (dds_entity *e)
{
if (dds_handle_drop_ref (&e->m_hdllink))
{
- /* increment pin count unconditionally to satisfy the "pinned" requirement */
- dds_handle_repin (&e->m_hdllink);
- ddsrt_mutex_lock (&e->m_mutex);
- dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
+ dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
assert (ret == DDS_RETCODE_OK);
(void) ret;
}
@@ -105,10 +102,7 @@ void dds_entity_unpin_and_drop_ref (dds_entity *e)
{
if (dds_handle_unpin_and_drop_ref (&e->m_hdllink))
{
- /* increment pin count unconditionally to satisfy the "pinned" requirement */
- dds_handle_repin (&e->m_hdllink);
- ddsrt_mutex_lock (&e->m_mutex);
- dds_return_t ret = really_delete_pinned_closed_locked (e, DIS_EXPLICIT);
+ dds_return_t ret = dds_delete_impl(e->m_hdllink.hdl, DIS_EXPLICIT);
assert (ret == DDS_RETCODE_OK);
(void) ret;
}
@@ -223,17 +217,45 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child)
dds_entity_add_ref_locked (parent);
}
-static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
+static dds_entity *get_first_child (ddsrt_avl_tree_t *remaining_children, bool ignore_topics)
{
ddsrt_avl_iter_t it;
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, remaining_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
{
- if (dds_entity_kind (e) != DDS_KIND_TOPIC)
+ if ((!ignore_topics) || (dds_entity_kind(e) != DDS_KIND_TOPIC))
return e;
}
return NULL;
}
+static void delete_children(struct dds_entity *parent, bool ignore_topics)
+{
+ dds_entity *child;
+ dds_return_t ret;
+ ddsrt_mutex_lock (&parent->m_mutex);
+ while ((child = get_first_child(&parent->m_children, ignore_topics)) != NULL)
+ {
+ dds_entity_t child_handle = child->m_hdllink.hdl;
+
+ /* The child will remove itself from the parent->m_children list. */
+ ddsrt_mutex_unlock (&parent->m_mutex);
+ ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
+ assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
+ ddsrt_mutex_lock (&parent->m_mutex);
+
+ /* The dds_delete can fail if the child is being deleted in parallel,
+ * in which case: wait when its not deleted yet.
+ * The child will trigger the condition after it removed itself from
+ * the childrens list. */
+ if ((ret == DDS_RETCODE_BAD_PARAMETER) &&
+ (get_first_child(&parent->m_children, ignore_topics) == child))
+ {
+ ddsrt_cond_wait (&parent->m_cond, &parent->m_mutex);
+ }
+ }
+ ddsrt_mutex_unlock (&parent->m_mutex);
+}
+
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
#if TRACE_DELETE
static const char *entity_kindstr (dds_entity_kind_t kind)
@@ -312,7 +334,6 @@ dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delst
static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, enum delete_impl_state delstate)
{
- dds_entity *child;
dds_return_t ret;
/* No threads pinning it anymore, no need to worry about other threads deleting
@@ -369,32 +390,8 @@ static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, en
*
* To circumvent the problem. We ignore topics in the first loop.
*/
- ddsrt_mutex_lock (&e->m_mutex);
- while ((child = next_non_topic_child (&e->m_children)) != NULL)
- {
- /* FIXME: dds_delete can fail if the child is being deleted in parallel, in which case: wait */
- dds_entity_t child_handle = child->m_hdllink.hdl;
- ddsrt_mutex_unlock (&e->m_mutex);
- ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
- assert (ret == DDS_RETCODE_OK || ret == DDS_RETCODE_BAD_PARAMETER);
- (void) ret;
- ddsrt_mutex_lock (&e->m_mutex);
- if (ret == DDS_RETCODE_BAD_PARAMETER && child == next_non_topic_child (&e->m_children))
- {
- ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
- }
- }
- while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL)
- {
- assert (dds_entity_kind (child) == DDS_KIND_TOPIC);
- dds_entity_t child_handle = child->m_hdllink.hdl;
- ddsrt_mutex_unlock (&e->m_mutex);
- ret = dds_delete_impl (child_handle, DIS_FROM_PARENT);
- assert (ret == DDS_RETCODE_OK);
- (void) ret;
- ddsrt_mutex_lock (&e->m_mutex);
- }
- ddsrt_mutex_unlock (&e->m_mutex);
+ delete_children(e, true /* ignore topics */);
+ delete_children(e, false /* delete topics */);
/* The dds_handle_delete will wait until the last active claim on that handle is
released. It is possible that this last release will be done by a thread that was
@@ -416,6 +413,7 @@ static dds_return_t really_delete_pinned_closed_locked (struct dds_entity *e, en
ddsrt_avl_delete (&dds_entity_children_td, &p->m_children, e);
if (dds_handle_drop_childref_and_pin (&p->m_hdllink, delstate != DIS_FROM_PARENT))
{
+ dds_handle_close(&p->m_hdllink);
assert (dds_handle_is_closed (&p->m_hdllink));
assert (dds_handle_is_not_refd (&p->m_hdllink));
assert (ddsrt_avl_is_empty (&p->m_children));
diff --git a/src/core/ddsc/src/dds_handles.c b/src/core/ddsc/src/dds_handles.c
index 4e22e4e..a2bbb0a 100644
--- a/src/core/ddsc/src/dds_handles.c
+++ b/src/core/ddsc/src/dds_handles.c
@@ -294,8 +294,16 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
outstanding references. This implies that there are no children, because then the
entire hierarchy would simply have been deleted. */
assert (!(cf & HDL_FLAG_ALLOW_CHILDREN));
- rc = DDS_RETCODE_ALREADY_DELETED;
- break;
+ if (cf & HDL_REFCOUNT_MASK)
+ {
+ rc = DDS_RETCODE_ALREADY_DELETED;
+ break;
+ }
+ else
+ {
+ /* Refcount reached zero. Pin to allow deletion. */
+ cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
+ }
}
else if (explicit)
{
@@ -305,21 +313,24 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
/* Entity is implicit, so handle doesn't hold a reference */
cf1 = (cf + 1u) | HDL_FLAG_CLOSING;
}
- else if (cf & HDL_FLAG_ALLOW_CHILDREN)
- {
- /* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
- assert ((cf & HDL_REFCOUNT_MASK) > 0);
- cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
- }
else
{
- /* Entity is explicit, so handle held a reference, refc counts non-children, refc > 1 means drop ref and error (so don't pin) */
assert ((cf & HDL_REFCOUNT_MASK) > 0);
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
+ {
+ /* Last reference is closing. Pin entity and indicate that it is closing. */
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ }
+ else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
+ {
+ /* The refcnt does not contain children.
+ * Indicate that the closing of the entity is deferred. */
+ cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
+ }
else
{
- cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
+ /* Entity is explicit, so handle held a reference, refc only counts children as so is not our concern */
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
}
}
}
@@ -328,11 +339,21 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
/* Implicit call to dds_delete (child invoking delete on its parent) */
if (cf & HDL_FLAG_IMPLICIT)
{
+ assert ((cf & HDL_REFCOUNT_MASK) > 0);
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
+ {
+ /* Last reference is closing. Pin entity and indicate that it is closing. */
cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ }
+ else if (!(cf & HDL_FLAG_ALLOW_CHILDREN))
+ {
+ /* The refcnt does not contain children.
+ * Indicate that the closing of the entity is deferred. */
+ cf1 = (cf - HDL_REFCOUNT_UNIT) | HDL_FLAG_DELETE_DEFERRED;
+ }
else
{
- assert ((cf & HDL_REFCOUNT_MASK) > 0);
+ /* Just reduce the children refcount by one. */
cf1 = (cf - HDL_REFCOUNT_UNIT);
}
}
@@ -373,7 +394,7 @@ bool dds_handle_drop_childref_and_pin (struct dds_handle_link *link, bool may_de
/* Implicit parent: delete if last ref */
if ((cf & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && may_delete_parent)
{
- cf1 = (cf - HDL_REFCOUNT_UNIT + 1u) | HDL_FLAG_CLOSING;
+ cf1 = (cf - HDL_REFCOUNT_UNIT + 1u);
del_parent = true;
}
else
@@ -436,8 +457,6 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
old = ddsrt_atomic_ld32 (&link->cnt_flags);
assert ((old & HDL_REFCOUNT_MASK) > 0);
new = old - HDL_REFCOUNT_UNIT;
- if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT)
- new |= HDL_FLAG_CLOSING;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
ddsrt_mutex_lock (&handles.lock);
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
@@ -445,7 +464,7 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
ddsrt_cond_broadcast (&handles.cond);
}
ddsrt_mutex_unlock (&handles.lock);
- return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
+ return ((new & HDL_REFCOUNT_MASK) == 0);
}
bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
@@ -456,8 +475,6 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
assert ((old & HDL_REFCOUNT_MASK) > 0);
assert ((old & HDL_PINCOUNT_MASK) > 0);
new = old - HDL_REFCOUNT_UNIT - 1u;
- if ((old & HDL_REFCOUNT_MASK) == HDL_REFCOUNT_UNIT && (old & HDL_FLAG_IMPLICIT))
- new |= HDL_FLAG_CLOSING;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
ddsrt_mutex_lock (&handles.lock);
if ((new & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
@@ -465,7 +482,7 @@ bool dds_handle_unpin_and_drop_ref (struct dds_handle_link *link)
ddsrt_cond_broadcast (&handles.cond);
}
ddsrt_mutex_unlock (&handles.lock);
- return (new & (HDL_FLAG_CLOSING | HDL_REFCOUNT_MASK)) == (HDL_FLAG_CLOSING | 0);
+ return ((new & HDL_REFCOUNT_MASK) == 0);
}
bool dds_handle_close (struct dds_handle_link *link)
From b6b0c2535585dafd794478e0778ed15c71a7afbb Mon Sep 17 00:00:00 2001
From: Martin Bremmer
Date: Wed, 6 Nov 2019 11:05:33 +0100
Subject: [PATCH 24/55] Add domain creation torture test.
Signed-off-by: Martin Bremmer
Disabled domain_torture_imlicit test.
Signed-off-by: Martin Bremmer
---
src/core/ddsc/src/dds_domain.c | 2 +-
src/core/ddsc/src/dds_participant.c | 4 +-
src/core/ddsc/tests/CMakeLists.txt | 1 +
src/core/ddsc/tests/domain.c | 7 --
src/core/ddsc/tests/domain_torture.c | 118 +++++++++++++++++++++++++++
5 files changed, 122 insertions(+), 10 deletions(-)
create mode 100644 src/core/ddsc/tests/domain_torture.c
diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c
index cc66198..0b5a919 100644
--- a/src/core/ddsc/src/dds_domain.c
+++ b/src/core/ddsc/src/dds_domain.c
@@ -252,7 +252,7 @@ dds_entity_t dds_create_domain (const dds_domainid_t domain, const char *config)
dds_domain *dom;
dds_entity_t ret;
- if (domain > 230)
+ if (domain == DDS_DOMAIN_DEFAULT)
return DDS_RETCODE_BAD_PARAMETER;
if (config == NULL)
diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c
index cafa6f9..31b5c82 100644
--- a/src/core/ddsc/src/dds_participant.c
+++ b/src/core/ddsc/src/dds_participant.c
@@ -126,9 +126,9 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
pp->m_builtin_subscriber = 0;
/* Add participant to extent */
- ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
+ ddsrt_mutex_lock (&dom->m_entity.m_mutex);
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
- ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
+ ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
dds_entity_init_complete (&pp->m_entity);
/* drop temporary extra ref to domain, dds_init */
diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt
index 6c977a0..af2ee77 100644
--- a/src/core/ddsc/tests/CMakeLists.txt
+++ b/src/core/ddsc/tests/CMakeLists.txt
@@ -21,6 +21,7 @@ set(ddsc_test_sources
"config.c"
"dispose.c"
"domain.c"
+ "domain_torture.c"
"entity_api.c"
"entity_hierarchy.c"
"entity_status.c"
diff --git a/src/core/ddsc/tests/domain.c b/src/core/ddsc/tests/domain.c
index 4f10beb..ab0a64b 100644
--- a/src/core/ddsc/tests/domain.c
+++ b/src/core/ddsc/tests/domain.c
@@ -287,10 +287,3 @@ CU_Test(ddsc_domain_create, invalid_xml)
domain = dds_create_domain(1, "any"DDS_PROJECT_NAME">");
- CU_ASSERT_FATAL(domain == DDS_RETCODE_BAD_PARAMETER);
-}
diff --git a/src/core/ddsc/tests/domain_torture.c b/src/core/ddsc/tests/domain_torture.c
new file mode 100644
index 0000000..d760cea
--- /dev/null
+++ b/src/core/ddsc/tests/domain_torture.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright(c) 2019 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
+
+#include "dds/dds.h"
+#include "CUnit/Theory.h"
+#include "RoundTrip.h"
+
+#include "dds/ddsrt/threads.h"
+#include "dds/ddsrt/atomics.h"
+#include "dds/ddsrt/time.h"
+
+
+#define N_THREADS (10)
+
+static const dds_duration_t TEST_DURATION = DDS_SECS(3);
+
+static ddsrt_atomic_uint32_t terminate;
+
+
+static uint32_t create_participants_thread (void *varg)
+{
+ (void) varg;
+ while (!ddsrt_atomic_ld32 (&terminate))
+ {
+ dds_entity_t par = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
+ if (par < 0)
+ {
+ fprintf (stderr, "dds_create_participant failed: %s\n", dds_strretcode (par));
+ ddsrt_atomic_st32 (&terminate, 1);
+ return 1;
+ }
+
+ dds_return_t ret = dds_delete(par);
+ if (ret != DDS_RETCODE_OK)
+ {
+ fprintf (stderr, "dds_delete failed: %s\n", dds_strretcode (ret));
+ ddsrt_atomic_st32 (&terminate, 1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void participant_creation_torture()
+{
+ dds_return_t rc;
+ ddsrt_thread_t tids[N_THREADS];
+ ddsrt_threadattr_t tattr;
+ ddsrt_threadattr_init (&tattr);
+
+ /* Start threads. */
+ for (size_t i = 0; i < sizeof(tids) / sizeof(*tids); i++)
+ {
+ rc = ddsrt_thread_create (&tids[i], "domain_torture_explicit", &tattr, create_participants_thread, 0);
+ CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
+ }
+
+ /* Let the threads do the torturing for a while. */
+ dds_sleepfor(TEST_DURATION);
+
+ /* Stop and check threads results. */
+ ddsrt_atomic_st32 (&terminate, 1);
+ for (size_t i = 0; i < sizeof (tids) / sizeof (tids[0]); i++)
+ {
+ uint32_t retval;
+ rc = ddsrt_thread_join (tids[i], &retval);
+ CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
+ CU_ASSERT (retval == 0);
+ }
+}
+
+
+/*
+ * There are some issues when completely init/deinit the
+ * library in a torturing way. We really just want to
+ * check the domain creation/deletion. So, disable this
+ * test for now.
+ */
+CU_Test (ddsc_domain, torture_implicit, .disabled=true)
+{
+ /* No explicit domain creation, just start creating and
+ * deleting participants (that'll create and delete the
+ * domain implicitly) in a torturing manner. */
+ participant_creation_torture();
+}
+
+
+CU_Test (ddsc_domain, torture_explicit)
+{
+ dds_return_t rc;
+ dds_entity_t domain;
+
+ /* Create domain explicitly. */
+ domain = dds_create_domain(1, "");
+ CU_ASSERT_FATAL (domain > 0);
+
+ /* Start creating and deleting participants on the
+ * explicit domain in a torturing manner. */
+ participant_creation_torture();
+
+ /* Delete domain. */
+ rc = dds_delete(domain);
+ CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
+ rc = dds_delete(domain);
+ CU_ASSERT_FATAL (rc != DDS_RETCODE_OK);
+}
From 9b7d93ec02bb91bb2c5e97a27f4ca9faa5f99a17 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 14 Nov 2019 21:54:33 +0100
Subject: [PATCH 25/55] Fix editing error in README config example
Signed-off-by: Erik Boasson
---
README.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 8a549c5..959743d 100644
--- a/README.md
+++ b/README.md
@@ -186,12 +186,11 @@ point to it. E.g. (on Linux):
$ cat cyclonedds.xml
-
-
+
auto
- auto
+ default
65500B
4000B
From 6ed01fc62a483c735d6a23577b9957ead2d9d0a6 Mon Sep 17 00:00:00 2001
From: Dan Rose
Date: Sat, 16 Nov 2019 13:28:53 -0600
Subject: [PATCH 26/55] Fix string literal under cpp compiler
PGUIDFMT creates invalid C++ code.
In file included from /opt/ros/master/src/ros2/rmw_cyclonedds/rmw_cyclonedds_cpp/src/serdata.cpp:23:
In file included from /opt/ros/master/install/include/dds/ddsi/q_radmin.h:17:
In file included from /opt/ros/master/install/include/dds/ddsi/ddsi_tran.h:19:
In file included from /opt/ros/master/install/include/dds/ddsi/q_protocol.h:19:
/opt/ros/master/install/include/dds/ddsi/q_rtps.h:30:21: error: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wreserved-user-defined-literal]
^
/opt/ros/master/install/include/dds/ddsi/q_rtps.h:30:31: error: invalid suffix on literal; C++11 requires a space between literal and identifier [-Wreserved-user-defined-literal]
Signed-off-by: Dan Rose
---
src/core/ddsi/include/dds/ddsi/q_rtps.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/ddsi/include/dds/ddsi/q_rtps.h b/src/core/ddsi/include/dds/ddsi/q_rtps.h
index dfe0d39..9359e5b 100644
--- a/src/core/ddsi/include/dds/ddsi/q_rtps.h
+++ b/src/core/ddsi/include/dds/ddsi/q_rtps.h
@@ -27,7 +27,7 @@ typedef int64_t seqno_t;
#define PGUIDPREFIX(gp) (gp).u[0], (gp).u[1], (gp).u[2]
#define PGUID(g) PGUIDPREFIX ((g).prefix), (g).entityid.u
-#define PGUIDFMT "%"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32
+#define PGUIDFMT "%" PRIx32 ":%" PRIx32 ":%" PRIx32 ":%" PRIx32
/* predefined entity ids; here viewed as an unsigned int, on the
network as four bytes corresponding to the integer in network byte
From fc0b402584f6f6caf6cbbdcb2d84b94311d998f6 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 15 Nov 2019 09:57:16 +0100
Subject: [PATCH 27/55] Delete some leftover type definitions
Signed-off-by: Erik Boasson
---
src/core/ddsi/include/dds/ddsi/q_config.h | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h
index def6e66..02b26c1 100644
--- a/src/core/ddsi/include/dds/ddsi/q_config.h
+++ b/src/core/ddsi/include/dds/ddsi/q_config.h
@@ -21,12 +21,6 @@
extern "C" {
#endif
-/* FIXME: should eventually move to abstraction layer */
-typedef enum q__schedPrioClass {
- Q__SCHED_PRIO_RELATIVE,
- Q__SCHED_PRIO_ABSOLUTE
-} q__schedPrioClass;
-
enum nn_standards_conformance {
NN_SC_PEDANTIC,
NN_SC_STRICT,
@@ -54,14 +48,6 @@ enum boolean_default {
BOOLDEF_TRUE
};
-enum durability_cdr
-{
- DUR_CDR_LE,
- DUR_CDR_BE,
- DUR_CDR_SERVER,
- DUR_CDR_CLIENT
-};
-
#define PARTICIPANT_INDEX_AUTO -1
#define PARTICIPANT_INDEX_NONE -2
From c603fdd4ed5f01d541ffa9d4c02f6d1c07f39fbd Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 15 Nov 2019 11:49:36 +0100
Subject: [PATCH 28/55] Fix trivial white space, compiler warnings
Signed-off-by: Erik Boasson
---
src/ddsrt/include/dds/ddsrt/bswap.h | 3 ++-
src/tools/pubsub/pubsub.c | 7 ++++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/ddsrt/include/dds/ddsrt/bswap.h b/src/ddsrt/include/dds/ddsrt/bswap.h
index 3e1ff56..953b1ac 100644
--- a/src/ddsrt/include/dds/ddsrt/bswap.h
+++ b/src/ddsrt/include/dds/ddsrt/bswap.h
@@ -84,4 +84,5 @@ inline int64_t ddsrt_bswap8 (int64_t x)
}
#endif
-#endif /* DDSRT_BSWAP_H */
\ No newline at end of file
+#endif /* DDSRT_BSWAP_H */
+
diff --git a/src/tools/pubsub/pubsub.c b/src/tools/pubsub/pubsub.c
index b810d24..434f564 100644
--- a/src/tools/pubsub/pubsub.c
+++ b/src/tools/pubsub/pubsub.c
@@ -292,7 +292,7 @@ static char *expand_env(const char *name, char op, const char *alt) {
else {
char *altx = expand_envvars(alt);
error_exit("%s: %s\n", name, altx);
- dds_free(altx);
+ //dds_free(altx);
return NULL;
}
case '+':
@@ -2103,6 +2103,7 @@ static int get_metadata(char **metadata, char **typename, char **keylist, const
return 1;
}
+#if 0
static dds_entity_t find_topic(dds_entity_t dpFindTopic, const char *name, const dds_duration_t *timeout) {
dds_entity_t tp;
(void)timeout;
@@ -2157,6 +2158,7 @@ static dds_entity_t find_topic(dds_entity_t dpFindTopic, const char *name, const
return tp;
}
+#endif
static void set_systemid_env(void) {
// TODO Determine encoding of dds_instance_handle_t, and see what sort of value can be extracted from it, if any
@@ -2678,7 +2680,9 @@ int main(int argc, char *argv[]) {
case OU: spec[i].tp = new_topic(spec[i].topicname, ts_OneULong, qos); break;
case ARB:
// TODO ARB type support
+#if 1
error_exit("Currently doesn't support ARB type\n");
+#else
if (spec[i].metadata == NULL) {
if (!(spec[i].tp = find_topic(dp, spec[i].topicname, &spec[i].findtopic_timeout)))
error_exit("topic %s not found\n", spec[i].topicname);
@@ -2691,6 +2695,7 @@ int main(int argc, char *argv[]) {
// dds_topic_descriptor_delete((dds_topic_descriptor_t*) ts);
}
// spec[i].rd.tgtp = spec[i].wr.tgtp = tgnew(spec[i].tp, printtype);
+#endif
break;
}
assert(spec[i].tp);
From 210fa7e78feb977f52b5543c1c807157d2cd4a6f Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 15 Nov 2019 11:51:13 +0100
Subject: [PATCH 29/55] Add keyless topics with small payloads to ddsperf
Signed-off-by: Erik Boasson
---
src/tools/ddsperf/ddsperf.c | 48 ++++++++++++++++++++---------
src/tools/ddsperf/ddsperf_types.idl | 14 +++++++++
2 files changed, 48 insertions(+), 14 deletions(-)
diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c
index d0eeb89..11ea1cf 100644
--- a/src/tools/ddsperf/ddsperf.c
+++ b/src/tools/ddsperf/ddsperf.c
@@ -53,7 +53,9 @@ enum topicsel {
KS, /* KeyedSeq type: seq#, key, sequence-of-octet */
K32, /* Keyed32 type: seq#, key, array-of-24-octet (sizeof = 32) */
K256, /* Keyed256 type: seq#, key, array-of-248-octet (sizeof = 256) */
- OU /* OneULong type: seq# */
+ OU, /* OneULong type: seq# */
+ UK16, /* Unkeyed16, type: seq#, array-of-12-octet (sizeof = 16) */
+ UK1024/* Unkeyed1024, type: seq#, array-of-1020-octet (sizeof = 1024) */
};
enum submode {
@@ -317,6 +319,8 @@ union data {
Keyed32 k32;
Keyed256 k256;
OneULong ou;
+ Unkeyed16 uk16;
+ Unkeyed1024 uk1024;
};
static void verrorx (int exitcode, const char *fmt, va_list ap)
@@ -529,6 +533,14 @@ static void *init_sample (union data *data, uint32_t seq)
case OU:
data->ou.seq = seq;
break;
+ case UK16:
+ data->uk16.seq = seq;
+ memset (data->uk16.baggage, 0xee, sizeof (data->uk16.baggage));
+ break;
+ case UK1024:
+ data->uk1024.seq = seq;
+ memset (data->uk1024.baggage, 0xee, sizeof (data->uk1024.baggage));
+ break;
}
return baggage;
}
@@ -791,10 +803,12 @@ static uint32_t topic_payload_size (enum topicsel tp, uint32_t bgsize)
uint32_t size = 0;
switch (tp)
{
- case KS: size = 12 + bgsize; break;
- case K32: size = 32; break;
- case K256: size = 256; break;
- case OU: size = 4; break;
+ case KS: size = 12 + bgsize; break;
+ case K32: size = 32; break;
+ case K256: size = 256; break;
+ case OU: size = 4; break;
+ case UK16: size = 16; break;
+ case UK1024: size = 1024; break;
}
return size;
}
@@ -814,13 +828,15 @@ static bool process_data (dds_entity_t rd, struct subthread_arg *arg)
uint32_t seq = 0, keyval = 0, size = 0;
switch (topicsel)
{
- case KS: {
- KeyedSeq *d = (KeyedSeq *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, d->baggage._length);
+ case KS: {
+ KeyedSeq *d = mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, d->baggage._length);
break;
}
- case K32: { Keyed32 *d = (Keyed32 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
- case K256: { Keyed256 *d = (Keyed256 *) mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
- case OU: { OneULong *d = (OneULong *) mseq[i]; keyval = 0; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
+ case K32: { Keyed32 *d = mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
+ case K256: { Keyed256 *d = mseq[i]; keyval = d->keyval; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
+ case OU: { OneULong *d = mseq[i]; keyval = 0; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
+ case UK16: { Unkeyed16 *d = mseq[i]; keyval = 0; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
+ case UK1024: { Unkeyed1024 *d = mseq[i]; keyval = 0; seq = d->seq; size = topic_payload_size (topicsel, 0); } break;
}
(void) check_eseq (&eseq_admin, seq, keyval, size, iseq[i].publication_handle);
if (iseq[i].source_timestamp & 1)
@@ -1883,6 +1899,8 @@ int main (int argc, char *argv[])
else if (strcmp (optarg, "K32") == 0) topicsel = K32;
else if (strcmp (optarg, "K256") == 0) topicsel = K256;
else if (strcmp (optarg, "OU") == 0) topicsel = OU;
+ else if (strcmp (optarg, "UK16") == 0) topicsel = UK16;
+ else if (strcmp (optarg, "UK1024") == 0) topicsel = UK1024;
else error3 ("%s: unknown topic\n", optarg);
break;
case 'M': maxwait = atof (optarg); if (maxwait <= 0) maxwait = HUGE_VAL; break;
@@ -1970,10 +1988,12 @@ int main (int argc, char *argv[])
const dds_topic_descriptor_t *tp_desc = NULL;
switch (topicsel)
{
- case KS: tp_suf = "KS"; tp_desc = &KeyedSeq_desc; break;
- case K32: tp_suf = "K32"; tp_desc = &Keyed32_desc; break;
- case K256: tp_suf = "K256"; tp_desc = &Keyed256_desc; break;
- case OU: tp_suf = "OU"; tp_desc = &OneULong_desc; break;
+ case KS: tp_suf = "KS"; tp_desc = &KeyedSeq_desc; break;
+ case K32: tp_suf = "K32"; tp_desc = &Keyed32_desc; break;
+ case K256: tp_suf = "K256"; tp_desc = &Keyed256_desc; break;
+ case OU: tp_suf = "OU"; tp_desc = &OneULong_desc; break;
+ case UK16: tp_suf = "UK16"; tp_desc = &Unkeyed16_desc; break;
+ case UK1024: tp_suf = "UK1024"; tp_desc = &Unkeyed1024_desc; break;
}
snprintf (tpname_data, sizeof (tpname_data), "DDSPerf%cData%s", reliable ? 'R' : 'U', tp_suf);
snprintf (tpname_ping, sizeof (tpname_ping), "DDSPerf%cPing%s", reliable ? 'R' : 'U', tp_suf);
diff --git a/src/tools/ddsperf/ddsperf_types.idl b/src/tools/ddsperf/ddsperf_types.idl
index 2a650f2..1ccc77e 100644
--- a/src/tools/ddsperf/ddsperf_types.idl
+++ b/src/tools/ddsperf/ddsperf_types.idl
@@ -4,6 +4,20 @@ struct OneULong
};
#pragma keylist OneULong
+struct Unkeyed16
+{
+ unsigned long seq;
+ octet baggage[12];
+};
+#pragma keylist Unkeyed16
+
+struct Unkeyed1024
+{
+ unsigned long seq;
+ octet baggage[1020];
+};
+#pragma keylist Unkeyed1024
+
struct Keyed32
{
unsigned long seq;
From 2d8bf36f8e5db53d779be6e5ef13b0003f1b578f Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Fri, 15 Nov 2019 11:51:41 +0100
Subject: [PATCH 30/55] Fix ddsperf interpretation of kHz
Signed-off-by: Erik Boasson
---
src/tools/ddsperf/ddsperf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c
index 11ea1cf..2a252d8 100644
--- a/src/tools/ddsperf/ddsperf.c
+++ b/src/tools/ddsperf/ddsperf.c
@@ -1675,7 +1675,7 @@ struct multiplier {
static const struct multiplier frequency_units[] = {
{ "Hz", 1 },
- { "kHz", 1024 },
+ { "kHz", 1000 },
{ NULL, 0 }
};
From 3da21315f2f3a3578a714729339a97fb528ec291 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 4 Nov 2019 19:56:53 +0100
Subject: [PATCH 31/55] Improve errors for invalid port numbers (#303)
Signed-off-by: Erik Boasson
---
docs/manual/options.md | 4 +-
etc/cyclonedds.rnc | 4 +-
etc/cyclonedds.xsd | 4 +-
src/core/ddsi/CMakeLists.txt | 2 +
.../ddsi/include/dds/ddsi/ddsi_portmapping.h | 47 ++++++
src/core/ddsi/include/dds/ddsi/ddsi_tran.h | 15 +-
src/core/ddsi/include/dds/ddsi/q_config.h | 9 +-
src/core/ddsi/include/dds/ddsi/q_debmon.h | 2 +-
src/core/ddsi/src/ddsi_portmapping.c | 126 ++++++++++++++++
src/core/ddsi/src/ddsi_raweth.c | 7 +
src/core/ddsi/src/ddsi_tcp.c | 9 +-
src/core/ddsi/src/ddsi_tran.c | 3 +-
src/core/ddsi/src/ddsi_udp.c | 7 +
src/core/ddsi/src/q_addrset.c | 13 +-
src/core/ddsi/src/q_config.c | 38 ++---
src/core/ddsi/src/q_debmon.c | 13 +-
src/core/ddsi/src/q_init.c | 134 ++++++++++++------
17 files changed, 337 insertions(+), 100 deletions(-)
create mode 100644 src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
create mode 100644 src/core/ddsi/src/ddsi_portmapping.c
diff --git a/docs/manual/options.md b/docs/manual/options.md
index 25caaf6..6eed7ca 100644
--- a/docs/manual/options.md
+++ b/docs/manual/options.md
@@ -261,7 +261,7 @@ The default value is: "250".
##### //CycloneDDS/Domain/Discovery/Ports/MulticastDataOffset
Integer
-This element specifies the port number for multicast meta traffic (refer
+This element specifies the port number for multicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d2).
The default value is: "1".
@@ -289,7 +289,7 @@ The default value is: "2".
##### //CycloneDDS/Domain/Discovery/Ports/UnicastDataOffset
Integer
-This element specifies the port number for unicast meta traffic (refer to
+This element specifies the port number for unicast data traffic (refer to
the DDSI 2.1 specification, section 9.6.1, constant d3).
The default value is: "11".
diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc
index 12444a9..95bb3ce 100644
--- a/etc/cyclonedds.rnc
+++ b/etc/cyclonedds.rnc
@@ -203,7 +203,7 @@ constant DG).
The default value is: "250".
""" ] ]
xsd:integer
}?
& [ a:documentation [ xml:lang="en" """
-This element specifies the port number for multicast meta traffic
+
This element specifies the port number for multicast data traffic
(refer to the DDSI 2.1 specification, section 9.6.1, constant
d2).
The default value is: "1".
""" ] ]
element MulticastDataOffset {
@@ -225,7 +225,7 @@ section 9.6.1, constant PG).The default value is:
xsd:integer
}?
& [ a:documentation [ xml:lang="en" """
-
This element specifies the port number for unicast meta traffic (refer
+
This element specifies the port number for unicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d3).
The
default value is: "11".
""" ] ]
element UnicastDataOffset {
diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd
index 4e31f2f..4ec63e5 100644
--- a/etc/cyclonedds.xsd
+++ b/etc/cyclonedds.xsd
@@ -313,7 +313,7 @@ constant DG).</p><p>The default value is: "250".&l
-<p>This element specifies the port number for multicast meta traffic
+<p>This element specifies the port number for multicast data traffic
(refer to the DDSI 2.1 specification, section 9.6.1, constant
d2).</p><p>The default value is: "1".</p>
@@ -338,7 +338,7 @@ section 9.6.1, constant PG).</p><p>The default value is:
-<p>This element specifies the port number for unicast meta traffic (refer
+<p>This element specifies the port number for unicast data traffic (refer
to the DDSI 2.1 specification, section 9.6.1, constant d3).</p><p>The
default value is: "11".</p>
diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt
index 9e8c6a7..933762a 100644
--- a/src/core/ddsi/CMakeLists.txt
+++ b/src/core/ddsi/CMakeLists.txt
@@ -18,6 +18,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_raweth.c
ddsi_ipaddr.c
ddsi_mcgroup.c
+ ddsi_portmapping.c
ddsi_serdata.c
ddsi_serdata_default.c
ddsi_sertopic.c
@@ -69,6 +70,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_ipaddr.h
ddsi_mcgroup.h
ddsi_plist_generic.h
+ ddsi_portmapping.h
ddsi_serdata.h
ddsi_sertopic.h
ddsi_serdata_default.h
diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h b/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
new file mode 100644
index 0000000..0374672
--- /dev/null
+++ b/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright(c) 2019 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
+ */
+#ifndef DDSI_PORTMAPPING_H
+#define DDSI_PORTMAPPING_H
+
+#include
+#include
+#include
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+enum ddsi_port {
+ DDSI_PORT_MULTI_DISC,
+ DDSI_PORT_MULTI_DATA,
+ DDSI_PORT_UNI_DISC,
+ DDSI_PORT_UNI_DATA
+};
+
+struct ddsi_portmapping {
+ uint32_t base;
+ uint32_t dg;
+ uint32_t pg;
+ uint32_t d0;
+ uint32_t d1;
+ uint32_t d2;
+ uint32_t d3;
+};
+
+bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain_id, int32_t participant_index, char *msg, size_t msgsize);
+uint32_t ddsi_get_port (const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* DDSI_PORTMAPPING_H */
diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h
index a3e5d89..488b401 100644
--- a/src/core/ddsi/include/dds/ddsi/ddsi_tran.h
+++ b/src/core/ddsi/include/dds/ddsi/ddsi_tran.h
@@ -61,7 +61,7 @@ typedef void (*ddsi_tran_peer_locator_fn_t) (ddsi_tran_conn_t, nn_locator_t *);
typedef void (*ddsi_tran_disable_multiplexing_fn_t) (ddsi_tran_conn_t);
typedef ddsi_tran_conn_t (*ddsi_tran_accept_fn_t) (ddsi_tran_listener_t);
typedef ddsi_tran_conn_t (*ddsi_tran_create_conn_fn_t) (ddsi_tran_factory_t fact, uint32_t, ddsi_tran_qos_t);
-typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t);
+typedef ddsi_tran_listener_t (*ddsi_tran_create_listener_fn_t) (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t);
typedef void (*ddsi_tran_release_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_close_conn_fn_t) (ddsi_tran_conn_t);
typedef void (*ddsi_tran_unblock_listener_fn_t) (ddsi_tran_listener_t);
@@ -70,6 +70,7 @@ typedef int (*ddsi_tran_join_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *src
typedef int (*ddsi_tran_leave_mc_fn_t) (ddsi_tran_conn_t, const nn_locator_t *srcip, const nn_locator_t *mcip, const struct nn_interface *interf);
typedef int (*ddsi_is_mcaddr_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc);
typedef int (*ddsi_is_ssm_mcaddr_fn_t) (ddsi_tran_factory_t tran, const nn_locator_t *loc);
+typedef int (*ddsi_is_valid_port_fn_t) (ddsi_tran_factory_t tran, uint32_t port);
enum ddsi_nearby_address_result {
DNAR_DISTANT,
@@ -172,7 +173,8 @@ struct ddsi_tran_factory
ddsi_locator_from_string_fn_t m_locator_from_string_fn;
ddsi_locator_to_string_fn_t m_locator_to_string_fn;
ddsi_enumerate_interfaces_fn_t m_enumerate_interfaces_fn;
-
+ ddsi_is_valid_port_fn_t m_is_valid_port_fn;
+
/* Data */
int32_t m_kind;
@@ -205,10 +207,17 @@ void ddsi_factory_conn_init (const struct ddsi_tran_factory *factory, ddsi_tran_
inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind) {
return factory->m_supports_fn (factory, kind);
}
+inline int ddsi_is_valid_port (ddsi_tran_factory_t factory, uint32_t port) {
+ return factory->m_is_valid_port_fn (factory, port);
+}
inline ddsi_tran_conn_t ddsi_factory_create_conn (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos) {
+ if (!ddsi_is_valid_port (factory, port))
+ return NULL;
return factory->m_create_conn_fn (factory, port, qos);
}
-inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos) {
+inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos) {
+ if (!ddsi_is_valid_port (factory, port))
+ return NULL;
return factory->m_create_listener_fn (factory, port, qos);
}
diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h
index 02b26c1..e4cebcd 100644
--- a/src/core/ddsi/include/dds/ddsi/q_config.h
+++ b/src/core/ddsi/include/dds/ddsi/q_config.h
@@ -16,6 +16,7 @@
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/q_feature_check.h"
+#include "dds/ddsi/ddsi_portmapping.h"
#if defined (__cplusplus)
extern "C" {
@@ -198,7 +199,6 @@ struct config
uint32_t domainId;
int participantIndex;
int maxAutoParticipantIndex;
- uint32_t port_base;
char *spdpMulticastAddressString;
char *defaultMulticastAddressString;
char *assumeMulticastCapable;
@@ -321,12 +321,7 @@ struct config
enum many_sockets_mode many_sockets_mode;
int assume_rti_has_pmd_endpoints;
- uint32_t port_dg;
- uint32_t port_pg;
- uint32_t port_d0;
- uint32_t port_d1;
- uint32_t port_d2;
- uint32_t port_d3;
+ struct ddsi_portmapping ports;
int monitor_port;
diff --git a/src/core/ddsi/include/dds/ddsi/q_debmon.h b/src/core/ddsi/include/dds/ddsi/q_debmon.h
index defb83e..5f5ac06 100644
--- a/src/core/ddsi/include/dds/ddsi/q_debmon.h
+++ b/src/core/ddsi/include/dds/ddsi/q_debmon.h
@@ -20,7 +20,7 @@ struct debug_monitor;
typedef int (*debug_monitor_cpf_t) (ddsi_tran_conn_t conn, const char *fmt, ...);
typedef int (*debug_monitor_plugin_t) (ddsi_tran_conn_t conn, debug_monitor_cpf_t cpf, void *arg);
-struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port);
+struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port);
void add_debug_monitor_plugin (struct debug_monitor *dm, debug_monitor_plugin_t fn, void *arg);
void free_debug_monitor (struct debug_monitor *dm);
diff --git a/src/core/ddsi/src/ddsi_portmapping.c b/src/core/ddsi/src/ddsi_portmapping.c
new file mode 100644
index 0000000..164ebfe
--- /dev/null
+++ b/src/core/ddsi/src/ddsi_portmapping.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright(c) 2019 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/ddsi/ddsi_portmapping.h"
+#include "dds/ddsi/q_config.h"
+
+static bool get_port_int (uint32_t *port, const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index, char *str_if_overflow, size_t strsize)
+{
+ uint32_t off = UINT32_MAX, ppidx = UINT32_MAX;
+
+ assert (domain_id != UINT32_MAX);
+ assert (participant_index >= 0 || participant_index == PARTICIPANT_INDEX_NONE);
+
+ switch (which)
+ {
+ case DDSI_PORT_MULTI_DISC:
+ off = map->d0;
+ /* multicast port numbers are not affected by participant index */
+ ppidx = 0;
+ break;
+ case DDSI_PORT_MULTI_DATA:
+ off = map->d2;
+ /* multicast port numbers are not affected by participant index */
+ ppidx = 0;
+ break;
+ case DDSI_PORT_UNI_DISC:
+ if (participant_index == PARTICIPANT_INDEX_NONE)
+ {
+ /* participant index "none" means unicast ports get chosen by the transport */
+ *port = 0;
+ return true;
+ }
+ off = map->d1;
+ ppidx = (uint32_t) participant_index;
+ break;
+ case DDSI_PORT_UNI_DATA:
+ if (participant_index == PARTICIPANT_INDEX_NONE)
+ {
+ /* participant index "none" means unicast ports get chosen by the transport */
+ *port = 0;
+ return true;
+ }
+ off = map->d3;
+ ppidx = (uint32_t) participant_index;
+ break;
+ }
+
+ const uint64_t a = (uint64_t) map->dg * domain_id;
+ const uint64_t b = map->base + (uint64_t) map->pg * ppidx + off;
+
+ /* For the mapping to be valid, the port number must be in range of an unsigned 32 bit integer and must
+ not be 0 (as that is used for indicating a random port should be selected by the transport). The
+ transports may limit this further, but at least we won't have to worry about overflow anymore. */
+ *port = (uint32_t) (a + b);
+ if (a <= UINT32_MAX && b <= UINT32_MAX - a && *port > 0)
+ return true;
+ else
+ {
+ /* a, b < 2^64 ~ 18e18; 2^32 <= a + b < 2^65 ~ 36e18
+ 2^32 ~ 4e9, so it can easily be split into (a+b) `div` 1e9 and (a+b) `mod` 1e9
+ and then the most-significant part is guaranteed to be > 0 */
+ const uint32_t billion = 1000000000;
+ const uint32_t y = (uint32_t) (a % billion) + (uint32_t) (b % billion);
+ const uint64_t x = (a / billion) + (b / billion) + (y / billion);
+ snprintf (str_if_overflow, strsize, "%"PRIu64"%09"PRIu32, x, y % billion);
+ return false;
+ }
+}
+
+static const char *portname (enum ddsi_port which)
+{
+ const char *n = "?";
+ switch (which)
+ {
+ case DDSI_PORT_MULTI_DISC: n = "multicast discovery"; break;
+ case DDSI_PORT_MULTI_DATA: n = "multicast data"; break;
+ case DDSI_PORT_UNI_DISC: n = "unicast discovery"; break;
+ case DDSI_PORT_UNI_DATA: n = "unicast data"; break;
+ }
+ return n;
+}
+
+bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain_id, int32_t participant_index, char *msg, size_t msgsize)
+{
+ DDSRT_STATIC_ASSERT (DDSI_PORT_MULTI_DISC >= 0 &&
+ DDSI_PORT_MULTI_DISC + 1 == DDSI_PORT_MULTI_DATA &&
+ DDSI_PORT_MULTI_DATA + 1 == DDSI_PORT_UNI_DISC &&
+ DDSI_PORT_UNI_DISC + 1 == DDSI_PORT_UNI_DATA &&
+ DDSI_PORT_UNI_DATA >= 0);
+ uint32_t dummy_port;
+ char str[32];
+ bool ok = true;
+ enum ddsi_port which = DDSI_PORT_MULTI_DISC;
+ int n = snprintf (msg, msgsize, "port number(s) of out range:");
+ size_t pos = (n >= 0 && (size_t) n <= msgsize) ? (size_t) n : msgsize;
+ do {
+ if (!get_port_int (&dummy_port, map, which, domain_id, participant_index, str, sizeof (str)))
+ {
+ n = snprintf (msg + pos, msgsize - pos, "%s %s %s", ok ? "" : ",", portname (which), str);
+ if (n >= 0 && (size_t) n <= msgsize - pos)
+ pos += (size_t) n;
+ ok = false;
+ }
+ } while (which++ != DDSI_PORT_UNI_DATA);
+ return ok;
+}
+
+uint32_t ddsi_get_port (const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index)
+{
+ /* Not supposed to come here if port mapping is invalid */
+ uint32_t port;
+ char str[32];
+ bool ok = get_port_int (&port, map, which, domain_id, participant_index, str, sizeof (str));
+ assert (ok);
+ (void) ok;
+ return port;
+}
diff --git a/src/core/ddsi/src/ddsi_raweth.c b/src/core/ddsi/src/ddsi_raweth.c
index bdb9e27..153fcf7 100644
--- a/src/core/ddsi/src/ddsi_raweth.c
+++ b/src/core/ddsi/src/ddsi_raweth.c
@@ -356,6 +356,12 @@ static int ddsi_raweth_enumerate_interfaces (ddsi_tran_factory_t fact, enum tran
return ddsrt_getifaddrs(ifs, afs);
}
+static int ddsi_raweth_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
+{
+ (void) fact;
+ return (port >= 1 && port <= 65535);
+}
+
int ddsi_raweth_init (struct q_globals *gv)
{
struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact));
@@ -377,6 +383,7 @@ int ddsi_raweth_init (struct q_globals *gv)
fact->m_locator_from_string_fn = ddsi_raweth_address_from_string;
fact->m_locator_to_string_fn = ddsi_raweth_to_string;
fact->m_enumerate_interfaces_fn = ddsi_raweth_enumerate_interfaces;
+ fact->m_is_valid_port_fn = ddsi_raweth_is_valid_port;
ddsi_factory_add (gv, fact);
GVLOG (DDS_LC_CONFIG, "raweth initialized\n");
return 0;
diff --git a/src/core/ddsi/src/ddsi_tcp.c b/src/core/ddsi/src/ddsi_tcp.c
index 778d733..47ff028 100644
--- a/src/core/ddsi/src/ddsi_tcp.c
+++ b/src/core/ddsi/src/ddsi_tcp.c
@@ -856,7 +856,7 @@ static ddsi_tcp_conn_t ddsi_tcp_new_conn (struct ddsi_tran_factory_tcp *fact, dd
return conn;
}
-static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, int port, ddsi_tran_qos_t qos)
+static ddsi_tran_listener_t ddsi_tcp_create_listener (ddsi_tran_factory_t fact, uint32_t port, ddsi_tran_qos_t qos)
{
char buff[DDSI_LOCSTRLEN];
ddsrt_socket_t sock;
@@ -1055,6 +1055,12 @@ static enum ddsi_nearby_address_result ddsi_tcp_is_nearby_address (ddsi_tran_fac
return ddsi_ipaddr_is_nearby_address(tran, loc, ownloc, ninterf, interf);
}
+static int ddsi_tcp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
+{
+ (void) fact;
+ return (port <= 65535);
+}
+
int ddsi_tcp_init (struct q_globals *gv)
{
struct ddsi_tran_factory_tcp *fact = ddsrt_malloc (sizeof (*fact));
@@ -1079,6 +1085,7 @@ int ddsi_tcp_init (struct q_globals *gv)
fact->fact.m_is_mcaddr_fn = ddsi_tcp_is_mcaddr;
fact->fact.m_is_ssm_mcaddr_fn = ddsi_tcp_is_ssm_mcaddr;
fact->fact.m_is_nearby_address_fn = ddsi_tcp_is_nearby_address;
+ fact->fact.m_is_valid_port_fn = ddsi_tcp_is_valid_port;
ddsi_factory_add (gv, &fact->fact);
#if DDSRT_HAVE_IPV6
diff --git a/src/core/ddsi/src/ddsi_tran.c b/src/core/ddsi/src/ddsi_tran.c
index 3094d29..7636167 100644
--- a/src/core/ddsi/src/ddsi_tran.c
+++ b/src/core/ddsi/src/ddsi_tran.c
@@ -23,8 +23,9 @@
extern inline uint32_t ddsi_conn_type (ddsi_tran_conn_t conn);
extern inline uint32_t ddsi_conn_port (ddsi_tran_conn_t conn);
-extern inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, int port, ddsi_tran_qos_t qos);
+extern inline ddsi_tran_listener_t ddsi_factory_create_listener (ddsi_tran_factory_t factory, uint32_t port, ddsi_tran_qos_t qos);
extern inline bool ddsi_factory_supports (const struct ddsi_tran_factory *factory, int32_t kind);
+extern inline int ddsi_is_valid_port (ddsi_tran_factory_t factory, uint32_t port);
extern inline ddsrt_socket_t ddsi_conn_handle (ddsi_tran_conn_t conn);
extern inline int ddsi_conn_locator (ddsi_tran_conn_t conn, nn_locator_t * loc);
extern inline ddsrt_socket_t ddsi_tran_handle (ddsi_tran_base_t base);
diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c
index 3d0a93d..90b1843 100644
--- a/src/core/ddsi/src/ddsi_udp.c
+++ b/src/core/ddsi/src/ddsi_udp.c
@@ -466,6 +466,12 @@ static void ddsi_udp_fini (ddsi_tran_factory_t fact)
ddsrt_free (fact);
}
+static int ddsi_udp_is_valid_port (ddsi_tran_factory_t fact, uint32_t port)
+{
+ (void) fact;
+ return (port <= 65535);
+}
+
int ddsi_udp_init (struct q_globals *gv)
{
struct ddsi_tran_factory *fact = ddsrt_malloc (sizeof (*fact));
@@ -489,6 +495,7 @@ int ddsi_udp_init (struct q_globals *gv)
fact->m_locator_from_string_fn = ddsi_udp_address_from_string;
fact->m_locator_to_string_fn = ddsi_udp_locator_to_string;
fact->m_enumerate_interfaces_fn = ddsi_eth_enumerate_interfaces;
+ fact->m_is_valid_port_fn = ddsi_udp_is_valid_port;
#if DDSRT_HAVE_IPV6
if (gv->config.transport_selector == TRANS_UDP6)
{
diff --git a/src/core/ddsi/src/q_addrset.c b/src/core/ddsi/src/q_addrset.c
index b04f064..7bc6d59 100644
--- a/src/core/ddsi/src/q_addrset.c
+++ b/src/core/ddsi/src/q_addrset.c
@@ -103,25 +103,22 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse
if (!ddsi_is_mcaddr (gv, &loc))
{
assert (gv->config.maxAutoParticipantIndex >= 0);
- for (uint32_t i = 0; i <= (uint32_t) gv->config.maxAutoParticipantIndex; i++)
+ for (int32_t i = 0; i <= gv->config.maxAutoParticipantIndex; i++)
{
- uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + i * gv->config.port_pg + gv->config.port_d1;
- loc.port = (unsigned) port;
+ loc.port = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DISC, gv->config.domainId, i);
if (i == 0)
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
else
- GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, port);
+ GVLOG (DDS_LC_CONFIG, ", :%"PRIu32, loc.port);
add_to_addrset (gv, as, &loc);
}
}
else
{
- uint32_t port;
if (port_mode == -1)
- port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0;
+ loc.port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
else
- port = (uint32_t) port_mode;
- loc.port = (unsigned) port;
+ loc.port = (uint32_t) port_mode;
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
add_to_addrset (gv, as, &loc);
}
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 75ca4fe..481c767 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -166,7 +166,6 @@ DUPF(uint32);
DU(natint);
DU(natint_255);
DUPF(participantIndex);
-DU(port);
DU(dyn_port);
DUPF(memsize);
DU(duration_inf);
@@ -610,20 +609,20 @@ static const struct cfgelem sizing_cfgelems[] = {
};
static const struct cfgelem discovery_ports_cfgelems[] = {
- { LEAF("Base"), 1, "7400", ABSOFF(port_base), 0, uf_port, 0, pf_uint,
+ { LEAF("Base"), 1, "7400", ABSOFF(ports.base), 0, uf_uint, 0, pf_uint,
BLURB("This element specifies the base port number (refer to the DDSI 2.1 specification, section 9.6.1, constant PB).
") },
- { LEAF("DomainGain"), 1, "250", ABSOFF(port_dg), 0, uf_uint, 0, pf_uint,
+ { LEAF("DomainGain"), 1, "250", ABSOFF(ports.dg), 0, uf_uint, 0, pf_uint,
BLURB("This element specifies the domain gain, relating domain ids to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant DG).
") },
- { LEAF("ParticipantGain"), 1, "2", ABSOFF(port_pg), 0, uf_uint, 0, pf_uint,
+ { LEAF("ParticipantGain"), 1, "2", ABSOFF(ports.pg), 0, uf_uint, 0, pf_uint,
BLURB("This element specifies the participant gain, relating p0, articipant index to sets of port numbers (refer to the DDSI 2.1 specification, section 9.6.1, constant PG).
") },
- { LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(port_d0), 0, uf_uint, 0, pf_uint,
+ { LEAF("MulticastMetaOffset"), 1, "0", ABSOFF(ports.d0), 0, uf_uint, 0, pf_uint,
BLURB("This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d0).
") },
- { LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(port_d1), 0, uf_uint, 0, pf_uint,
+ { LEAF("UnicastMetaOffset"), 1, "10", ABSOFF(ports.d1), 0, uf_uint, 0, pf_uint,
BLURB("This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d1).
") },
- { LEAF("MulticastDataOffset"), 1, "1", ABSOFF(port_d2), 0, uf_uint, 0, pf_uint,
- BLURB("This element specifies the port number for multicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d2).
") },
- { LEAF("UnicastDataOffset"), 1, "11", ABSOFF(port_d3), 0, uf_uint, 0, pf_uint,
- BLURB("This element specifies the port number for unicast meta traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d3).
") },
+ { LEAF("MulticastDataOffset"), 1, "1", ABSOFF(ports.d2), 0, uf_uint, 0, pf_uint,
+ BLURB("This element specifies the port number for multicast data traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d2).
") },
+ { LEAF("UnicastDataOffset"), 1, "11", ABSOFF(ports.d3), 0, uf_uint, 0, pf_uint,
+ BLURB("This element specifies the port number for unicast data traffic (refer to the DDSI 2.1 specification, section 9.6.1, constant d3).
") },
END_MARKER
};
@@ -1883,34 +1882,23 @@ static enum update_result uf_natint_255(struct cfgst *cfgst, void *parent, struc
static enum update_result uf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG (int first), const char *value)
{
- unsigned * const elem = cfg_address (cfgst, parent, cfgelem);
+ uint32_t * const elem = cfg_address (cfgst, parent, cfgelem);
char *endptr;
unsigned long v = strtoul (value, &endptr, 10);
if (*value == 0 || *endptr != 0)
return cfg_error (cfgst, "%s: not a decimal integer", value);
- if (v != (unsigned) v)
+ if (v != (uint32_t) v)
return cfg_error (cfgst, "%s: value out of range", value);
- *elem = (unsigned) v;
+ *elem = (uint32_t) v;
return URES_SUCCESS;
}
static void pf_uint (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources)
{
- unsigned const * const p = cfg_address (cfgst, parent, cfgelem);
+ uint32_t const * const p = cfg_address (cfgst, parent, cfgelem);
cfg_logelem (cfgst, sources, "%u", *p);
}
-static enum update_result uf_port(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int first, const char *value)
-{
- int *elem = cfg_address (cfgst, parent, cfgelem);
- if (uf_uint (cfgst, parent, cfgelem, first, value) != URES_SUCCESS)
- return URES_ERROR;
- else if (*elem < 1 || *elem > 65535)
- return cfg_error (cfgst, "%s: out of range", value);
- else
- return URES_SUCCESS;
-}
-
static enum update_result uf_duration_gen (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, const char *value, int64_t def_mult, int64_t min_ns, int64_t max_ns)
{
return uf_natint64_unit (cfgst, cfg_address (cfgst, parent, cfgelem), value, unittab_duration, def_mult, min_ns, max_ns);
diff --git a/src/core/ddsi/src/q_debmon.c b/src/core/ddsi/src/q_debmon.c
index 58c8971..b4f6c29 100644
--- a/src/core/ddsi/src/q_debmon.c
+++ b/src/core/ddsi/src/q_debmon.c
@@ -346,10 +346,11 @@ static uint32_t debmon_main (void *vdm)
return 0;
}
-struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port)
+struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port)
{
struct debug_monitor *dm;
+ /* negative port number means the feature is disabled */
if (gv->config.monitor_port < 0)
return NULL;
@@ -362,7 +363,14 @@ struct debug_monitor *new_debug_monitor (struct q_globals *gv, int port)
dm->plugins = NULL;
if ((dm->tran_factory = ddsi_factory_find (gv, "tcp")) == NULL)
dm->tran_factory = ddsi_factory_find (gv, "tcp6");
- dm->servsock = ddsi_factory_create_listener (dm->tran_factory, port, NULL);
+
+ if (!ddsi_is_valid_port (dm->tran_factory, (uint32_t) port))
+ {
+ GVERROR ("debug monitor port number %"PRId32" is invalid\n", port);
+ goto err_invalid_port;
+ }
+
+ dm->servsock = ddsi_factory_create_listener (dm->tran_factory, (uint32_t) port, NULL);
if (dm->servsock == NULL)
{
GVWARNING ("debmon: can't create socket\n");
@@ -389,6 +397,7 @@ err_listen:
ddsrt_mutex_destroy(&dm->lock);
ddsi_listener_free(dm->servsock);
err_servsock:
+err_invalid_port:
ddsrt_free(dm);
return NULL;
}
diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c
index c73a39e..04d94ba 100644
--- a/src/core/ddsi/src/q_init.c
+++ b/src/core/ddsi/src/q_init.c
@@ -71,36 +71,30 @@ static void add_peer_addresses (const struct q_globals *gv, struct addrset *as,
}
}
-static int make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid)
+enum make_uc_sockets_ret {
+ MUSRET_SUCCESS,
+ MUSRET_INVALID_PORTS,
+ MUSRET_NOSOCKET
+};
+
+static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * pdata, int ppid)
{
if (gv->config.many_sockets_mode == MSM_NO_UNICAST)
{
assert (ppid == PARTICIPANT_INDEX_NONE);
- *pdata = *pdisc = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId);
+ *pdata = *pdisc = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, ppid);
if (gv->config.allowMulticast)
{
/* FIXME: ugly hack - but we'll fix up after creating the multicast sockets */
- return 0;
+ return MUSRET_SUCCESS;
}
}
- if (ppid >= 0)
- {
- /* FIXME: verify port numbers are in range instead of truncating them like this */
- uint32_t base = gv->config.port_base + (gv->config.port_dg * gv->config.domainId) + ((uint32_t) ppid * gv->config.port_pg);
- *pdisc = base + gv->config.port_d1;
- *pdata = base + gv->config.port_d3;
- }
- else if (ppid == PARTICIPANT_INDEX_NONE)
- {
- *pdata = 0;
- *pdisc = 0;
- }
- else
- {
- DDS_FATAL ("make_uc_sockets: invalid participant index %d\n", ppid);
- return -1;
- }
+ *pdisc = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DISC, gv->config.domainId, ppid);
+ *pdata = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DATA, gv->config.domainId, ppid);
+
+ if (!ddsi_is_valid_port (gv->m_factory, *pdisc) || !ddsi_is_valid_port (gv->m_factory, *pdata))
+ return MUSRET_INVALID_PORTS;
gv->disc_conn_uc = ddsi_factory_create_conn (gv->m_factory, *pdisc, NULL);
if (gv->disc_conn_uc)
@@ -123,13 +117,12 @@ static int make_uc_sockets (struct q_globals *gv, uint32_t * pdisc, uint32_t * p
else
{
/* Set unicast locators */
-
ddsi_conn_locator (gv->disc_conn_uc, &gv->loc_meta_uc);
ddsi_conn_locator (gv->data_conn_uc, &gv->loc_default_uc);
}
}
- return gv->data_conn_uc ? 0 : -1;
+ return gv->data_conn_uc ? MUSRET_SUCCESS : MUSRET_NOSOCKET;
}
static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template)
@@ -286,7 +279,7 @@ static int string_to_default_locator (const struct q_globals *gv, nn_locator_t *
static int set_spdp_address (struct q_globals *gv)
{
- const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0);
+ const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
int rc = 0;
/* FIXME: FIXME: FIXME: */
gv->loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID;
@@ -318,7 +311,7 @@ static int set_spdp_address (struct q_globals *gv)
static int set_default_mc_address (struct q_globals *gv)
{
- const uint32_t port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2);
+ const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
int rc;
if (!gv->config.defaultMulticastAddressString)
gv->loc_default_mc = gv->loc_spdp_mc;
@@ -459,6 +452,25 @@ int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst)
unsigned num_channel_threads = 0;
#endif
+ {
+ char message[256];
+ int32_t ppidx;
+ if (gv->config.participantIndex >= 0 || gv->config.participantIndex == PARTICIPANT_INDEX_NONE)
+ ppidx = gv->config.participantIndex;
+ else if (gv->config.participantIndex == PARTICIPANT_INDEX_AUTO)
+ ppidx = gv->config.maxAutoParticipantIndex;
+ else
+ {
+ assert (0);
+ ppidx = 0;
+ }
+ if (!ddsi_valid_portmapping (&gv->config.ports, gv->config.domainId, ppidx, message, sizeof (message)))
+ {
+ DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "Invalid port mapping: %s\n", message);
+ goto err_config_late_error;
+ }
+ }
+
/* retry_on_reject_duration default is dependent on late_ack_mode and responsiveness timeout, so fix up */
if (gv->config.whc_init_highwater_mark.isdefault)
gv->config.whc_init_highwater_mark.value = gv->config.whc_lowwater_mark;
@@ -646,8 +658,13 @@ int create_multicast_sockets (struct q_globals *gv)
uint32_t port;
qos->m_multicast = 1;
- /* FIXME: should check for overflow */
- port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d0);
+ port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
+ if (!ddsi_is_valid_port (gv->m_factory, port))
+ {
+ GVERROR ("Failed to create discovery multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
+ gv->config.domainId, port);
+ goto err_disc;
+ }
if ((disc = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
goto err_disc;
if (gv->config.many_sockets_mode == MSM_NO_UNICAST)
@@ -657,16 +674,24 @@ int create_multicast_sockets (struct q_globals *gv)
}
else
{
- port = (uint32_t) (gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2);
+ port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
+ if (!ddsi_is_valid_port (gv->m_factory, port))
+ {
+ GVERROR ("Failed to create data multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
+ gv->config.domainId, port);
+ goto err_disc;
+ }
if ((data = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
+ {
goto err_data;
+ }
}
ddsi_tran_free_qos (qos);
gv->disc_conn_mc = disc;
gv->data_conn_mc = data;
- GVTRACE ("Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n",
- ddsi_conn_port (gv->disc_conn_mc), ddsi_conn_port (gv->data_conn_mc));
+ GVLOG (DDS_LC_CONFIG, "Multicast Ports: discovery %"PRIu32" data %"PRIu32" \n",
+ ddsi_conn_port (gv->disc_conn_mc), ddsi_conn_port (gv->data_conn_mc));
return 1;
err_data:
@@ -980,7 +1005,7 @@ int rtps_init (struct q_globals *gv)
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
/* Convert address sets in partition mappings from string to address sets */
{
- const uint32_t port = gv->config.port_base + gv->config.port_dg * gv->config.domainId + gv->config.port_d2;
+ const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
struct config_networkpartition_listelem *np;
for (np = gv->config.networkPartitions; np; np = np->next)
{
@@ -1070,33 +1095,44 @@ int rtps_init (struct q_globals *gv)
{
if (gv->config.participantIndex >= 0 || gv->config.participantIndex == PARTICIPANT_INDEX_NONE)
{
- if (make_uc_sockets (gv, &port_disc_uc, &port_data_uc, gv->config.participantIndex) < 0)
+ enum make_uc_sockets_ret musret = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, gv->config.participantIndex);
+ switch (musret)
{
- GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, gv->config.participantIndex);
- goto err_unicast_sockets;
+ case MUSRET_SUCCESS:
+ break;
+ case MUSRET_INVALID_PORTS:
+ GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
+ gv->config.domainId, gv->config.participantIndex, port_disc_uc, port_data_uc);
+ goto err_unicast_sockets;
+ case MUSRET_NOSOCKET:
+ GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant index %d (ports %"PRIu32", %"PRIu32")\n", gv->config.domainId, gv->config.participantIndex, port_disc_uc, port_data_uc);
+ goto err_unicast_sockets;
}
}
else if (gv->config.participantIndex == PARTICIPANT_INDEX_AUTO)
{
/* try to find a free one, and update gv->config.participantIndex */
+ enum make_uc_sockets_ret musret = MUSRET_NOSOCKET;
int ppid;
GVLOG (DDS_LC_CONFIG, "rtps_init: trying to find a free participant index\n");
- for (ppid = 0; ppid <= gv->config.maxAutoParticipantIndex; ppid++)
+ for (ppid = 0; ppid <= gv->config.maxAutoParticipantIndex && musret == MUSRET_NOSOCKET; ppid++)
{
- int r = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, ppid);
- if (r == 0) /* Success! */
- break;
- else if (r == -1) /* Try next one */
- continue;
- else /* Oops! */
+ musret = make_uc_sockets (gv, &port_disc_uc, &port_data_uc, ppid);
+ switch (musret)
{
- GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant %d\n", gv->config.domainId, ppid);
- goto err_unicast_sockets;
+ case MUSRET_SUCCESS:
+ break;
+ case MUSRET_INVALID_PORTS:
+ GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
+ gv->config.domainId, ppid, port_disc_uc, port_data_uc);
+ goto err_unicast_sockets;
+ case MUSRET_NOSOCKET: /* Try next one */
+ break;
}
}
if (ppid > gv->config.maxAutoParticipantIndex)
{
- GVERROR ("rtps_init: failed to find a free participant index for domain %"PRId32"\n", gv->config.domainId);
+ GVERROR ("Failed to find a free participant index for domain %"PRIu32"\n", gv->config.domainId);
goto err_unicast_sockets;
}
gv->config.participantIndex = ppid;
@@ -1107,7 +1143,7 @@ int rtps_init (struct q_globals *gv)
}
GVLOG (DDS_LC_CONFIG, "rtps_init: uc ports: disc %"PRIu32" data %"PRIu32"\n", port_disc_uc, port_data_uc);
}
- GVLOG (DDS_LC_CONFIG, "rtps_init: domainid %"PRId32" participantid %d\n", gv->config.domainId, gv->config.participantIndex);
+ GVLOG (DDS_LC_CONFIG, "rtps_init: domainid %"PRIu32" participantid %d\n", gv->config.domainId, gv->config.participantIndex);
if (gv->config.pcap_file && *gv->config.pcap_file)
{
@@ -1157,9 +1193,15 @@ int rtps_init (struct q_globals *gv)
/* Must have a data_conn_uc/tev_conn/transmit_conn */
gv->data_conn_uc = ddsi_factory_create_conn (gv->m_factory, 0, NULL);
- if (gv->config.tcp_port != -1)
+ if (gv->config.tcp_port == -1)
+ ; /* nop */
+ else if (!ddsi_is_valid_port (gv->m_factory, (uint32_t) gv->config.tcp_port))
{
- gv->listener = ddsi_factory_create_listener (gv->m_factory, gv->config.tcp_port, NULL);
+ GVERROR ("Listener port %d is out of range for transport %s\n", gv->config.tcp_port, gv->m_factory->m_typename);
+ }
+ else
+ {
+ gv->listener = ddsi_factory_create_listener (gv->m_factory, (uint32_t) gv->config.tcp_port, NULL);
if (gv->listener == NULL || ddsi_listener_listen (gv->listener) != 0)
{
GVERROR ("Failed to create %s listener\n", gv->m_factory->m_typename);
From e43bdb73c73931d73c4ec95ad2969a07f8cc3ce9 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Sun, 17 Nov 2019 21:27:45 +0100
Subject: [PATCH 32/55] Fix install dir of CycloneDDSConfig.cmake (#321)
Installing Cyclone DDS for multiple architectures with the same
installation prefix gave problems because the CMake configuration files
ended up overwriting each other. This brings it in line with the
recommended locations. Thanks to @hansfn.
Signed-off-by: Erik Boasson
---
.travis.yml | 14 +++++++++-----
README.md | 9 ++++-----
appveyor.yml | 2 +-
cmake/Modules/Packaging.cmake | 2 +-
docs/manual/GettingStartedGuide/helloworld.rst | 15 +++++++--------
examples/helloworld/CMakeLists.export | 8 +++-----
examples/roundtrip/CMakeLists.export | 8 +++-----
examples/throughput/CMakeLists.export | 8 +++-----
src/idlc/CMakeLists.txt | 6 +++---
9 files changed, 34 insertions(+), 38 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index e25c289..3db66a7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -191,11 +191,12 @@ before_script:
# code has been vetted, the test has been run a great many times (with the odd
# failure), and so we now simply skip the test to avoid the spurious failures.
script:
+ - INSTALLPREFIX="$(pwd)/install"
- mkdir build
- cd build
- conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} ..
- cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
- -DCMAKE_INSTALL_PREFIX=$(pwd)/install
+ -DCMAKE_INSTALL_PREFIX=${INSTALLPREFIX}
-DUSE_SANITIZER=${ASAN}
-DENABLE_SSL=${SSL}
-DBUILD_TESTING=on
@@ -217,12 +218,15 @@ script:
CMAKE_LINKER_FLAGS="-DCMAKE_LINKER_FLAGS=-fsanitize=${USE_SANITIZER}";
CMAKE_C_FLAGS="-DCMAKE_C_FLAGS=-fsanitize=${USE_SANITIZER}";
fi
- - mkdir install/share/CycloneDDS/examples/helloworld/build
- - cd install/share/CycloneDDS/examples/helloworld/build
- - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
+ - cd ..
+ - mkdir helloworld_build
+ - cd helloworld_build
+ - cmake -DCMAKE_PREFIX_PATH=${INSTALLPREFIX}
+ -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
${CMAKE_C_FLAGS}
${CMAKE_LINKER_FLAGS}
- -G "${GENERATOR}" ..
+ -G "${GENERATOR}"
+ ${INSTALLPREFIX}/share/CycloneDDS/examples/helloworld
- cmake --build . --config ${BUILD_TYPE}
- cd "${TRAVIS_BUILD_DIR}/build"
diff --git a/README.md b/README.md
index 959743d..2c80530 100644
--- a/README.md
+++ b/README.md
@@ -124,11 +124,10 @@ We will show you how to build and run an example program that measures latency.
built automatically when you build Cyclone DDS, so you don't need to follow these steps to be able
to run the program, it is merely to illustrate the process.
- $ cd cyclonedds/examples/roundtrip
- $ mkdir build
- $ cd build
- $ cmake ..
- $ make
+ $ mkdir roundtrip
+ $ cd roundtrip
+ $ cmake /share/CycloneDDS/examples/helloworld
+ $ cmake --build .
On one terminal start the application that will be responding to pings:
diff --git a/appveyor.yml b/appveyor.yml
index 5bf38d1..f686920 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -41,7 +41,7 @@ build_script:
- cd install/share/CycloneDDS/examples/helloworld
- mkdir build
- cd build
- - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%GENERATOR%" ..
+ - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_PREFIX_PATH=%CD%/../../../../.. -G "%GENERATOR%" ..
- cmake --build . --config %CONFIGURATION% -- /nologo /verbosity:minimal /maxcpucount /p:CL_MPCount=2
- cd ../../../../../..
diff --git a/cmake/Modules/Packaging.cmake b/cmake/Modules/Packaging.cmake
index a635869..bbc59f2 100644
--- a/cmake/Modules/Packaging.cmake
+++ b/cmake/Modules/Packaging.cmake
@@ -18,7 +18,7 @@ include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
set(PACKAGING_MODULE_DIR "${PROJECT_SOURCE_DIR}/cmake/Modules/Packaging")
-set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}")
+set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
# Generates Config.cmake.
configure_package_config_file(
diff --git a/docs/manual/GettingStartedGuide/helloworld.rst b/docs/manual/GettingStartedGuide/helloworld.rst
index c2c7862..0494952 100644
--- a/docs/manual/GettingStartedGuide/helloworld.rst
+++ b/docs/manual/GettingStartedGuide/helloworld.rst
@@ -206,13 +206,12 @@ look in the default locations for the code:`CycloneDDS` package.
.. _`IdlcGenerate`:
-The :code:`CycloneDDS` package provides the :code:`ddsc` library
-that contains the DDS API that the application needs. But apart
-from that, it also contains helper functionality
-(:code:`idlc_generate`) to generate library targets from IDL
-files. These library targets can be easily used when compiling
-an application that depends on a data type described
-in an IDL file.
+The :code:`CycloneDDS` package provides the :code:`ddsc` library that
+contains the DDS API that the application needs. It also provides a
+component "idlc" that provides helper functionality for generating
+library targets from IDL files (:code:`idlc_generate`). These library
+targets can be easily used when compiling an application that depends on
+a data type described in an IDL file.
Two applications will be created, :code:`HelloworldPublisher`
and :code:`HelloworldSubscriber`. Both consist only out of one
@@ -241,7 +240,7 @@ Here, we can let CMake configure the build environment for
us by typing:
::
- cmake ../
+ cmake ..
.. note::
CMake does a pretty good job at guessing which generator to use, but some
diff --git a/examples/helloworld/CMakeLists.export b/examples/helloworld/CMakeLists.export
index 3e24d44..9ecb402 100644
--- a/examples/helloworld/CMakeLists.export
+++ b/examples/helloworld/CMakeLists.export
@@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.5)
-if (NOT TARGET CycloneDDS::ddsc)
- # Find the CycloneDDS package. If it is not in a default location, try
- # finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
-endif()
+# Find the CycloneDDS package. If it is not in a default location, try
+# finding it relative to the example where it most likely resides.
+find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
diff --git a/examples/roundtrip/CMakeLists.export b/examples/roundtrip/CMakeLists.export
index a95a615..845ff71 100644
--- a/examples/roundtrip/CMakeLists.export
+++ b/examples/roundtrip/CMakeLists.export
@@ -11,11 +11,9 @@
#
cmake_minimum_required(VERSION 3.5)
-if (NOT TARGET CycloneDDS::ddsc)
- # Find the CycloneDDS package. If it is not in a default location, try
- # finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
-endif()
+# Find the CycloneDDS package. If it is not in a default location, try
+# finding it relative to the example where it most likely resides.
+find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
diff --git a/examples/throughput/CMakeLists.export b/examples/throughput/CMakeLists.export
index b037bf6..3741a82 100644
--- a/examples/throughput/CMakeLists.export
+++ b/examples/throughput/CMakeLists.export
@@ -11,11 +11,9 @@
#
cmake_minimum_required(VERSION 3.5)
-if (NOT TARGET CycloneDDS::ddsc)
- # Find the CycloneDDS package. If it is not in a default location, try
- # finding it relative to the example where it most likely resides.
- find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
-endif()
+# Find the CycloneDDS package. If it is not in a default location, try
+# finding it relative to the example where it most likely resides.
+find_package(CycloneDDS REQUIRED COMPONENTS idlc PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../../../..")
# This is a convenience function, provided by the CycloneDDS package,
# that will supply a library target related the the given idl file.
diff --git a/src/idlc/CMakeLists.txt b/src/idlc/CMakeLists.txt
index ae210c3..a6b2ea2 100644
--- a/src/idlc/CMakeLists.txt
+++ b/src/idlc/CMakeLists.txt
@@ -45,17 +45,17 @@ include(cmake/IdlcGenerate.cmake)
install(
FILES "cmake/IdlcGenerate.cmake"
- DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc"
COMPONENT idlc)
install(
FILES "${IDLC_SCRIPT_IN}"
- DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc"
COMPONENT idlc)
install(
FILES "${IDLC_JAR}"
- DESTINATION "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/idlc"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/idlc"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
COMPONENT idlc)
From a16118c8c88f7e8d2ad52408245f14d9b76b3749 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 18 Nov 2019 14:34:55 +0100
Subject: [PATCH 33/55] Remove references to deleted make, solution files
(#236)
Signed-off-by: Erik Boasson
---
.../manual/GettingStartedGuide/helloworld.rst | 103 +-----------------
1 file changed, 2 insertions(+), 101 deletions(-)
diff --git a/docs/manual/GettingStartedGuide/helloworld.rst b/docs/manual/GettingStartedGuide/helloworld.rst
index 0494952..780ed27 100644
--- a/docs/manual/GettingStartedGuide/helloworld.rst
+++ b/docs/manual/GettingStartedGuide/helloworld.rst
@@ -46,99 +46,7 @@ used for building your own applications.
Build Files
-===========
-Three files are available *Hello World!* root directory to support
-building the example. Both
-:ref:`Windows native ` (HelloWorld.sln) and
-:ref:`Linux native ` (Makefile) build files
-will only be available for this *Hello World!* example. All the
-other examples make use of the :ref:`CMake ` build
-system and thus only have the CMakeLists.txt build related file.
-
-.. _`LinuxNativeBuild`:
-
-Linux Native Build
-==================
-
-A Linux native :code:`Makefile` is provided in the
-:code:`examples/helloworld` directory within the destination location
-entered in the
-:ref:`vdds_install_examples script `.
-In a terminal, go to that directory and type
-::
-
- make
-
-The build process should have access to the include files and
-the ddsc library. The Makefile expects them to be present at
-system default locations so that it can find them automatically.
-If this isn't the case on your machine, then please
-update the commented out :code:`CFLAGS` and :code:`LDFLAGS` within the
-:code:`Makefile` to point to the proper locations.
-
-This will build the HelloworldSubscriber and HelloworldPublisher
-executables in the helloworld source directory (not the bin
-directory that contains the pre-build binaries).
-
-The *Hello World!* example can now be executed,
-like described in :ref:`Test your installation `,
-using the binaries that were just build. Be sure to use the right directories.
-
-
-.. _`WindowsNativeBuild`:
-
-Windows Native Build
-====================
-
-For the Windows Native Build, a Visual Studio solution file is
-available in the :code:`examples/helloworld` directory. Use a
-file explorer to navigate to that directory and double click on
-the :code:`HelloWorld.sln` file. Visual Studio should now start
-with the HelloWorld solution that contains three projects.
-
-+----------------------+-------------------------------------------------+
-| Project | Description |
-+======================+=================================================+
-| HelloWorldPublisher | Information to build the example publisher. |
-+----------------------+-------------------------------------------------+
-| HelloWorldSubscriber | Information to build the example subcriber. |
-+----------------------+-------------------------------------------------+
-| HelloWorldType | Information to (re)generate |
-| | :ref:`HelloWorldData_Msg ` |
-| | data type. |
-+----------------------+-------------------------------------------------+
-
-Creating the *Hello World!* example executables is as simple as
-selecting the required configuration and building the solution.
-
-:code:`helloworld\vs\directories.props` contains the location of where
-the Eclipse Cyclone DDS header files and libraries are be placed. These locations
-are based on the default installation directory structure. When Eclipse Cyclone DDS
-is installed in a different directory, the following paths in
-:code:`helloworld\vs\directories.props` should be changed, like:
-
-.. code-block:: xml
-
- C:/Path/To/CycloneDDS/Installation/lib
- C:/Path/To/CycloneDDS/Installation/include
- C:/Path/To/CycloneDDS/Installation/share/CycloneDDS/idlc
-
-To run the example, Visual Studio should run both the publisher
-and subscriber simultaneously. It is capable of doing so, but
-it's not its default setting. To change it, open the HelloWorld
-solution property page by right clicking the solution and
-selecting :code:`Properties`. Then go to :code:`Common Properties`
--> :code:`Startup Project`, select :code:`Multiple startup project`
-and set :code:`Action "Start"` for HelloWorldPublisher and
-HelloWorldSubscriber. Finish the change by selecting :code:`OK`.
-
-Visual Studio is now ready to actually run the *Hello World!*
-example, which can be done by selecting :code:`Debug` ->
-:code:`Start without debugging`.
-Both the HelloworldSubscriber and the HelloworldPublisher will be
-started and the HelloworldPublisher will write a message that is
-received by the HelloworldSubscriber.
.. _`BuildingWithCMake`:
@@ -146,11 +54,6 @@ received by the HelloworldSubscriber.
Building With CMake
*******************
-In the earlier chapters, building the *Hello World!* example is done
-natively. However, the *Hello World!* example can also be build using the
-`CMake tool `_. This is what is recommended. In fact,
-all the other examples don't provide native makefiles, only CMake files.
-
.. _`CMakeIntro`:
@@ -190,10 +93,8 @@ scope of this document.
Hello World! CMake (CycloneDDS Package)
=======================================
-After the CMake digression, we're back with the *Hello World!*
-example. Apart from the native build files, CMake build files
-are provided as well. See
-:code:`examples/helloworld/CMakeLists.txt`
+Specifying how to build the *Hello World!* example requires only a few
+lines of configuration in :code:`examples/helloworld/CMakeLists.txt`
.. literalinclude:: ../../../examples/helloworld/CMakeLists.export
:linenos:
From 3a3fb64a356636e4180f4f64df164ab293b99826 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 18 Nov 2019 14:45:54 +0100
Subject: [PATCH 34/55] Fix casing of domain "Id" attribute in test config
(#283)
Signed-off-by: Erik Boasson
---
src/core/ddsc/tests/config_simple_udp.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/ddsc/tests/config_simple_udp.xml b/src/core/ddsc/tests/config_simple_udp.xml
index 9367f80..a0963d0 100644
--- a/src/core/ddsc/tests/config_simple_udp.xml
+++ b/src/core/ddsc/tests/config_simple_udp.xml
@@ -15,7 +15,7 @@
-
+
127.0.0.1
true
From 8849392c5e248513659ae559ac37e369bd35505e Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 10:15:28 +0100
Subject: [PATCH 35/55] Accept invalid pre-emptive ACKNACK from Connext
Connext (sometimes, for some versions?) sends a pre-emptive ACKNACK with
a base sequence number of 0, which were rejected following the DDSI
specification (8.3.4.1, 8.3.5.5 and 8.3.7.1.3). That doesn't really
help anyone. (https://github.com/ros2/ros2/issues/824)
Signed-off-by: Erik Boasson
---
src/core/ddsi/src/q_receive.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index 6f4b7a8..82b5953 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -130,9 +130,11 @@ static int valid_AckNack (const struct receiver_state *rst, AckNack_t *msg, size
/* Validation following 8.3.7.1.3 + 8.3.5.5 */
if (!valid_sequence_number_set (&msg->readerSNState))
{
- /* FastRTPS sends invalid pre-emptive ACKs -- patch the message so we can process it */
- if (! NN_STRICT_P (rst->gv->config) && vendor_is_eprosima (rst->vendor) &&
- fromSN (msg->readerSNState.bitmap_base) == 0 && msg->readerSNState.numbits == 0)
+ /* FastRTPS, Connext send invalid pre-emptive ACKs -- patch the message to
+ make it well-formed and process it as normal */
+ if (! NN_STRICT_P (rst->gv->config) &&
+ (fromSN (msg->readerSNState.bitmap_base) == 0 && msg->readerSNState.numbits == 0) &&
+ (vendor_is_eprosima (rst->vendor) || vendor_is_rti (rst->vendor)))
msg->readerSNState.bitmap_base = toSN (1);
else
return 0;
From 0426e4b3551103a577fd171c380d934ffa33526e Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 11:01:10 +0100
Subject: [PATCH 36/55] Delete unused CRC32 implementation
Signed-off-by: Erik Boasson
---
src/core/ddsi/include/dds/ddsi/q_config.h | 1 -
src/core/ddsi/include/dds/ddsi/q_misc.h | 2 -
src/core/ddsi/src/q_config.c | 5 --
src/core/ddsi/src/q_misc.c | 63 -----------------------
4 files changed, 71 deletions(-)
diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h
index e4cebcd..383ddb0 100644
--- a/src/core/ddsi/include/dds/ddsi/q_config.h
+++ b/src/core/ddsi/include/dds/ddsi/q_config.h
@@ -64,7 +64,6 @@ struct config_networkpartition_listelem {
char *address_string;
struct addrset *as;
int connected;
- uint32_t partitionHash;
uint32_t partitionId;
};
diff --git a/src/core/ddsi/include/dds/ddsi/q_misc.h b/src/core/ddsi/include/dds/ddsi/q_misc.h
index f410ebb..cb67ef5 100644
--- a/src/core/ddsi/include/dds/ddsi/q_misc.h
+++ b/src/core/ddsi/include/dds/ddsi/q_misc.h
@@ -37,8 +37,6 @@ int WildcardOverlap(char * p1, char * p2);
int ddsi2_patmatch (const char *pat, const char *str);
-uint32_t crc32_calc (const void *buf, size_t length);
-
#if defined (__cplusplus)
}
#endif
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 481c767..6443021 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -2822,12 +2822,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi
while (p)
{
cfgst->cfg->nof_networkPartitions++;
- /* also use crc32 just like native nw and ordinary ddsi2e, only
- for interoperability because it is asking for trouble &
- forces us to include a crc32 routine when we have md5
- available anyway */
p->partitionId = cfgst->cfg->nof_networkPartitions; /* starting at 1 */
- p->partitionHash = crc32_calc(p->name, strlen(p->name));
p = p->next;
}
}
diff --git a/src/core/ddsi/src/q_misc.c b/src/core/ddsi/src/q_misc.c
index 8569c01..f0b6df1 100644
--- a/src/core/ddsi/src/q_misc.c
+++ b/src/core/ddsi/src/q_misc.c
@@ -89,66 +89,3 @@ int ddsi2_patmatch (const char *pat, const char *str)
}
return *str == 0;
}
-
-
-static const uint32_t crc32_table[] = {
- 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
- 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
- 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
- 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
- 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
- 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
- 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
- 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
- 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
- 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
- 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
- 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
- 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
- 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
- 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
- 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
- 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
- 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
- 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
- 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
- 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
- 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
- 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
- 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
- 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
- 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
- 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
- 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
- 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
- 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
- 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
- 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
- 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
- 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
- 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
- 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
- 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
- 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
- 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
- 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
- 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
-};
-
-uint32_t crc32_calc (const void *buf, size_t length)
-{
- const uint8_t *vptr = buf;
- uint32_t reg = 0;
- uint8_t top;
- size_t i;
- for (i = 0; i < length; i++)
- {
- top = (uint8_t) (reg >> 24);
- top ^= *vptr;
- reg = (reg << 8) ^ crc32_table[top];
- vptr++;
- }
- return reg;
-}
From 8cbd67c32bd30e5bd3a58573795bbcceba669b38 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 14:01:34 +0100
Subject: [PATCH 37/55] Report failure from CUnit only on test failure
Non-automated mode too should allow running a subset of the tests
without reporting failure.
Signed-off-by: Erik Boasson
---
cmake/Modules/CUnit/src/main.c.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/cmake/Modules/CUnit/src/main.c.in b/cmake/Modules/CUnit/src/main.c.in
index a61ac85..9980a4c 100644
--- a/cmake/Modules/CUnit/src/main.c.in
+++ b/cmake/Modules/CUnit/src/main.c.in
@@ -222,6 +222,7 @@ int main(int argc, char *argv[])
}
CU_automated_run_tests();
} else {
+ CU_set_fail_on_inactive(0);
CU_basic_set_mode(opts.mode);
CU_basic_run_tests();
}
From 15179910d1e692e2a76ab057b4d3722020a98640 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 14:04:08 +0100
Subject: [PATCH 38/55] Write test fails to stdout/stderr even from ctest
Running tests while writing failed assertions to a text file means the
little information there is that causes test failures becomes pretty
much inaccessible on Travis. Sending the output to stdout/stderr means
it can be trivially shown for failed tests using the --output-on-failure
option of ctest.
Signed-off-by: Erik Boasson
---
cmake/Modules/CUnit.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cmake/Modules/CUnit.cmake b/cmake/Modules/CUnit.cmake
index ac63690..7453679 100644
--- a/cmake/Modules/CUnit.cmake
+++ b/cmake/Modules/CUnit.cmake
@@ -274,7 +274,7 @@ function(add_cunit_executable TARGET)
add_test(
NAME ${ctest}
- COMMAND ${TARGET} -a -r "${suite}-${test}" -s ${suite} -t ${test})
+ COMMAND ${TARGET} -s ${suite} -t ${test})
set_property(TEST ${ctest} PROPERTY TIMEOUT ${timeout})
set_property(TEST ${ctest} PROPERTY DISABLED ${disabled})
if(APPLE)
From 08d9c296f1b569c18188528fd5e8f086e94dd67d Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 21:25:17 +0100
Subject: [PATCH 39/55] Add DOMAIN_ID, DOMAIN_TAG to config, discovery
This commits adds support for the DOMAIN_ID and DOMAIN_TAG parameters in
participant discovery, allowing multiple domains to share a port
number (a feature introduced in DDSI 2.3). The tag can be configured
via Discovery/Tag.
This commit also introduces a setting Discovery/ExternalDomainId that
makes it possible to override the domain id on the network, both in what
is advertised in the DOMAIN_ID discovery parameter and in the
calculation of port numbers. This way a single process can create two
independent domains that talk via the network, which is on occassion
useful in writing tests.
Signed-off-by: Erik Boasson
---
docs/manual/options.md | 22 ++++++++++-
etc/cyclonedds.rnc | 15 ++++++++
etc/cyclonedds.xsd | 19 ++++++++++
.../ddsi/include/dds/ddsi/ddsi_portmapping.h | 6 ++-
src/core/ddsi/include/dds/ddsi/q_config.h | 2 +
src/core/ddsi/include/dds/ddsi/q_plist.h | 4 ++
src/core/ddsi/include/dds/ddsi/q_protocol.h | 2 +
src/core/ddsi/src/ddsi_portmapping.c | 8 ++--
src/core/ddsi/src/q_addrset.c | 4 +-
src/core/ddsi/src/q_config.c | 4 ++
src/core/ddsi/src/q_ddsi_discovery.c | 27 ++++++++++++-
src/core/ddsi/src/q_init.c | 38 +++++++++++--------
src/core/ddsi/src/q_plist.c | 12 ++----
13 files changed, 130 insertions(+), 33 deletions(-)
diff --git a/docs/manual/options.md b/docs/manual/options.md
index 6eed7ca..eab7449 100644
--- a/docs/manual/options.md
+++ b/docs/manual/options.md
@@ -101,7 +101,7 @@ The default value is: "lax".
### //CycloneDDS/Domain/Discovery
-Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress)
+Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [ExternalDomainId](#cycloneddsdomaindiscoveryexternaldomainid), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress), [Tag](#cycloneddsdomaindiscoverytag)
The Discovery element allows specifying various parameters related to the
@@ -140,6 +140,17 @@ Do not use.
The default value is: "true".
+#### //CycloneDDS/Domain/Discovery/ExternalDomainId
+Text
+
+An override for the domain id, to be used in discovery and for
+determining the port number mapping. This allows creating multiple
+domains in a single process while making them appear as a single domain
+on the network. The value "default" disables the override.
+
+The default value is: "default".
+
+
#### //CycloneDDS/Domain/Discovery/MaxAutoParticipantIndex
Integer
@@ -328,6 +339,15 @@ address.
The default value is: "239.255.0.1".
+#### //CycloneDDS/Domain/Discovery/Tag
+Text
+
+String extension for domain id that remote participants must match to be
+discovered.
+
+The default value is: "".
+
+
### //CycloneDDS/Domain/General
Children: [AllowMulticast](#cycloneddsdomaingeneralallowmulticast), [DontRoute](#cycloneddsdomaingeneraldontroute), [EnableMulticastLoopback](#cycloneddsdomaingeneralenablemulticastloopback), [ExternalNetworkAddress](#cycloneddsdomaingeneralexternalnetworkaddress), [ExternalNetworkMask](#cycloneddsdomaingeneralexternalnetworkmask), [FragmentSize](#cycloneddsdomaingeneralfragmentsize), [MaxMessageSize](#cycloneddsdomaingeneralmaxmessagesize), [MulticastRecvNetworkInterfaceAddresses](#cycloneddsdomaingeneralmulticastrecvnetworkinterfaceaddresses), [MulticastTimeToLive](#cycloneddsdomaingeneralmulticasttimetolive), [NetworkInterfaceAddress](#cycloneddsdomaingeneralnetworkinterfaceaddress), [PreferMulticast](#cycloneddsdomaingeneralprefermulticast), [Transport](#cycloneddsdomaingeneraltransport), [UseIPv6](#cycloneddsdomaingeneraluseipv6)
diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc
index 95bb3ce..19e6dcb 100644
--- a/etc/cyclonedds.rnc
+++ b/etc/cyclonedds.rnc
@@ -111,6 +111,15 @@ Discovery/SPDPMulticastAddress.The default value is:
xsd:boolean
}?
& [ a:documentation [ xml:lang="en" """
+
An override for the domain id, to be used in discovery and for
+determining the port number mapping. This allows creating multiple
+domains in a single process while making them appear as a single domain
+on the network. The value "default" disables the override.
The
+default value is: "default".
""" ] ]
+ element ExternalDomainId {
+ text
+ }?
+ & [ a:documentation [ xml:lang="en" """
This element specifies the maximum DDSI participant index selected by
this instance of the Cyclone DDS service if the
Discovery/ParticipantIndex is "auto".
The default value is:
@@ -257,6 +266,12 @@ address.
The default value is: "239.255.0.1".
""" ] ]
element SPDPMulticastAddress {
text
}?
+ & [ a:documentation [ xml:lang="en" """
+String extension for domain id that remote participants must match to
+be discovered.
The default value is: "".
""" ] ]
+ element Tag {
+ text
+ }?
}?
& [ a:documentation [ xml:lang="en" """
The General element specifies overall Cyclone DDS service
diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd
index 4ec63e5..867f95b 100644
--- a/etc/cyclonedds.xsd
+++ b/etc/cyclonedds.xsd
@@ -157,12 +157,14 @@ the discovery of peers.</p>
+
+
@@ -194,6 +196,16 @@ Discovery/SPDPMulticastAddress.</p><p>The default value is:
<p>Do not use.</p><p>The default value is: "true".</p>
+
+
+
+<p>An override for the domain id, to be used in discovery and for
+determining the port number mapping. This allows creating multiple
+domains in a single process while making them appear as a single domain
+on the network. The value "default" disables the override.</p><p>The
+default value is: "default".</p>
+
+
@@ -371,6 +383,13 @@ ff02::ffff:239.255.0.1, which is a non-standardised link-local multicast
address.</p><p>The default value is: "239.255.0.1".</p>
+
+
+
+<p>String extension for domain id that remote participants must match to
+be discovered.</p><p>The default value is: "".</p>
+
+
diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h b/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
index 0374672..573f19b 100644
--- a/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
+++ b/src/core/ddsi/include/dds/ddsi/ddsi_portmapping.h
@@ -37,8 +37,10 @@ struct ddsi_portmapping {
uint32_t d3;
};
-bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain_id, int32_t participant_index, char *msg, size_t msgsize);
-uint32_t ddsi_get_port (const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index);
+struct config;
+
+bool ddsi_valid_portmapping (const struct config *config, int32_t participant_index, char *msg, size_t msgsize);
+uint32_t ddsi_get_port (const struct config *config, enum ddsi_port which, int32_t participant_index);
#if defined (__cplusplus)
}
diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h
index 383ddb0..c20f2a4 100644
--- a/src/core/ddsi/include/dds/ddsi/q_config.h
+++ b/src/core/ddsi/include/dds/ddsi/q_config.h
@@ -196,6 +196,8 @@ struct config
int dontRoute;
int enableMulticastLoopback;
uint32_t domainId;
+ struct config_maybe_uint32 extDomainId; // domain id advertised in discovery
+ char *domainTag;
int participantIndex;
int maxAutoParticipantIndex;
char *spdpMulticastAddressString;
diff --git a/src/core/ddsi/include/dds/ddsi/q_plist.h b/src/core/ddsi/include/dds/ddsi/q_plist.h
index 4a9d6f3..3a0c20c 100644
--- a/src/core/ddsi/include/dds/ddsi/q_plist.h
+++ b/src/core/ddsi/include/dds/ddsi/q_plist.h
@@ -59,6 +59,8 @@ extern "C" {
/* Security extensions. */
#define PP_IDENTITY_TOKEN ((uint64_t)1 << 41)
#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 42)
+#define PP_DOMAIN_ID ((uint64_t)1 << 43)
+#define PP_DOMAIN_TAG ((uint64_t)1 << 44)
/* Set for unrecognized parameters that are in the reserved space or
in our own vendor-specific space that have the
PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */
@@ -162,6 +164,8 @@ typedef struct nn_plist {
#ifdef DDSI_INCLUDE_SSM
nn_reader_favours_ssm_t reader_favours_ssm;
#endif
+ uint32_t domain_id;
+ char *domain_tag;
} nn_plist_t;
diff --git a/src/core/ddsi/include/dds/ddsi/q_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h
index 93bda9a..54844f9 100644
--- a/src/core/ddsi/include/dds/ddsi/q_protocol.h
+++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h
@@ -330,6 +330,8 @@ DDSRT_WARNING_MSVC_ON(4200)
#define PID_PAD 0x0u
#define PID_SENTINEL 0x1u
+#define PID_DOMAIN_ID 0xfu
+#define PID_DOMAIN_TAG (0x14u | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)
#define PID_USER_DATA 0x2cu
#define PID_TOPIC_NAME 0x5u
#define PID_TYPE_NAME 0x7u
diff --git a/src/core/ddsi/src/ddsi_portmapping.c b/src/core/ddsi/src/ddsi_portmapping.c
index 164ebfe..a87b803 100644
--- a/src/core/ddsi/src/ddsi_portmapping.c
+++ b/src/core/ddsi/src/ddsi_portmapping.c
@@ -89,7 +89,7 @@ static const char *portname (enum ddsi_port which)
return n;
}
-bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain_id, int32_t participant_index, char *msg, size_t msgsize)
+bool ddsi_valid_portmapping (const struct config *config, int32_t participant_index, char *msg, size_t msgsize)
{
DDSRT_STATIC_ASSERT (DDSI_PORT_MULTI_DISC >= 0 &&
DDSI_PORT_MULTI_DISC + 1 == DDSI_PORT_MULTI_DATA &&
@@ -103,7 +103,7 @@ bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain
int n = snprintf (msg, msgsize, "port number(s) of out range:");
size_t pos = (n >= 0 && (size_t) n <= msgsize) ? (size_t) n : msgsize;
do {
- if (!get_port_int (&dummy_port, map, which, domain_id, participant_index, str, sizeof (str)))
+ if (!get_port_int (&dummy_port, &config->ports, which, config->extDomainId.value, participant_index, str, sizeof (str)))
{
n = snprintf (msg + pos, msgsize - pos, "%s %s %s", ok ? "" : ",", portname (which), str);
if (n >= 0 && (size_t) n <= msgsize - pos)
@@ -114,12 +114,12 @@ bool ddsi_valid_portmapping (const struct ddsi_portmapping *map, uint32_t domain
return ok;
}
-uint32_t ddsi_get_port (const struct ddsi_portmapping *map, enum ddsi_port which, uint32_t domain_id, int32_t participant_index)
+uint32_t ddsi_get_port (const struct config *config, enum ddsi_port which, int32_t participant_index)
{
/* Not supposed to come here if port mapping is invalid */
uint32_t port;
char str[32];
- bool ok = get_port_int (&port, map, which, domain_id, participant_index, str, sizeof (str));
+ bool ok = get_port_int (&port, &config->ports, which, config->extDomainId.value, participant_index, str, sizeof (str));
assert (ok);
(void) ok;
return port;
diff --git a/src/core/ddsi/src/q_addrset.c b/src/core/ddsi/src/q_addrset.c
index 7bc6d59..0d557e7 100644
--- a/src/core/ddsi/src/q_addrset.c
+++ b/src/core/ddsi/src/q_addrset.c
@@ -105,7 +105,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse
assert (gv->config.maxAutoParticipantIndex >= 0);
for (int32_t i = 0; i <= gv->config.maxAutoParticipantIndex; i++)
{
- loc.port = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DISC, gv->config.domainId, i);
+ loc.port = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, i);
if (i == 0)
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
else
@@ -116,7 +116,7 @@ static int add_addresses_to_addrset_1 (const struct q_globals *gv, struct addrse
else
{
if (port_mode == -1)
- loc.port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
+ loc.port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
else
loc.port = (uint32_t) port_mode;
GVLOG (DDS_LC_CONFIG, "%s", ddsi_locator_to_string(gv, buf, sizeof(buf), &loc));
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 6443021..3993283 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -697,6 +697,10 @@ static const struct cfgelem discovery_peers_cfgelems[] = {
};
static const struct cfgelem discovery_cfgelems[] = {
+ { LEAF("Tag"), 0, "", ABSOFF(domainTag), 0, uf_string, ff_free, pf_string,
+ BLURB("String extension for domain id that remote participants must match to be discovered.
") },
+ { LEAF ("ExternalDomainId"), 1, "default", ABSOFF (extDomainId), 0, uf_maybe_int32, 0, pf_maybe_int32,
+ BLURB("An override for the domain id, to be used in discovery and for determining the port number mapping. This allows creating multiple domains in a single process while making them appear as a single domain on the network. The value \"default\" disables the override.
") },
{ LEAF("DSGracePeriod"), 1, "30 s", ABSOFF(ds_grace_period), 0, uf_duration_inf, 0, pf_duration,
BLURB("This setting controls for how long endpoints discovered via a Cloud discovery service will survive after the discovery service disappeared, allowing reconnect without loss of data when the discovery service restarts (or another instance takes over).
") },
{ GROUP("Peers", discovery_peers_cfgelems),
diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c
index 74d025a..45b3e9e 100644
--- a/src/core/ddsi/src/q_ddsi_discovery.c
+++ b/src/core/ddsi/src/q_ddsi_discovery.c
@@ -216,12 +216,25 @@ int spdp_write (struct participant *pp)
nn_plist_init_empty (&ps);
ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET |
- PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION;
+ PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION |
+ PP_DOMAIN_ID;
ps.participant_guid = pp->e.guid;
ps.builtin_endpoint_set = pp->bes;
ps.protocol_version.major = RTPS_MAJOR;
ps.protocol_version.minor = RTPS_MINOR;
ps.vendorid = NN_VENDORID_ECLIPSE;
+ ps.domain_id = pp->e.gv->config.extDomainId.value;
+ /* Be sure not to send a DOMAIN_TAG when it is the default (an empty)
+ string: it is an "incompatible-if-unrecognized" parameter, and so
+ implementations that don't understand the parameter will refuse to
+ discover us, and so sending the default would break backwards
+ compatibility. */
+ if (strcmp (pp->e.gv->config.domainTag, "") != 0)
+ {
+ ps.present |= PP_DOMAIN_TAG;
+ ps.aliased |= PP_DOMAIN_TAG;
+ ps.domain_tag = pp->e.gv->config.domainTag;
+ }
if (pp->prismtech_bes)
{
ps.present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET;
@@ -520,6 +533,18 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
dds_duration_t lease_duration;
unsigned custom_flags = 0;
+ /* If advertised domain id or domain tag doesn't match, ignore the message. Do this first to
+ minimize the impact such messages have. */
+ {
+ const uint32_t domain_id = (datap->present & PP_DOMAIN_ID) ? datap->domain_id : gv->config.extDomainId.value;
+ const char *domain_tag = (datap->present & PP_DOMAIN_TAG) ? datap->domain_tag : "";
+ if (domain_id != gv->config.extDomainId.value || strcmp (domain_tag, gv->config.domainTag) != 0)
+ {
+ GVTRACE ("ignore remote participant in mismatching domain %"PRIu32" tag \"%s\"\n", domain_id, domain_tag);
+ return 0;
+ }
+ }
+
if (!(datap->present & PP_PARTICIPANT_GUID) || !(datap->present & PP_BUILTIN_ENDPOINT_SET))
{
GVWARNING ("data (SPDP, vendor %u.%u): no/invalid payload\n", rst->vendor.id[0], rst->vendor.id[1]);
diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c
index 04d94ba..17cc553 100644
--- a/src/core/ddsi/src/q_init.c
+++ b/src/core/ddsi/src/q_init.c
@@ -82,7 +82,7 @@ static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t
if (gv->config.many_sockets_mode == MSM_NO_UNICAST)
{
assert (ppid == PARTICIPANT_INDEX_NONE);
- *pdata = *pdisc = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, ppid);
+ *pdata = *pdisc = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, ppid);
if (gv->config.allowMulticast)
{
/* FIXME: ugly hack - but we'll fix up after creating the multicast sockets */
@@ -90,8 +90,8 @@ static enum make_uc_sockets_ret make_uc_sockets (struct q_globals *gv, uint32_t
}
}
- *pdisc = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DISC, gv->config.domainId, ppid);
- *pdata = ddsi_get_port (&gv->config.ports, DDSI_PORT_UNI_DATA, gv->config.domainId, ppid);
+ *pdisc = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DISC, ppid);
+ *pdata = ddsi_get_port (&gv->config, DDSI_PORT_UNI_DATA, ppid);
if (!ddsi_is_valid_port (gv->m_factory, *pdisc) || !ddsi_is_valid_port (gv->m_factory, *pdata))
return MUSRET_INVALID_PORTS;
@@ -279,7 +279,7 @@ static int string_to_default_locator (const struct q_globals *gv, nn_locator_t *
static int set_spdp_address (struct q_globals *gv)
{
- const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
+ const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
int rc = 0;
/* FIXME: FIXME: FIXME: */
gv->loc_spdp_mc.kind = NN_LOCATOR_KIND_INVALID;
@@ -311,7 +311,7 @@ static int set_spdp_address (struct q_globals *gv)
static int set_default_mc_address (struct q_globals *gv)
{
- const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
+ const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
int rc;
if (!gv->config.defaultMulticastAddressString)
gv->loc_default_mc = gv->loc_spdp_mc;
@@ -452,6 +452,14 @@ int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst)
unsigned num_channel_threads = 0;
#endif
+ /* advertised domain id defaults to the real domain id; clear "isdefault" so the config
+ dump includes the actually used value rather than "default" */
+ if (gv->config.extDomainId.isdefault)
+ {
+ gv->config.extDomainId.value = gv->config.domainId;
+ gv->config.extDomainId.isdefault = 0;
+ }
+
{
char message[256];
int32_t ppidx;
@@ -464,7 +472,7 @@ int rtps_config_prep (struct q_globals *gv, struct cfgst *cfgst)
assert (0);
ppidx = 0;
}
- if (!ddsi_valid_portmapping (&gv->config.ports, gv->config.domainId, ppidx, message, sizeof (message)))
+ if (!ddsi_valid_portmapping (&gv->config, ppidx, message, sizeof (message)))
{
DDS_ILOG (DDS_LC_ERROR, gv->config.domainId, "Invalid port mapping: %s\n", message);
goto err_config_late_error;
@@ -658,11 +666,11 @@ int create_multicast_sockets (struct q_globals *gv)
uint32_t port;
qos->m_multicast = 1;
- port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DISC, gv->config.domainId, 0);
+ port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DISC, 0);
if (!ddsi_is_valid_port (gv->m_factory, port))
{
GVERROR ("Failed to create discovery multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
- gv->config.domainId, port);
+ gv->config.extDomainId.value, port);
goto err_disc;
}
if ((disc = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
@@ -674,11 +682,11 @@ int create_multicast_sockets (struct q_globals *gv)
}
else
{
- port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
+ port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
if (!ddsi_is_valid_port (gv->m_factory, port))
{
GVERROR ("Failed to create data multicast socket for domain %"PRIu32": resulting port number (%"PRIu32") is out of range\n",
- gv->config.domainId, port);
+ gv->config.extDomainId.value, port);
goto err_disc;
}
if ((data = ddsi_factory_create_conn (gv->m_factory, port, qos)) == NULL)
@@ -1005,7 +1013,7 @@ int rtps_init (struct q_globals *gv)
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
/* Convert address sets in partition mappings from string to address sets */
{
- const uint32_t port = ddsi_get_port (&gv->config.ports, DDSI_PORT_MULTI_DATA, gv->config.domainId, 0);
+ const uint32_t port = ddsi_get_port (&gv->config, DDSI_PORT_MULTI_DATA, 0);
struct config_networkpartition_listelem *np;
for (np = gv->config.networkPartitions; np; np = np->next)
{
@@ -1102,10 +1110,10 @@ int rtps_init (struct q_globals *gv)
break;
case MUSRET_INVALID_PORTS:
GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
- gv->config.domainId, gv->config.participantIndex, port_disc_uc, port_data_uc);
+ gv->config.extDomainId.value, gv->config.participantIndex, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
case MUSRET_NOSOCKET:
- GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant index %d (ports %"PRIu32", %"PRIu32")\n", gv->config.domainId, gv->config.participantIndex, port_disc_uc, port_data_uc);
+ GVERROR ("rtps_init: failed to create unicast sockets for domain %"PRId32" participant index %d (ports %"PRIu32", %"PRIu32")\n", gv->config.extDomainId.value, gv->config.participantIndex, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
}
}
@@ -1124,7 +1132,7 @@ int rtps_init (struct q_globals *gv)
break;
case MUSRET_INVALID_PORTS:
GVERROR ("Failed to create unicast sockets for domain %"PRIu32" participant index %d: resulting port numbers (%"PRIu32", %"PRIu32") are out of range\n",
- gv->config.domainId, ppid, port_disc_uc, port_data_uc);
+ gv->config.extDomainId.value, ppid, port_disc_uc, port_data_uc);
goto err_unicast_sockets;
case MUSRET_NOSOCKET: /* Try next one */
break;
@@ -1132,7 +1140,7 @@ int rtps_init (struct q_globals *gv)
}
if (ppid > gv->config.maxAutoParticipantIndex)
{
- GVERROR ("Failed to find a free participant index for domain %"PRIu32"\n", gv->config.domainId);
+ GVERROR ("Failed to find a free participant index for domain %"PRIu32"\n", gv->config.extDomainId.value);
goto err_unicast_sockets;
}
gv->config.participantIndex = ppid;
diff --git a/src/core/ddsi/src/q_plist.c b/src/core/ddsi/src/q_plist.c
index b11931e..6571c3f 100644
--- a/src/core/ddsi/src/q_plist.c
+++ b/src/core/ddsi/src/q_plist.c
@@ -1173,6 +1173,8 @@ static const struct piddesc piddesc_omg[] = {
#ifdef DDSI_INCLUDE_SSM
PPV (READER_FAVOURS_SSM, reader_favours_ssm, Xu),
#endif
+ PP (DOMAIN_ID, domain_id, Xu),
+ PP (DOMAIN_TAG, domain_tag, XS),
{ PID_STATUSINFO, PDF_FUNCTION, PP_STATUSINFO, "STATUSINFO",
offsetof (struct nn_plist, statusinfo), membersize (struct nn_plist, statusinfo),
{ .f = { .deser = deser_statusinfo, .ser = ser_statusinfo } }, 0 },
@@ -1318,8 +1320,8 @@ static const struct piddesc_index piddesc_vendor_index[] = {
/* List of entries that require unalias, fini processing;
initialized by nn_plist_init_tables; will assert when
table too small or too large */
-static const struct piddesc *piddesc_unalias[19];
-static const struct piddesc *piddesc_fini[19];
+static const struct piddesc *piddesc_unalias[20];
+static const struct piddesc *piddesc_fini[20];
static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT;
static nn_parameterid_t pid_without_flags (nn_parameterid_t pid)
@@ -2098,13 +2100,7 @@ static dds_return_t init_one_parameter (nn_plist_t *plist, nn_ipaddress_params_t
return return_unrecognized_pid (plist, pid);
assert (pid_without_flags (pid) == pid_without_flags (entry->pid));
if (pid != entry->pid)
- {
- DDS_CERROR (logcfg, "error processing parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" mapped to pid %"PRIx16"\n",
- dd->vendorid.id[0], dd->vendorid.id[1],
- dd->protocol_version.major, dd->protocol_version.minor,
- pid, entry->pid);
return return_unrecognized_pid (plist, pid);
- }
assert (pid != PID_PAD);
struct flagset flagset;
From c84c69e551e7b63a80c28a52a2a9e31a1d2d6ac6 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Tue, 19 Nov 2019 15:08:43 +0100
Subject: [PATCH 40/55] Bump version number to 0.5 prior to release
Signed-off-by: Erik Boasson
---
CMakeLists.txt | 2 +-
docs/manual/config.rst | 18 ------------------
src/core/CMakeLists.txt | 3 ++-
3 files changed, 3 insertions(+), 20 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b679c09..3180abb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
cmake_minimum_required(VERSION 3.7)
-project(CycloneDDS VERSION 0.1.0)
+project(CycloneDDS VERSION 0.5.0)
# Set a default build type if none was specified
set(default_build_type "RelWithDebInfo")
diff --git a/docs/manual/config.rst b/docs/manual/config.rst
index bd8b182..50a3244 100644
--- a/docs/manual/config.rst
+++ b/docs/manual/config.rst
@@ -1110,21 +1110,3 @@ an endless loop.
There is furthermore also a difference of interpretation of the meaning of the
‘autodispose_unregistered_instances’ QoS on the writer. Eclipse Cyclone DDS aligns with
OpenSplice.
-
-
-.. _`Compatibility issues with TwinOaks`:
-
-Compatibility issues with TwinOaks
-----------------------------------
-
-In the default configuration there should be no interoperability issues with TwinOaks CoreDX,
-although there is the aforementioned difference in interpretation of the meaning of the
-‘autodispose_unregistered_instances’ QoS on the writer.
-
-Interoperability with very old versions of CoreDX may require setting:
-
-+ ``Compatibility/ManySocketsMode``: *true*
-+ ``Compatibility/ExplicitlyPublishQosSetToDefault``: *true*
-
-The exact version number of CoreDX starting with which these settings are no longer needed is
-unknown, but it has certainly not been needed for several years.
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 46506aa..e2edb53 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -94,7 +94,8 @@ if(BUILD_DOCS)
"__attribute__="
"__declspec(x)="
"DDS_EXPORT="
- "DDS_DEPRECATED_EXPORT=")
+ "DDS_DEPRECATED_EXPORT="
+ "DDSRT_STATIC_ASSERT(x)=")
find_package(Doxygen REQUIRED)
doxygen_add_docs(ddsc_api_docs "ddsc/include")
endif()
From 9a3a37732781456a04d6fb9a28384dff2bb5d8ab Mon Sep 17 00:00:00 2001
From: Bart Poot
Date: Tue, 5 Nov 2019 10:46:04 +0100
Subject: [PATCH 41/55] Fixed coverity issues
Signed-off-by: Bart Poot
Processed review comments
Signed-off-by: Bart Poot
---
examples/throughput/subscriber.c | 12 +-
src/core/ddsc/src/dds_instance.c | 4 +-
src/core/ddsc/src/dds_reader.c | 1 +
src/core/ddsc/src/dds_rhc_default.c | 4 +-
src/core/ddsc/src/dds_stream.c | 83 +++++------
src/core/ddsi/include/dds/ddsi/q_radmin.h | 2 +-
src/core/ddsi/src/ddsi_ipaddr.c | 2 +-
src/core/ddsi/src/ddsi_mcgroup.c | 2 +-
src/core/ddsi/src/ddsi_raweth.c | 18 +--
src/core/ddsi/src/ddsi_tran.c | 4 +-
src/core/ddsi/src/ddsi_udp.c | 2 +-
src/core/ddsi/src/q_config.c | 18 +--
src/core/ddsi/src/q_ddsi_discovery.c | 4 +-
src/core/ddsi/src/q_debmon.c | 3 +-
src/core/ddsi/src/q_entity.c | 14 +-
src/core/ddsi/src/q_gc.c | 2 +-
src/core/ddsi/src/q_init.c | 5 +-
src/core/ddsi/src/q_lease.c | 4 +-
src/core/ddsi/src/q_nwif.c | 4 +-
src/core/ddsi/src/q_pcap.c | 18 +--
src/core/ddsi/src/q_radmin.c | 4 +-
src/core/ddsi/src/q_receive.c | 7 +-
src/core/ddsi/src/q_sockwaitset.c | 4 +-
src/core/ddsi/src/q_thread.c | 2 +-
src/core/ddsi/src/q_transmit.c | 2 +-
src/core/ddsi/src/q_xevent.c | 14 +-
src/core/ddsi/src/q_xmsg.c | 5 +-
src/core/xtests/rhc_torture/rhc_torture.c | 4 +-
src/ddsrt/src/expand_envvars.c | 4 +-
src/ddsrt/src/ifaddrs/posix/ifaddrs.c | 2 +-
src/ddsrt/src/log.c | 2 +-
src/ddsrt/src/process/posix/process.c | 14 +-
src/ddsrt/src/rusage/posix/rusage.c | 2 +-
src/ddsrt/src/threads/posix/threads.c | 2 +-
src/ddsrt/src/threads/windows/threads.c | 2 +-
src/ddsrt/src/xmlparser.c | 10 +-
src/ddsrt/tests/log.c | 4 +-
src/ddsrt/tests/socket.c | 2 +-
src/tools/ddsls/ddsls.c | 12 +-
src/tools/ddsperf/cputime.c | 2 +-
src/tools/ddsperf/ddsperf.c | 2 +-
src/tools/pubsub/pubsub.c | 168 +---------------------
42 files changed, 168 insertions(+), 308 deletions(-)
diff --git a/examples/throughput/subscriber.c b/examples/throughput/subscriber.c
index 92560b6..e4c754f 100644
--- a/examples/throughput/subscriber.c
+++ b/examples/throughput/subscriber.c
@@ -93,7 +93,7 @@ int main (int argc, char **argv)
signal (SIGINT, sigint);
process_samples(reader, maxCycles);
- dds_set_status_mask (reader, 0);
+ (void) dds_set_status_mask (reader, 0);
HandleMap__free (imap);
finalize_dds (participant);
return EXIT_SUCCESS;
@@ -154,7 +154,7 @@ static HandleEntry * retrieve_handle (HandleMap *map, dds_instance_handle_t key)
static int do_take (dds_entity_t reader)
{
int samples_received;
- dds_sample_info_t info [MAX_SAMPLES];
+ dds_sample_info_t *info = NULL;
dds_instance_handle_t ph = 0;
HandleEntry * current = NULL;
@@ -165,9 +165,14 @@ static int do_take (dds_entity_t reader)
/* Take samples and iterate through them */
+ info = dds_alloc (sizeof(dds_sample_info_t) * MAX_SAMPLES);
+
samples_received = dds_take (reader, samples, info, MAX_SAMPLES, MAX_SAMPLES);
if (samples_received < 0)
+ {
+ dds_free( info );
DDS_FATAL("dds_take: %s\n", dds_strretcode(-samples_received));
+ }
for (int i = 0; !done && i < samples_received; i++)
{
@@ -196,13 +201,14 @@ static int do_take (dds_entity_t reader)
total_samples++;
}
}
+ dds_free (info);
return samples_received;
}
static void data_available_handler (dds_entity_t reader, void *arg)
{
(void)arg;
- do_take (reader);
+ (void) do_take (reader);
}
static int parse_args(int argc, char **argv, unsigned long long *maxCycles, char **partitionName)
diff --git a/src/core/ddsc/src/dds_instance.c b/src/core/ddsc/src/dds_instance.c
index 3104485..74c2089 100644
--- a/src/core/ddsc/src/dds_instance.c
+++ b/src/core/ddsc/src/dds_instance.c
@@ -113,7 +113,7 @@ dds_return_t dds_unregister_instance_ts (dds_entity_t writer, const void *data,
return ret;
if (wr->m_entity.m_qos)
- dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
+ (void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
if (autodispose)
@@ -140,7 +140,7 @@ dds_return_t dds_unregister_instance_ih_ts (dds_entity_t writer, dds_instance_ha
return ret;
if (wr->m_entity.m_qos)
- dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
+ (void) dds_qget_writer_data_lifecycle (wr->m_entity.m_qos, &autodispose);
thread_state_awake (ts1, &wr->m_entity.m_domain->gv);
if (autodispose)
diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c
index 22e118b..d754f10 100644
--- a/src/core/ddsc/src/dds_reader.c
+++ b/src/core/ddsc/src/dds_reader.c
@@ -150,6 +150,7 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
rd->m_entity.m_cb_count--;
rd->m_entity.m_cb_pending_count--;
+
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
}
diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c
index dee3eb6..9f84ec3 100644
--- a/src/core/ddsc/src/dds_rhc_default.c
+++ b/src/core/ddsc/src/dds_rhc_default.c
@@ -1110,7 +1110,7 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
if (inst->wrcount == 2 && inst->wr_iid_islive && inst->wr_iid != wr_iid)
{
TRACE (",delreg(remain)");
- lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
+ (void) lwregs_delete (&rhc->registrations, inst->iid, inst->wr_iid);
}
return 1;
}
@@ -1627,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
}
}
- dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
+ (void) dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
TRACE ("\n");
diff --git a/src/core/ddsc/src/dds_stream.c b/src/core/ddsc/src/dds_stream.c
index 9be8810..e020735 100644
--- a/src/core/ddsc/src/dds_stream.c
+++ b/src/core/ddsc/src/dds_stream.c
@@ -256,24 +256,25 @@ size_t dds_stream_check_optimize (const dds_topic_descriptor_t * __restrict desc
return dds_stream_check_optimize1 (desc);
}
-static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
+static void dds_stream_reuse_string_bound (dds_istream_t * __restrict is, char * __restrict str, const uint32_t bound)
{
const uint32_t length = dds_is_get4 (is);
const void *src = is->m_buffer + is->m_index;
- if (bound)
- {
- /* FIXME: validation now rejects data containing an oversize bounded string,
- so this check is superfluous, but perhaps rejecting such a sample is the
- wrong thing to do */
- assert (str != NULL);
- memcpy (str, src, length > bound ? bound : length);
- }
- else
- {
- if (str == NULL || strlen (str) + 1 < length)
- str = dds_realloc (str, length);
- memcpy (str, src, length);
- }
+ /* FIXME: validation now rejects data containing an oversize bounded string,
+ so this check is superfluous, but perhaps rejecting such a sample is the
+ wrong thing to do */
+ assert (str != NULL);
+ memcpy (str, src, length > bound ? bound : length);
+ is->m_index += length;
+}
+
+static char *dds_stream_reuse_string (dds_istream_t * __restrict is, char * __restrict str)
+{
+ const uint32_t length = dds_is_get4 (is);
+ const void *src = is->m_buffer + is->m_index;
+ if (str == NULL || strlen (str) + 1 < length)
+ str = dds_realloc (str, length);
+ memcpy (str, src, length);
is->m_index += length;
return str;
}
@@ -596,7 +597,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
char **ptr = (char **) seq->_buffer;
for (uint32_t i = 0; i < seq->_length; i++)
- ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
+ ptr[i] = dds_stream_reuse_string (is, ptr[i]);
for (uint32_t i = seq->_length; i < num; i++)
dds_stream_skip_string (is);
return ops + 2;
@@ -607,7 +608,7 @@ static const uint32_t *dds_stream_read_seq (dds_istream_t * __restrict is, char
seq->_length = (num <= seq->_maximum) ? num : seq->_maximum;
char *ptr = (char *) seq->_buffer;
for (uint32_t i = 0; i < seq->_length; i++)
- (void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
+ dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
for (uint32_t i = seq->_length; i < num; i++)
dds_stream_skip_string (is);
return ops + 3;
@@ -641,14 +642,14 @@ static const uint32_t *dds_stream_read_arr (dds_istream_t * __restrict is, char
case DDS_OP_VAL_STR: {
char **ptr = (char **) addr;
for (uint32_t i = 0; i < num; i++)
- ptr[i] = dds_stream_reuse_string (is, ptr[i], 0);
+ ptr[i] = dds_stream_reuse_string (is, ptr[i]);
return ops + 3;
}
case DDS_OP_VAL_BST: {
char *ptr = (char *) addr;
const uint32_t elem_size = ops[4];
for (uint32_t i = 0; i < num; i++)
- (void) dds_stream_reuse_string (is, ptr + i * elem_size, elem_size);
+ dds_stream_reuse_string_bound (is, ptr + i * elem_size, elem_size);
return ops + 5;
}
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
@@ -685,7 +686,7 @@ static const uint32_t *dds_stream_read_uni (dds_istream_t * __restrict is, char
case DDS_OP_VAL_2BY: *((uint16_t *) valaddr) = dds_is_get2 (is); break;
case DDS_OP_VAL_4BY: *((uint32_t *) valaddr) = dds_is_get4 (is); break;
case DDS_OP_VAL_8BY: *((uint64_t *) valaddr) = dds_is_get8 (is); break;
- case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr), 0); break;
+ case DDS_OP_VAL_STR: *(char **) valaddr = dds_stream_reuse_string (is, *((char **) valaddr)); break;
case DDS_OP_VAL_BST: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
dds_stream_read (is, valaddr, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]));
break;
@@ -709,8 +710,8 @@ static void dds_stream_read (dds_istream_t * __restrict is, char * __restrict da
case DDS_OP_VAL_2BY: *((uint16_t *) addr) = dds_is_get2 (is); ops += 2; break;
case DDS_OP_VAL_4BY: *((uint32_t *) addr) = dds_is_get4 (is); ops += 2; break;
case DDS_OP_VAL_8BY: *((uint64_t *) addr) = dds_is_get8 (is); ops += 2; break;
- case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr), 0); ops += 2; break;
- case DDS_OP_VAL_BST: dds_stream_reuse_string (is, (char *) addr, ops[2]); ops += 3; break;
+ case DDS_OP_VAL_STR: *((char **) addr) = dds_stream_reuse_string (is, *((char **) addr)); ops += 2; break;
+ case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, (char *) addr, ops[2]); ops += 3; break;
case DDS_OP_VAL_SEQ: ops = dds_stream_read_seq (is, addr, ops, insn); break;
case DDS_OP_VAL_ARR: ops = dds_stream_read_arr (is, addr, ops, insn); break;
case DDS_OP_VAL_UNI: ops = dds_stream_read_uni (is, addr, data, ops, insn); break;
@@ -1126,8 +1127,8 @@ void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sampl
case DDS_OP_VAL_2BY: *((uint16_t *) dst) = dds_is_get2 (is); break;
case DDS_OP_VAL_4BY: *((uint32_t *) dst) = dds_is_get4 (is); break;
case DDS_OP_VAL_8BY: *((uint64_t *) dst) = dds_is_get8 (is); break;
- case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst), 0); break;
- case DDS_OP_VAL_BST: dds_stream_reuse_string (is, dst, op[2]); break;
+ case DDS_OP_VAL_STR: *((char **) dst) = dds_stream_reuse_string (is, *((char **) dst)); break;
+ case DDS_OP_VAL_BST: dds_stream_reuse_string_bound (is, dst, op[2]); break;
case DDS_OP_VAL_ARR:
dds_is_get_bytes (is, dst, op[2], get_type_size (DDS_OP_SUBTYPE (*op)));
break;
@@ -1728,16 +1729,16 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
num = dds_is_get4 (is);
if (num == 0)
{
- prtf (buf, bufsize, "{}");
+ (void) prtf (buf, bufsize, "{}");
return skip_sequence_insns (ops, insn);
}
switch (subtype)
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
- prtf_simple_array (buf, bufsize, is, num, subtype);
+ (void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + 2;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
- prtf_simple_array (buf, bufsize, is, num, subtype);
+ (void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3);
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
@@ -1745,10 +1746,10 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
- if (i > 0) prtf (buf, bufsize, ",");
+ if (i > 0) (void) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
- prtf (buf, bufsize, "}");
+ (void) prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
}
}
@@ -1762,10 +1763,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
switch (subtype)
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
- prtf_simple_array (buf, bufsize, is, num, subtype);
+ (void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + 3;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
- prtf_simple_array (buf, bufsize, is, num, subtype);
+ (void) prtf_simple_array (buf, bufsize, is, num, subtype);
return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5);
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: {
const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
@@ -1773,10 +1774,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
- if (i > 0) prtf (buf, bufsize, ",");
+ if (i > 0) (void) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
- prtf (buf, bufsize, "}");
+ (void) prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 5);
}
}
@@ -1787,7 +1788,7 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
{
const uint32_t disc = read_union_discriminant (is, DDS_OP_SUBTYPE (insn));
uint32_t const * const jeq_op = find_union_case (ops, disc);
- prtf (buf, bufsize, "%"PRIu32":", disc);
+ (void) prtf (buf, bufsize, "%"PRIu32":", disc);
ops += DDS_OP_ADR_JMP (ops[3]);
if (jeq_op)
{
@@ -1796,10 +1797,10 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is
{
case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY:
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
- prtf_simple (buf, bufsize, is, valtype);
+ (void) prtf_simple (buf, bufsize, is, valtype);
break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
- dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
+ (void) dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU);
break;
}
}
@@ -1812,11 +1813,11 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
bool cont = true;
bool needs_comma = false;
if (add_braces)
- prtf (buf, bufsize, "{");
+ (void) prtf (buf, bufsize, "{");
while (cont && (insn = *ops) != DDS_OP_RTS)
{
if (needs_comma)
- prtf (buf, bufsize, ",");
+ (void) prtf (buf, bufsize, ",");
needs_comma = true;
switch (DDS_OP (insn))
{
@@ -1859,13 +1860,13 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric
}
}
if (add_braces)
- prtf (buf, bufsize, "}");
+ (void) prtf (buf, bufsize, "}");
return cont;
}
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
{
- dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
+ (void) dds_stream_print_sample1 (&buf, &bufsize, is, topic->type->m_ops, true);
return bufsize;
}
@@ -1891,7 +1892,7 @@ size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_se
break;
}
}
- prtf (&buf, &bufsize, "}");
+ (void) prtf (&buf, &bufsize, "}");
return bufsize;
}
diff --git a/src/core/ddsi/include/dds/ddsi/q_radmin.h b/src/core/ddsi/include/dds/ddsi/q_radmin.h
index 61814bf..f3d4a2d 100644
--- a/src/core/ddsi/include/dds/ddsi/q_radmin.h
+++ b/src/core/ddsi/include/dds/ddsi/q_radmin.h
@@ -98,7 +98,7 @@ struct nn_rmsg {
struct nn_rmsg_chunk chunk;
};
-#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (&(m)->chunk + 1))
+#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (m + 1))
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
struct receiver_state {
diff --git a/src/core/ddsi/src/ddsi_ipaddr.c b/src/core/ddsi/src/ddsi_ipaddr.c
index 4b33048..f939816 100644
--- a/src/core/ddsi/src/ddsi_ipaddr.c
+++ b/src/core/ddsi/src/ddsi_ipaddr.c
@@ -123,7 +123,7 @@ char *ddsi_ipaddr_to_string (ddsi_tran_factory_t tran, char *dst, size_t sizeof_
(void)tran;
assert (sizeof_dst > 1);
if (loc->kind == NN_LOCATOR_KIND_INVALID)
- snprintf (dst, sizeof_dst, "(invalid)");
+ (void) snprintf (dst, sizeof_dst, "(invalid)");
else
{
struct sockaddr_storage src;
diff --git a/src/core/ddsi/src/ddsi_mcgroup.c b/src/core/ddsi/src/ddsi_mcgroup.c
index 0728c7c..a956ce1 100644
--- a/src/core/ddsi/src/ddsi_mcgroup.c
+++ b/src/core/ddsi/src/ddsi_mcgroup.c
@@ -148,7 +148,7 @@ static char *make_joinleave_msg (char *buf, size_t bufsz, ddsi_tran_conn_t conn,
(void) snprintf (interfstr, sizeof (interfstr), "(default)");
n = err ? snprintf (buf, bufsz, "error %d in ", err) : 0;
if ((size_t) n < bufsz)
- snprintf (buf + n, bufsz - (size_t) n, "%s conn %p for (%s, %s) interface %s", join ? "join" : "leave", (void *) conn, mcstr, srcstr, interfstr);
+ (void) snprintf (buf + n, bufsz - (size_t) n, "%s conn %p for (%s, %s) interface %s", join ? "join" : "leave", (void *) conn, mcstr, srcstr, interfstr);
return buf;
}
diff --git a/src/core/ddsi/src/ddsi_raweth.c b/src/core/ddsi/src/ddsi_raweth.c
index 153fcf7..e3454f9 100644
--- a/src/core/ddsi/src/ddsi_raweth.c
+++ b/src/core/ddsi/src/ddsi_raweth.c
@@ -42,13 +42,13 @@ static char *ddsi_raweth_to_string (ddsi_tran_factory_t tran, char *dst, size_t
{
(void)tran;
if (with_port)
- snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
- loc->address[10], loc->address[11], loc->address[12],
- loc->address[13], loc->address[14], loc->address[15], loc->port);
+ (void) snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
+ loc->address[10], loc->address[11], loc->address[12],
+ loc->address[13], loc->address[14], loc->address[15], loc->port);
else
- snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]",
- loc->address[10], loc->address[11], loc->address[12],
- loc->address[13], loc->address[14], loc->address[15]);
+ (void) snprintf(dst, sizeof_dst, "[%02x:%02x:%02x:%02x:%02x:%02x]",
+ loc->address[10], loc->address[11], loc->address[12],
+ loc->address[13], loc->address[14], loc->address[15]);
return dst;
}
@@ -94,9 +94,9 @@ static ssize_t ddsi_raweth_conn_read (ddsi_tran_conn_t conn, unsigned char * buf
)
{
char addrbuf[DDSI_LOCSTRLEN];
- snprintf(addrbuf, sizeof(addrbuf), "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
- src.sll_addr[0], src.sll_addr[1], src.sll_addr[2],
- src.sll_addr[3], src.sll_addr[4], src.sll_addr[5], ntohs(src.sll_protocol));
+ (void) snprintf(addrbuf, sizeof(addrbuf), "[%02x:%02x:%02x:%02x:%02x:%02x]:%u",
+ src.sll_addr[0], src.sll_addr[1], src.sll_addr[2],
+ src.sll_addr[3], src.sll_addr[4], src.sll_addr[5], ntohs(src.sll_protocol));
DDS_CWARNING(&conn->m_base.gv->logconfig, "%s => %d truncated to %d\n", addrbuf, (int)ret, (int)len);
}
}
diff --git a/src/core/ddsi/src/ddsi_tran.c b/src/core/ddsi/src/ddsi_tran.c
index 7636167..5350d58 100644
--- a/src/core/ddsi/src/ddsi_tran.c
+++ b/src/core/ddsi/src/ddsi_tran.c
@@ -286,7 +286,7 @@ char *ddsi_locator_to_string (const struct q_globals *gv, char *dst, size_t size
if (0 < pos && (size_t)pos < sizeof_dst)
(void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 1);
} else {
- snprintf (dst, sizeof_dst, "invalid/0:0");
+ (void) snprintf (dst, sizeof_dst, "invalid/0:0");
}
return dst;
}
@@ -299,7 +299,7 @@ char *ddsi_locator_to_string_no_port (const struct q_globals *gv, char *dst, siz
if (0 < pos && (size_t)pos < sizeof_dst)
(void) tran->m_locator_to_string_fn (tran, dst + (size_t)pos, sizeof_dst - (size_t)pos, loc, 0);
} else {
- snprintf (dst, sizeof_dst, "invalid/0");
+ (void) snprintf (dst, sizeof_dst, "invalid/0");
}
return dst;
}
diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c
index 90b1843..5addd41 100644
--- a/src/core/ddsi/src/ddsi_udp.c
+++ b/src/core/ddsi/src/ddsi_udp.c
@@ -454,7 +454,7 @@ static char *ddsi_udp_locator_to_string (ddsi_tran_factory_t tran, char *dst, si
pos += (size_t)cnt;
}
if (with_port && pos < sizeof_dst) {
- snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port);
+ (void) snprintf (dst + pos, sizeof_dst - pos, ":%"PRIu32, loc->port);
}
return dst;
}
diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c
index 3993283..8818134 100644
--- a/src/core/ddsi/src/q_config.c
+++ b/src/core/ddsi/src/q_config.c
@@ -1166,7 +1166,7 @@ static int64_t lookup_multiplier (struct cfgst *cfgst, const struct unit *unitta
always allow 0 to be specified without a unit */
return 1;
} else if (def_mult == 0 && err_on_unrecognised) {
- cfg_error (cfgst, "%s: unit is required", value);
+ (void) cfg_error (cfgst, "%s: unit is required", value);
return 0;
} else {
cfg_warning (cfgst, "%s: use of default unit is deprecated", value);
@@ -1179,7 +1179,7 @@ static int64_t lookup_multiplier (struct cfgst *cfgst, const struct unit *unitta
if (strcmp(unittab[i].name, value + unit_pos) == 0)
return unittab[i].multiplier;
if (err_on_unrecognised)
- cfg_error(cfgst, "%s: unrecognised unit", value + unit_pos);
+ (void) cfg_error(cfgst, "%s: unrecognised unit", value + unit_pos);
return 0;
}
}
@@ -2072,7 +2072,7 @@ static int set_default (struct cfgst *cfgst, void *parent, struct cfgelem const
enum update_result res;
if (cfgelem->defvalue == NULL)
{
- cfg_error (cfgst, "element missing in configuration");
+ (void) cfg_error (cfgst, "element missing in configuration");
return 0;
}
res = do_update (cfgst, cfgelem->update, parent, cfgelem, cfgelem->defvalue, 0);
@@ -2402,7 +2402,7 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
cfg_subelem = partial_match;
else
{
- cfg_error (cfgst, "%s: unknown element", name);
+ (void) cfg_error (cfgst, "%s: unknown element", name);
cfgst_push (cfgst, 0, NULL, NULL);
return 0;
}
@@ -2516,7 +2516,7 @@ static int proc_attr (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *n
return proc_update_cfgelem (cfgst, cfg_attr, value, true);
else
{
- cfg_error (cfgst, "%s: unknown attribute", name);
+ (void) cfg_error (cfgst, "%s: unknown attribute", name);
return 0;
}
}
@@ -2533,7 +2533,7 @@ static int proc_elem_data (void *varg, UNUSED_ARG (uintptr_t eleminfo), const ch
return proc_update_cfgelem (cfgst, cfgelem, value, isattr);
else
{
- cfg_error (cfgst, "%s: no data expected", value);
+ (void) cfg_error (cfgst, "%s: no data expected", value);
return 0;
}
}
@@ -2560,7 +2560,7 @@ static int proc_elem_close (void *varg, UNUSED_ARG (uintptr_t eleminfo), int lin
static void proc_error (void *varg, const char *msg, int line)
{
struct cfgst * const cfgst = varg;
- cfg_error (cfgst, "parser error %s at line %d", msg, line);
+ (void) cfg_error (cfgst, "parser error %s at line %d", msg, line);
}
static int cfgst_node_cmp (const void *va, const void *vb)
@@ -2722,7 +2722,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi
qx = ddsrt_xmlp_new_string (tok, cfgst, &cb);
ddsrt_xmlp_set_options (qx, DDSRT_XMLP_ANONYMOUS_CLOSE_TAG | DDSRT_XMLP_MISSING_CLOSE_AS_EOF);
fp = NULL;
- snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
+ (void) snprintf (env_input, sizeof (env_input), "CYCLONEDDS_URI+%u", (unsigned) (tok - copy));
cfgst->input = env_input;
cfgst->line = 1;
}
@@ -2902,7 +2902,7 @@ static char *get_partition_search_pattern (const char *partition, const char *to
{
size_t sz = strlen (partition) + strlen (topic) + 2;
char *pt = ddsrt_malloc (sz);
- snprintf (pt, sz, "%s.%s", partition, topic);
+ (void) snprintf (pt, sz, "%s.%s", partition, topic);
return pt;
}
diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c
index 45b3e9e..dc07149 100644
--- a/src/core/ddsi/src/q_ddsi_discovery.c
+++ b/src/core/ddsi/src/q_ddsi_discovery.c
@@ -317,7 +317,7 @@ int spdp_write (struct participant *pp)
ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock);
if (ddsrt_gethostname(node, sizeof(node)-1) < 0)
- ddsrt_strlcpy (node, "unknown", sizeof (node));
+ (void) ddsrt_strlcpy (node, "unknown", sizeof (node));
size = strlen(node) + strlen(DDS_VERSION) + strlen(DDS_HOST_NAME) + strlen(DDS_TARGET_NAME) + 4; /* + ///'\0' */
ps.prismtech_participant_version_info.internals = ddsrt_malloc(size);
(void) snprintf(ps.prismtech_participant_version_info.internals, size, "%s/%s/%s/%s", node, DDS_VERSION, DDS_HOST_NAME, DDS_TARGET_NAME);
@@ -413,7 +413,7 @@ static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest
GVTRACE (" %"PRId64, delay);
if (!pp->e.gv->config.unicast_response_to_spdp_messages)
/* pp can't reach gc_delete_participant => can safely reschedule */
- resched_xevent_if_earlier (pp->spdp_xevent, tsched);
+ (void) resched_xevent_if_earlier (pp->spdp_xevent, tsched);
else
qxev_spdp (gv->xevents, tsched, &pp->e.guid, dest_proxypp_guid);
}
diff --git a/src/core/ddsi/src/q_debmon.c b/src/core/ddsi/src/q_debmon.c
index b4f6c29..e347347 100644
--- a/src/core/ddsi/src/q_debmon.c
+++ b/src/core/ddsi/src/q_debmon.c
@@ -389,7 +389,8 @@ struct debug_monitor *new_debug_monitor (struct q_globals *gv, int32_t port)
if (ddsi_listener_listen (dm->servsock) < 0)
goto err_listen;
dm->stop = 0;
- create_thread (&dm->servts, gv, "debmon", debmon_main, dm);
+ if (create_thread (&dm->servts, gv, "debmon", debmon_main, dm) != DDS_RETCODE_OK)
+ goto err_listen;
return dm;
err_listen:
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index ed13d6c..85ae9c3 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -1698,7 +1698,7 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd)
if (tnext.v < wr->hbcontrol.tsched.v)
{
wr->hbcontrol.tsched = tnext;
- resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
+ (void) resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
}
ddsrt_mutex_unlock (&wr->e.lock);
}
@@ -1807,7 +1807,9 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr,
/* FIXME: for now, assume that the ports match for datasock_mc --
't would be better to dynamically create and destroy sockets on
an as needed basis. */
- ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
+ int ret = ddsi_join_mc (rd->e.gv, rd->e.gv->mship, rd->e.gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc);
+ if (ret < 0)
+ ELOGDISC (rd, " unable to join\n");
}
else
{
@@ -2931,7 +2933,7 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g
if (wr->lease_duration != T_NEVER)
{
nn_mtime_t tsched = { 0 };
- resched_xevent_if_earlier (pp->pmd_update_xevent, tsched);
+ (void) resched_xevent_if_earlier (pp->pmd_update_xevent, tsched);
}
return 0;
@@ -3770,7 +3772,7 @@ int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, se
switch (source)
{
case UPD_PROXYPP_SPDP:
- update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
+ (void) update_qos_locked (&proxypp->e, &proxypp->plist->qos, &new_plist->qos, timestamp);
nn_plist_fini (new_plist);
ddsrt_free (new_plist);
proxypp->proxypp_have_spdp = 1;
@@ -4181,7 +4183,7 @@ void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset
}
}
- update_qos_locked (&pwr->e, pwr->c.xqos, xqos, timestamp);
+ (void) update_qos_locked (&pwr->e, pwr->c.xqos, xqos, timestamp);
}
ddsrt_mutex_unlock (&pwr->e.lock);
}
@@ -4239,7 +4241,7 @@ void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset
}
}
- update_qos_locked (&prd->e, prd->c.xqos, xqos, timestamp);
+ (void) update_qos_locked (&prd->e, prd->c.xqos, xqos, timestamp);
}
ddsrt_mutex_unlock (&prd->e.lock);
}
diff --git a/src/core/ddsi/src/q_gc.c b/src/core/ddsi/src/q_gc.c
index 054485c..39274ae 100644
--- a/src/core/ddsi/src/q_gc.c
+++ b/src/core/ddsi/src/q_gc.c
@@ -133,7 +133,7 @@ static uint32_t gcreq_queue_thread (struct gcreq_queue *q)
} else {
to = delay;
}
- ddsrt_cond_waitfor (&q->cond, &q->lock, to);
+ (void) ddsrt_cond_waitfor (&q->cond, &q->lock, to);
}
if (q->first)
{
diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c
index 17cc553..e200483 100644
--- a/src/core/ddsi/src/q_init.c
+++ b/src/core/ddsi/src/q_init.c
@@ -734,7 +734,7 @@ static void wait_for_receive_threads_helper (struct xevent *xev, void *varg, nn_
if (arg->count++ == arg->gv->config.recv_thread_stop_maxretries)
abort ();
trigger_recv_threads (arg->gv);
- resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND));
+ (void) resched_xevent_if_earlier (xev, add_duration_to_mtime (tnow, T_SECOND));
}
static void wait_for_receive_threads (struct q_globals *gv)
@@ -1453,7 +1453,8 @@ int rtps_start (struct q_globals *gv)
}
if (gv->listener)
{
- create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener);
+ if (create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener) != DDS_RETCODE_OK)
+ GVERROR ("rtps_start: can't create listener thread\n");
/* FIXME: error handling */
}
if (gv->config.monitor_port >= 0)
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index e35abda..18a0fbf 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -263,13 +263,13 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
delete_writer_nolinger (gv, &g);
break;
case EK_PROXY_WRITER:
- delete_proxy_writer (gv, &g, now(), 1);
+ (void) delete_proxy_writer (gv, &g, now(), 1);
break;
case EK_READER:
delete_reader (gv, &g);
break;
case EK_PROXY_READER:
- delete_proxy_reader (gv, &g, now(), 1);
+ (void) delete_proxy_reader (gv, &g, now(), 1);
break;
}
diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c
index bed0449..c5c4c85 100644
--- a/src/core/ddsi/src/q_nwif.c
+++ b/src/core/ddsi/src/q_nwif.c
@@ -464,11 +464,11 @@ int find_own_ip (struct q_globals *gv, const char *requested_address)
char if_name[sizeof (last_if_name)];
int q = 0;
- ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name));
+ (void) ddsrt_strlcpy(if_name, ifa->name, sizeof(if_name));
if (strcmp (if_name, last_if_name))
GVLOG (DDS_LC_CONFIG, "%s%s", sep, if_name);
- ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
+ (void) ddsrt_strlcpy(last_if_name, if_name, sizeof(last_if_name));
/* interface must be up */
if ((ifa->flags & IFF_UP) == 0) {
diff --git a/src/core/ddsi/src/q_pcap.c b/src/core/ddsi/src/q_pcap.c
index f588bbc..1ac6117 100644
--- a/src/core/ddsi/src/q_pcap.c
+++ b/src/core/ddsi/src/q_pcap.c
@@ -96,7 +96,7 @@ FILE *new_pcap_file (const struct ddsrt_log_cfg *logcfg, const char *name)
hdr.sigfigs = 0;
hdr.snaplen = 65535;
hdr.network = LINKTYPE_RAW;
- fwrite (&hdr, sizeof (hdr), 1, fp);
+ (void) fwrite (&hdr, sizeof (hdr), 1, fp);
return fp;
DDSRT_WARNING_MSVC_ON(4996);
@@ -109,7 +109,7 @@ static void write_data (FILE *fp, const ddsrt_msghdr_t *msghdr, size_t sz)
{
size_t m1 = msghdr->msg_iov[i].iov_len;
size_t m = (n + m1 <= sz) ? m1 : sz - n;
- fwrite (msghdr->msg_iov[i].iov_base, m, 1, fp);
+ (void) fwrite (msghdr->msg_iov[i].iov_base, m, 1, fp);
n += m;
}
assert (n == sz);
@@ -142,20 +142,20 @@ void write_pcap_received (struct q_globals *gv, nn_wctime_t tstamp, const struct
ddsrt_mutex_lock (&gv->pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
- fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
+ (void) fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = ddsrt_toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 128;
u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((struct sockaddr_in*) dst)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
- fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
+ (void) fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((struct sockaddr_in*) dst)->sin_port;
udp_hdr.length = ddsrt_toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
- fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
- fwrite (buf, sz, 1, gv->pcap_fp);
+ (void) fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
+ (void) fwrite (buf, sz, 1, gv->pcap_fp);
ddsrt_mutex_unlock (&gv->pcap_lock);
}
}
@@ -175,19 +175,19 @@ void write_pcap_sent (struct q_globals *gv, nn_wctime_t tstamp, const struct soc
ddsrt_mutex_lock (&gv->pcap_lock);
wctime_to_sec_usec (&pcap_hdr.ts_sec, &pcap_hdr.ts_usec, tstamp);
pcap_hdr.incl_len = pcap_hdr.orig_len = (uint32_t) sz_iud;
- fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
+ (void) fwrite (&pcap_hdr, sizeof (pcap_hdr), 1, gv->pcap_fp);
u.ipv4_hdr = ipv4_hdr_template;
u.ipv4_hdr.totallength = ddsrt_toBE2u ((unsigned short) sz_iud);
u.ipv4_hdr.ttl = 255;
u.ipv4_hdr.srcip = ((struct sockaddr_in*) src)->sin_addr.s_addr;
u.ipv4_hdr.dstip = ((struct sockaddr_in*) hdr->msg_name)->sin_addr.s_addr;
u.ipv4_hdr.checksum = calc_ipv4_checksum (u.x);
- fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
+ (void) fwrite (&u.ipv4_hdr, sizeof (u.ipv4_hdr), 1, gv->pcap_fp);
udp_hdr.srcport = ((struct sockaddr_in*) src)->sin_port;
udp_hdr.dstport = ((struct sockaddr_in*) hdr->msg_name)->sin_port;
udp_hdr.length = ddsrt_toBE2u ((unsigned short) sz_ud);
udp_hdr.checksum = 0; /* don't have to compute a checksum for UDPv4 */
- fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
+ (void) fwrite (&udp_hdr, sizeof (udp_hdr), 1, gv->pcap_fp);
write_data (gv->pcap_fp, hdr, sz);
ddsrt_mutex_unlock (&gv->pcap_lock);
}
diff --git a/src/core/ddsi/src/q_radmin.c b/src/core/ddsi/src/q_radmin.c
index d553510..e6a8252 100644
--- a/src/core/ddsi/src/q_radmin.c
+++ b/src/core/ddsi/src/q_radmin.c
@@ -2535,7 +2535,7 @@ struct nn_dqueue *nn_dqueue_new (const char *name, const struct q_globals *gv, u
thrnamesz = 3 + strlen (name) + 1;
if ((thrname = ddsrt_malloc (thrnamesz)) == NULL)
goto fail_thrname;
- snprintf (thrname, thrnamesz, "dq.%s", name);
+ (void) snprintf (thrname, thrnamesz, "dq.%s", name);
if (create_thread (&q->ts, gv, thrname, (uint32_t (*) (void *)) dqueue_thread, q) != DDS_RETCODE_OK)
goto fail_thread;
ddsrt_free (thrname);
@@ -2648,7 +2648,7 @@ void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct
ddsrt_atomic_add32 (&q->nof_samples, 1 + (uint32_t) rres);
if (nn_dqueue_enqueue_bubble_locked (q, b))
ddsrt_cond_broadcast (&q->cond);
- nn_dqueue_enqueue_locked (q, sc);
+ (void) nn_dqueue_enqueue_locked (q, sc);
ddsrt_mutex_unlock (&q->lock);
}
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index 82b5953..cb962fb 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -1348,7 +1348,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
samples we no longer care about) */
int64_t delay = rst->gv->config.nack_delay;
RSTTRACE ("/nackfrag");
- resched_xevent_if_earlier (m->acknack_xevent, add_duration_to_mtime (now_mt(), delay));
+ (void) resched_xevent_if_earlier (m->acknack_xevent, add_duration_to_mtime (now_mt(), delay));
}
}
}
@@ -2893,12 +2893,15 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d
{
return false;
}
+
+ assert(sizeof(struct nn_rmsg) == offsetof(struct nn_rmsg, chunk) + sizeof(struct nn_rmsg_chunk));
+
buff = (unsigned char *) NN_RMSG_PAYLOAD (rmsg);
hdr = (Header_t*) buff;
if (conn->m_stream)
{
- MsgLen_t * ml = (MsgLen_t*) (buff + RTPS_MESSAGE_HEADER_SIZE);
+ MsgLen_t * ml = (MsgLen_t*) (hdr + 1);
/*
Read in packet header to get size of packet in MsgLen_t, then read in
diff --git a/src/core/ddsi/src/q_sockwaitset.c b/src/core/ddsi/src/q_sockwaitset.c
index dabff22..951281d 100644
--- a/src/core/ddsi/src/q_sockwaitset.c
+++ b/src/core/ddsi/src/q_sockwaitset.c
@@ -704,8 +704,8 @@ void os_sockWaitsetFree (os_sockWaitset ws)
closesocket (ws->pipe[0]);
closesocket (ws->pipe[1]);
#elif !defined(LWIP_SOCKET)
- close (ws->pipe[0]);
- close (ws->pipe[1]);
+ (void) close (ws->pipe[0]);
+ (void) close (ws->pipe[1]);
#endif
#if defined(__VXWORKS__) && defined(__RTP__)
pipeDevDelete ((char*) &nameBuf, 0);
diff --git a/src/core/ddsi/src/q_thread.c b/src/core/ddsi/src/q_thread.c
index 60e8afa..1c0c144 100644
--- a/src/core/ddsi/src/q_thread.c
+++ b/src/core/ddsi/src/q_thread.c
@@ -251,7 +251,7 @@ static struct thread_state1 *init_thread_state (const char *tname, const struct
ts = &thread_states.ts[cand];
ddsrt_atomic_stvoidp (&ts->gv, (struct q_globals *) gv);
assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts->vtime)));
- ddsrt_strlcpy (ts->name, tname, sizeof (ts->name));
+ (void) ddsrt_strlcpy (ts->name, tname, sizeof (ts->name));
ts->state = state;
return ts;
diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c
index 0a99fc9..7afd1fe 100644
--- a/src/core/ddsi/src/q_transmit.c
+++ b/src/core/ddsi/src/q_transmit.c
@@ -120,7 +120,7 @@ void writer_hbcontrol_note_asyncwrite (struct writer *wr, nn_mtime_t tnow)
least one unacked msg if there are reliable readers, so must
have a heartbeat scheduled. Do so now */
hbc->tsched = tnext;
- resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
+ (void) resched_xevent_if_earlier (wr->heartbeat_xevent, tnext);
}
}
diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c
index 775b2f4..0e939a3 100644
--- a/src/core/ddsi/src/q_xevent.c
+++ b/src/core/ddsi/src/q_xevent.c
@@ -623,7 +623,7 @@ static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, nn_mt
ddsrt_avl_is_empty (&wr->readers) ? (seqno_t) -1 : ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->min_seq,
ddsrt_avl_is_empty (&wr->readers) || ((struct wr_prd_match *) ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers))->all_have_replied_to_hb ? "" : "!",
whcst.max_seq, writer_read_seq_xmit (wr));
- resched_xevent_if_earlier (ev, t_next);
+ (void) resched_xevent_if_earlier (ev, t_next);
wr->hbcontrol.tsched = t_next;
ddsrt_mutex_unlock (&wr->e.lock);
@@ -895,7 +895,7 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent
HEARTBEAT, I've seen too many cases of not sending an NACK
because the writing side got confused ... Better to recover
eventually. */
- resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, gv->config.auto_resched_nack_delay));
+ (void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, gv->config.auto_resched_nack_delay));
}
GVTRACE ("send acknack(rd "PGUIDFMT" -> pwr "PGUIDFMT")\n",
PGUID (ev->u.acknack.rd_guid), PGUID (ev->u.acknack.pwr_guid));
@@ -921,7 +921,7 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent
intv = 5;
else
intv = 10;
- resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, intv * T_SECOND));
+ (void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, intv * T_SECOND));
}
ddsrt_mutex_unlock (&pwr->e.lock);
@@ -934,7 +934,7 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent
outofmem:
/* What to do if out of memory? Crash or burn? */
ddsrt_mutex_unlock (&pwr->e.lock);
- resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, 100 * T_MILLISECOND));
+ (void) resched_xevent_if_earlier (ev, add_duration_to_mtime (tnow, 100 * T_MILLISECOND));
}
static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_guid_t *guid, struct proxy_reader *prd)
@@ -1059,7 +1059,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
PGUID (pp->e.guid),
PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER,
(double)(tnext.v - tnow.v) / 1e9);
- resched_xevent_if_earlier (ev, tnext);
+ (void) resched_xevent_if_earlier (ev, tnext);
}
}
else
@@ -1086,7 +1086,7 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
PGUID (pp->e.guid),
PGUIDPREFIX (ev->u.spdp.dest_proxypp_guid_prefix), NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER,
(double)(tnext.v - tnow.v) / 1e9);
- resched_xevent_if_earlier (ev, tnext);
+ (void) resched_xevent_if_earlier (ev, tnext);
}
}
@@ -1168,7 +1168,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_
GVTRACE ("resched pmd("PGUIDFMT"): %gs\n", PGUID (pp->e.guid), (double)(tnext.v - tnow.v) / 1e9);
}
- resched_xevent_if_earlier (ev, tnext);
+ (void) resched_xevent_if_earlier (ev, tnext);
ddsrt_mutex_unlock (&pp->e.lock);
}
diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c
index 5e704a3..869fb18 100644
--- a/src/core/ddsi/src/q_xmsg.c
+++ b/src/core/ddsi/src/q_xmsg.c
@@ -1188,7 +1188,7 @@ static uint32_t nn_xpack_sendq_thread (void *vgv)
struct nn_xpack *xp;
if ((xp = gv->sendq_head) == NULL)
{
- ddsrt_cond_waitfor (&gv->sendq_cond, &gv->sendq_lock, 1000000);
+ (void) ddsrt_cond_waitfor (&gv->sendq_cond, &gv->sendq_lock, 1000000);
}
else
{
@@ -1217,7 +1217,8 @@ void nn_xpack_sendq_init (struct q_globals *gv)
void nn_xpack_sendq_start (struct q_globals *gv)
{
- create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL);
+ if (create_thread (&gv->sendq_ts, gv, "sendq", nn_xpack_sendq_thread, NULL) != DDS_RETCODE_OK)
+ GVERROR ("nn_xpack_sendq_start: can't create nn_xpack_sendq_thread\n");
}
void nn_xpack_sendq_stop (struct q_globals *gv)
diff --git a/src/core/xtests/rhc_torture/rhc_torture.c b/src/core/xtests/rhc_torture/rhc_torture.c
index 3c1095c..6046519 100644
--- a/src/core/xtests/rhc_torture/rhc_torture.c
+++ b/src/core/xtests/rhc_torture/rhc_torture.c
@@ -70,7 +70,7 @@ static char *print_tstamp (char *buf, size_t sz, dds_time_t t)
if (d / 1000000000 != 0)
pos += (size_t) snprintf (buf + pos, sz - pos, "%+ds", (int) (d / 1000000000));
if (d % 1000000000 != 0)
- snprintf (buf + pos, sz - pos, "%+dns", (int) (d % 1000000000));
+ (void) snprintf (buf + pos, sz - pos, "%+dns", (int) (d % 1000000000));
return buf;
}
@@ -439,7 +439,7 @@ static void print_condmask (char *buf, size_t bufsz, const dds_readcond *cond)
pos += (size_t) snprintf (buf + pos, bufsz - pos, "%sALIVE | DISPOSED", sep);
break;
}
- snprintf (buf + pos, bufsz - pos, "]");
+ (void) snprintf (buf + pos, bufsz - pos, "]");
}
static void rdcond (struct dds_rhc *rhc, dds_readcond *cond, const struct check *chk, int max, bool print, uint32_t states_seen[STATIC_ARRAY_DIM 2*2*3][2])
diff --git a/src/ddsrt/src/expand_envvars.c b/src/ddsrt/src/expand_envvars.c
index bd988c7..faa166a 100644
--- a/src/ddsrt/src/expand_envvars.c
+++ b/src/ddsrt/src/expand_envvars.c
@@ -42,10 +42,10 @@ static char *expand_env (const char *name, char op, const char *alt, expand_fn e
if ((ret = ddsrt_getenv (name, &env)) == DDS_RETCODE_OK) {
/* ok */
} else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) {
- snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ());
+ (void) snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ());
env = idstr;
} else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0 && domid != UINT32_MAX) {
- snprintf (idstr, sizeof (idstr), "%"PRIu32, domid);
+ (void) snprintf (idstr, sizeof (idstr), "%"PRIu32, domid);
env = idstr;
}
diff --git a/src/ddsrt/src/ifaddrs/posix/ifaddrs.c b/src/ddsrt/src/ifaddrs/posix/ifaddrs.c
index 8bf8f52..393757a 100644
--- a/src/ddsrt/src/ifaddrs/posix/ifaddrs.c
+++ b/src/ddsrt/src/ifaddrs/posix/ifaddrs.c
@@ -94,7 +94,7 @@ static enum ddsrt_iftype guess_iftype (const struct ifaddrs *sys_ifa)
struct ifmediareq ifmr;
enum ddsrt_iftype type;
memset (&ifmr, 0, sizeof (ifmr));
- ddsrt_strlcpy (ifmr.ifm_name, sys_ifa->ifa_name, sizeof (ifmr.ifm_name));
+ (void) ddsrt_strlcpy (ifmr.ifm_name, sys_ifa->ifa_name, sizeof (ifmr.ifm_name));
if (ioctl (sock, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
{
type = DDSRT_IFTYPE_UNKNOWN;
diff --git a/src/ddsrt/src/log.c b/src/ddsrt/src/log.c
index a988c92..f426b90 100644
--- a/src/ddsrt/src/log.c
+++ b/src/ddsrt/src/log.c
@@ -54,7 +54,7 @@ static void default_sink (void *ptr, const dds_log_data_t *data)
{
if (ptr)
{
- fwrite (data->message - data->hdrsize, 1, data->hdrsize + data->size + 1, (FILE *) ptr);
+ (void) fwrite (data->message - data->hdrsize, 1, data->hdrsize + data->size + 1, (FILE *) ptr);
fflush ((FILE *) ptr);
}
}
diff --git a/src/ddsrt/src/process/posix/process.c b/src/ddsrt/src/process/posix/process.c
index f8de0fc..1a4e47f 100644
--- a/src/ddsrt/src/process/posix/process.c
+++ b/src/ddsrt/src/process/posix/process.c
@@ -203,8 +203,8 @@ ddsrt_proc_create(
if (write(exec_fds[1], &exec_err, sizeof(int)) < (ssize_t)sizeof(int)) {
DDS_ERROR("Could not write proc error pipe.\n");
}
- close(exec_fds[1]);
- close(exec_fds[0]);
+ (void) close(exec_fds[1]);
+ (void) close(exec_fds[0]);
ddsrt_free(exec_argv);
_exit(1);
}
@@ -214,7 +214,7 @@ ddsrt_proc_create(
/* Get execv result. */
rv = DDS_RETCODE_ERROR;
- close(exec_fds[1]);
+ (void) close(exec_fds[1]);
nr = read(exec_fds[0], &exec_err, sizeof(int));
if (nr == 0) {
/* Pipe closed by successful execv. */
@@ -228,14 +228,14 @@ ddsrt_proc_create(
rv = DDS_RETCODE_NOT_ALLOWED;
}
}
- close(exec_fds[0]);
+ (void) close(exec_fds[0]);
if (rv == DDS_RETCODE_OK) {
/* Remember child pid. */
*pid = spawn;
} else {
/* Remove the failed fork pid from the system list. */
- waitpid(spawn, NULL, 0);
+ (void) waitpid(spawn, NULL, 0);
}
}
@@ -244,8 +244,8 @@ ddsrt_proc_create(
fail_fork:
fail_fctl:
- close(exec_fds[0]);
- close(exec_fds[1]);
+ (void) close(exec_fds[0]);
+ (void) close(exec_fds[1]);
fail_pipe:
ddsrt_free(exec_argv);
return rv;
diff --git a/src/ddsrt/src/rusage/posix/rusage.c b/src/ddsrt/src/rusage/posix/rusage.c
index d8806e3..41c2a07 100644
--- a/src/ddsrt/src/rusage/posix/rusage.c
+++ b/src/ddsrt/src/rusage/posix/rusage.c
@@ -109,7 +109,7 @@ ddsrt_getrusage_anythread (
return DDS_RETCODE_ERROR;
if ((fp = fopen (file, "r")) == NULL)
return DDS_RETCODE_NOT_FOUND;
- enum { ERROR, READ_HEADING, SKIP_TO_EOL, READ_VCSW, READ_IVCSW } state = READ_HEADING;
+ enum { ERROR = 1, READ_HEADING, SKIP_TO_EOL, READ_VCSW, READ_IVCSW } state = READ_HEADING;
savepos = 0;
while (state != ERROR && (c = fgetc (fp)) != EOF)
{
diff --git a/src/ddsrt/src/threads/posix/threads.c b/src/ddsrt/src/threads/posix/threads.c
index bbf5f8d..0d2c387 100644
--- a/src/ddsrt/src/threads/posix/threads.c
+++ b/src/ddsrt/src/threads/posix/threads.c
@@ -126,7 +126,7 @@ ddsrt_thread_setname(const char *__restrict name)
/* Thread names are limited to 16 bytes on Linux. ERANGE is returned if the
name exceeds the limit, so silently truncate. */
char buf[MAXTHREADNAMESIZE + 1] = "";
- ddsrt_strlcpy(buf, name, sizeof(buf));
+ (void)ddsrt_strlcpy(buf, name, sizeof(buf));
(void)pthread_setname_np(pthread_self(), name);
#elif defined(__APPLE__)
(void)pthread_setname_np(name);
diff --git a/src/ddsrt/src/threads/windows/threads.c b/src/ddsrt/src/threads/windows/threads.c
index ab83246..2bc8052 100644
--- a/src/ddsrt/src/threads/windows/threads.c
+++ b/src/ddsrt/src/threads/windows/threads.c
@@ -313,7 +313,7 @@ ddsrt_thread_setname(
}
#pragma warning(pop)
}
- ddsrt_strlcpy (thread_name, name, sizeof (thread_name));
+ (void)ddsrt_strlcpy (thread_name, name, sizeof (thread_name));
}
dds_return_t
diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c
index 0096c88..873aa0d 100644
--- a/src/ddsrt/src/xmlparser.c
+++ b/src/ddsrt/src/xmlparser.c
@@ -459,10 +459,10 @@ static int next_token_tag_withoutclose (struct ddsrt_xmlp_state *st, char **payl
} else {
int tok = TOK_OPEN_TAG;
/* pre: peek_char(st) == '<' */
- next_char (st);
+ (void) next_char (st);
if (peek_char (st) == '/') {
tok = TOK_CLOSE_TAG;
- next_char (st);
+ (void) next_char (st);
}
/* we only do tag names that are identifiers */
if (peek_char (st) == '>' && (st->options & DDSRT_XMLP_ANONYMOUS_CLOSE_TAG)) {
@@ -501,7 +501,7 @@ static int skip_comment (struct ddsrt_xmlp_state *st)
return 0;
}
while (peek_char (st) != TOK_EOF && (peek_char (st) != '-' || !peek_chars (st, "-->", 0))) {
- next_char (st);
+ (void) next_char (st);
}
if (peek_chars (st, "-->", 1)) {
return 1;
@@ -514,7 +514,7 @@ static void processing_instruction (struct ddsrt_xmlp_state *st, const char *end
{
/* just after ; skip everything up to and include ?> */
while (peek_char (st) != TOK_EOF && !peek_chars (st, end, 1)) {
- next_char (st);
+ (void) next_char (st);
}
}
@@ -551,7 +551,7 @@ static int next_token (struct ddsrt_xmlp_state *st, char **payload)
st->prevline = st->line;
do {
while (qq_isspace (peek_char (st))) {
- next_char (st);
+ (void) next_char (st);
}
} while ((cmt = skip_comment (st)) > 0);
if (cmt == TOK_ERROR) {
diff --git a/src/ddsrt/tests/log.c b/src/ddsrt/tests/log.c
index 9f5223b..53a7629 100644
--- a/src/ddsrt/tests/log.c
+++ b/src/ddsrt/tests/log.c
@@ -435,13 +435,13 @@ static void abort_handler (int sig)
static void abort_log (void *arg, const dds_log_data_t *info)
{
(void) arg;
- ddsrt_strlcpy (abort_message, info->message, sizeof (abort_message));
+ (void) ddsrt_strlcpy (abort_message, info->message, sizeof (abort_message));
}
static void abort_trace (void *arg, const dds_log_data_t *info)
{
(void) arg;
- ddsrt_strlcpy (abort_message_trace, info->message, sizeof (abort_message_trace));
+ (void) ddsrt_strlcpy (abort_message_trace, info->message, sizeof (abort_message_trace));
}
CU_TheoryDataPoints(dds_log, fatal_aborts) = {
diff --git a/src/ddsrt/tests/socket.c b/src/ddsrt/tests/socket.c
index 411524b..e6c7ca1 100644
--- a/src/ddsrt/tests/socket.c
+++ b/src/ddsrt/tests/socket.c
@@ -157,7 +157,7 @@ CU_Test(ddsrt_sockets, gethostname)
sysbuf[0] = '\0';
#if LWIP_SOCKET
- ddsrt_strlcpy(sysbuf, "localhost", sizeof(sysbuf));
+ (void) ddsrt_strlcpy(sysbuf, "localhost", sizeof(sysbuf));
#else
int ret = gethostname(sysbuf, sizeof(sysbuf));
CU_ASSERT_EQUAL(ret, 0);
diff --git a/src/tools/ddsls/ddsls.c b/src/tools/ddsls/ddsls.c
index 216cff6..46f77cf 100644
--- a/src/tools/ddsls/ddsls.c
+++ b/src/tools/ddsls/ddsls.c
@@ -27,9 +27,9 @@
static char *qp_duration_str (char *buf, size_t bufsz, dds_duration_t d)
{
if (d == DDS_INFINITY)
- snprintf (buf, bufsz, "infinite");
+ (void) snprintf (buf, bufsz, "infinite");
else
- snprintf (buf, bufsz, "%u.%09u", (unsigned)(d / DDS_NSECS_IN_SEC), (unsigned)(d % DDS_NSECS_IN_SEC));
+ (void) snprintf (buf, bufsz, "%u.%09u", (unsigned)(d / DDS_NSECS_IN_SEC), (unsigned)(d % DDS_NSECS_IN_SEC));
return buf;
}
@@ -443,9 +443,9 @@ static void print_dcps_participant (FILE *fp, dds_entity_t pp)
qp_qos (data->qos, fp);
}
}
- dds_return_loan (rd, ptrs, n);
+ (void) dds_return_loan (rd, ptrs, n);
}
- dds_delete (rd);
+ (void) dds_delete (rd);
}
static void print_dcps_endpoint (FILE *fp, dds_entity_t pp, const char *type, dds_entity_t topic)
@@ -472,9 +472,9 @@ static void print_dcps_endpoint (FILE *fp, dds_entity_t pp, const char *type, dd
qp_qos (data->qos,fp);
}
}
- dds_return_loan (rd, ptrs, n);
+ (void) dds_return_loan (rd, ptrs, n);
}
- dds_delete (rd);
+ (void) dds_delete (rd);
}
static void print_dcps_subscription (FILE *fp, dds_entity_t pp)
diff --git a/src/tools/ddsperf/cputime.c b/src/tools/ddsperf/cputime.c
index 591720d..b94a473 100644
--- a/src/tools/ddsperf/cputime.c
+++ b/src/tools/ddsperf/cputime.c
@@ -180,7 +180,7 @@ bool record_cputime (struct record_cputime_state *state, const char *prefix, dds
}
state->tprev = tnow;
state->s.some_above = some_above;
- dds_write (state->wr, &state->s);
+ (void) dds_write (state->wr, &state->s);
return print_cputime (&state->s, prefix, false, true);
}
diff --git a/src/tools/ddsperf/ddsperf.c b/src/tools/ddsperf/ddsperf.c
index 2a252d8..8fe6eae 100644
--- a/src/tools/ddsperf/ddsperf.c
+++ b/src/tools/ddsperf/ddsperf.c
@@ -1881,7 +1881,7 @@ int main (int argc, char *argv[])
case 'd': {
char *col;
int pos;
- ddsrt_strlcpy (netload_if, optarg, sizeof (netload_if));
+ (void) ddsrt_strlcpy (netload_if, optarg, sizeof (netload_if));
if ((col = strrchr (netload_if, ':')) == NULL || col == netload_if ||
(sscanf (col+1, "%lf%n", &netload_bw, &pos) != 1 || (col+1)[pos] != 0))
error3 ("-d%s: expected DEVICE:BANDWIDTH\n", optarg);
diff --git a/src/tools/pubsub/pubsub.c b/src/tools/pubsub/pubsub.c
index 434f564..3c5a9c4 100644
--- a/src/tools/pubsub/pubsub.c
+++ b/src/tools/pubsub/pubsub.c
@@ -266,162 +266,6 @@ Use \"\" for default partition.\n",
exit (1);
}
-static void expand_append(char **dst, size_t *sz,size_t *pos, char c) {
- if (*pos == *sz) {
- *sz += 1024;
- *dst = dds_realloc(*dst, *sz);
- }
- (*dst)[*pos] = c;
- (*pos)++;
-}
-
-static char *expand_envvars(const char *src0);
-
-// FIXME: This is the same as the expand function in util. Merge.
-static char *expand_env(const char *name, char op, const char *alt) {
- char *env = NULL;
- ddsrt_getenv(name, &env);
- switch (op) {
- case 0:
- return dds_string_dup(env ? env : "");
- case '-':
- return env ? dds_string_dup(env) : expand_envvars(alt);
- case '?':
- if (env)
- return dds_string_dup(env);
- else {
- char *altx = expand_envvars(alt);
- error_exit("%s: %s\n", name, altx);
- //dds_free(altx);
- return NULL;
- }
- case '+':
- return env ? expand_envvars(alt) : dds_string_dup("");
- default:
- exit(2);
- }
-}
-
-static char *expand_envbrace(const char **src) {
- const char *start = *src + 1;
- char *name, *x;
- assert(**src == '{');
- (*src)++;
- while (**src && **src != ':' && **src != '}')
- (*src)++;
- if (**src == 0)
- goto err;
-
- name = dds_alloc((size_t) (*src - start) + 1);
- memcpy(name, start, (size_t) (*src - start));
- name[*src - start] = 0;
- if (**src == '}') {
- (*src)++;
- x = expand_env(name, 0, NULL);
- dds_free(name);
- return x;
- } else {
- const char *altstart;
- char *alt;
- char op;
- assert(**src == ':');
- (*src)++;
-
- switch (**src) {
- case '-': case '+': case '?':
- op = **src;
- (*src)++;
- break;
- default:
- goto err;
- }
-
- altstart = *src;
- while (**src && **src != '}') {
- if (**src == '\\') {
- (*src)++;
- if (**src == 0)
- goto err;
- }
- (*src)++;
- }
- if (**src == 0)
- goto err;
- assert(**src == '}');
- alt = dds_alloc((size_t) (*src - altstart) + 1);
- memcpy(alt, altstart, (size_t) (*src - altstart));
- alt[*src - altstart] = 0;
- (*src)++;
- x = expand_env(name, op, alt);
- dds_free(alt);
- dds_free(name);
- return x;
- }
-
- err:
- error_exit("%*.*s: invalid expansion\n", (int) (*src - start), (int) (*src - start), start);
- return NULL;
-}
-
-static char *expand_envsimple(const char **src) {
- const char *start = *src;
- char *name, *x;
- while (**src && (isalnum((unsigned char)**src) || **src == '_'))
- (*src)++;
- assert(*src > start);
- name = dds_alloc((size_t) (*src - start) + 1);
- memcpy(name, start, (size_t) (*src - start));
- name[*src - start] = 0;
- x = expand_env(name, 0, NULL);
- dds_free(name);
- return x;
-}
-
-static char *expand_envchar(const char **src) {
- char name[2];
- assert(**src);
- name[0] = **src;
- name[1] = 0;
- (*src)++;
- return expand_env(name, 0, NULL);
-}
-
-static char *expand_envvars(const char *src0) {
- /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms */
- const char *src = src0;
- size_t sz = strlen(src) + 1, pos = 0;
- char *dst = dds_alloc(sz);
- while (*src) {
- if (*src == '\\') {
- src++;
- if (*src == 0)
- error_exit("%s: incomplete escape at end of string\n", src0);
- expand_append(&dst, &sz, &pos, *src++);
- } else if (*src == '$') {
- char *x, *xp;
- src++;
- if (*src == 0) {
- error_exit("%s: incomplete variable expansion at end of string\n", src0);
- return NULL;
- } else if (*src == '{') {
- x = expand_envbrace(&src);
- } else if (isalnum((unsigned char)*src) || *src == '_') {
- x = expand_envsimple(&src);
- } else {
- x = expand_envchar(&src);
- }
- xp = x;
- while (*xp)
- expand_append(&dst, &sz, &pos, *xp++);
- dds_free(x);
- } else {
- expand_append(&dst, &sz, &pos, *src++);
- }
- }
- expand_append(&dst, &sz, &pos, 0);
- return dst;
-}
-
static unsigned split_partitions(const char ***p_ps, char **p_bufcopy, const char *buf) {
const char *b;
const char **ps;
@@ -432,7 +276,7 @@ static unsigned split_partitions(const char ***p_ps, char **p_bufcopy, const cha
nps += (*b == ',');
}
ps = dds_alloc(nps * sizeof(*ps));
- bufcopy = expand_envvars(buf);
+ bufcopy = ddsrt_expand_envvars_sh(buf, 0);
i = 0; bc = bufcopy;
while (1) {
ps[i++] = bc;
@@ -1427,7 +1271,7 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) {
case 'Q': {
dds_qos_t *qos = dds_create_qos ();
setqos_from_args (DDS_KIND_PARTICIPANT, qos, 1, (const char **) &arg);
- dds_set_qos (dp, qos);
+ (void) dds_set_qos (dp, qos);
dds_delete_qos (qos);
break;
}
@@ -2058,8 +1902,8 @@ static uint32_t autotermthread(void *varg __attribute__((unused))) {
tnow = dds_time();
}
- dds_waitset_detach(ws, termcond);
- dds_delete(ws);
+ (void) dds_waitset_detach(ws, termcond);
+ (void) dds_delete(ws);
return 0;
}
@@ -2648,7 +2492,7 @@ int main(int argc, char *argv[]) {
{
char **ps = (char **) dds_alloc(sizeof(char *) * (uint32_t)(argc - optind));
for (i = 0; i < (unsigned) (argc - optind); i++)
- ps[i] = expand_envvars(argv[(unsigned) optind + i]);
+ ps[i] = ddsrt_expand_envvars_sh(argv[(unsigned) optind + i], 0);
if (want_reader) {
qos = dds_create_qos();
setqos_from_args(DDS_KIND_SUBSCRIBER, qos, nqsubscriber, qsubscriber);
@@ -2709,7 +2553,7 @@ int main(int argc, char *argv[]) {
fprintf (stderr,"C99 API doesn't support the creation of content filtered topic.\n");
spec[i].cftp = spec[i].tp;
// TODO Content Filtered Topic support
-// char name[40], *expr = expand_envvars(spec[i].cftp_expr);
+// char name[40], *expr = expand_envvars_sh(spec[i].cftp_exp, 0);
// DDS_StringSeq *params = DDS_StringSeq__alloc();
// snprintf (name, sizeof (name), "cft%u", i);
// if ((spec[i].cftp = DDS_DomainParticipant_create_contentfilteredtopic(dp, name, spec[i].tp, expr, params)) == NULL)
From 482e1cd00653c08db39231239a2dcf59d05c84b5 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Mon, 25 Nov 2019 17:14:56 +0100
Subject: [PATCH 42/55] Fix rtps_start error handling on thread creation
Signed-off-by: Erik Boasson
Use static assert instead of run-time assert
Signed-off-by: Erik Boasson
Use static assertion to verify nn_rmsg offset calc
Signed-off-by: Erik Boasson
---
src/core/ddsc/src/dds_domain.c | 1 +
src/core/ddsi/include/dds/ddsi/q_radmin.h | 1 +
src/core/ddsi/src/q_init.c | 17 +++++++++++++----
src/core/ddsi/src/q_receive.c | 3 +--
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/core/ddsc/src/dds_domain.c b/src/core/ddsc/src/dds_domain.c
index 0b5a919..1769250 100644
--- a/src/core/ddsc/src/dds_domain.c
+++ b/src/core/ddsc/src/dds_domain.c
@@ -167,6 +167,7 @@ static dds_entity_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
return domh;
fail_rtps_start:
+ dds__builtin_fini (domain);
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
ddsi_threadmon_stop (dds_global.threadmon);
fail_threadmon_start:
diff --git a/src/core/ddsi/include/dds/ddsi/q_radmin.h b/src/core/ddsi/include/dds/ddsi/q_radmin.h
index f3d4a2d..3dde1be 100644
--- a/src/core/ddsi/include/dds/ddsi/q_radmin.h
+++ b/src/core/ddsi/include/dds/ddsi/q_radmin.h
@@ -98,6 +98,7 @@ struct nn_rmsg {
struct nn_rmsg_chunk chunk;
};
+DDSRT_STATIC_ASSERT (sizeof (struct nn_rmsg) == offsetof (struct nn_rmsg, chunk) + sizeof (struct nn_rmsg_chunk));
#define NN_RMSG_PAYLOAD(m) ((unsigned char *) (m + 1))
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c
index e200483..ee10f46 100644
--- a/src/core/ddsi/src/q_init.c
+++ b/src/core/ddsi/src/q_init.c
@@ -1454,13 +1454,22 @@ int rtps_start (struct q_globals *gv)
if (gv->listener)
{
if (create_thread (&gv->listen_ts, gv, "listen", (uint32_t (*) (void *)) listen_thread, gv->listener) != DDS_RETCODE_OK)
- GVERROR ("rtps_start: can't create listener thread\n");
- /* FIXME: error handling */
+ {
+ GVERROR ("failed to create TCP listener thread\n");
+ ddsi_listener_free (gv->listener);
+ gv->listener = NULL;
+ rtps_stop (gv);
+ return -1;
+ }
}
if (gv->config.monitor_port >= 0)
{
- gv->debmon = new_debug_monitor (gv, gv->config.monitor_port);
- /* FIXME: clean up */
+ if ((gv->debmon = new_debug_monitor (gv, gv->config.monitor_port)) == NULL)
+ {
+ GVERROR ("failed to create debug monitor thread\n");
+ rtps_stop (gv);
+ return -1;
+ }
}
return 0;
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index cb962fb..5ab6472 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -2894,8 +2894,7 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d
return false;
}
- assert(sizeof(struct nn_rmsg) == offsetof(struct nn_rmsg, chunk) + sizeof(struct nn_rmsg_chunk));
-
+ DDSRT_STATIC_ASSERT (sizeof (struct nn_rmsg) == offsetof (struct nn_rmsg, chunk) + sizeof (struct nn_rmsg_chunk));
buff = (unsigned char *) NN_RMSG_PAYLOAD (rmsg);
hdr = (Header_t*) buff;
From 3822f42effa1dab7467a2bae54aecf0d3acdce48 Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Wed, 9 Oct 2019 10:28:19 +0200
Subject: [PATCH 43/55] Liveliness QoS implementation for auto and
manual-by-participant
This commit adds support for the liveliness QoS for the liveliness
kinds automatic and manual-by-participant. It also implements the
lease_duration from this QoS, which was ignored until now. In the
api the function dds_assert_liveliness is added to assert liveliness
on a participant, which can be used when using liveliness kind
manual-by-participant.
Liveliness kind manual-by-topic is not yet supported, this will be
added in a later commit.
* Proxy participants now have 2 fibheaps to keep leases: one for leases
of pwrs with automatic liveliness and one for leases of the pwrs with
manual-by-participant liveliness (both protected by the proxypp lock).
The minl_auto and minl_man members represent the shortest lease from
these fibheaps and these leases are renewed when receiving data.
Replacing the minl_ leases is now done by replacing the lease object
(atomic ptr) with delayed deletion of the old lease using the gc.
* Proxy writers are set not-alive when the lease expired, and reset to
alive then data is received. When data is received by a pwr, the other
pwrs in the proxypp might also be set alive. I think the specification
is not clear at this point, and for now I have not implemented this
* I refactored out the counter for man-by-pp proxy writers and improved
locking when updating the min-leases on the proxy participant, so I
think this fixes the race conditions.
Some additional tests are required, e.g. to test the not-alive->alive
transition for pwrs. I will add these in short term, as well as the
implementation of the manual-by-topic liveliness kind.
Signed-off-by: Dennis Potman
---
src/core/ddsc/include/dds/dds.h | 23 ++
src/core/ddsc/src/dds_entity.c | 27 ++
src/core/ddsc/tests/CMakeLists.txt | 5 +-
src/core/ddsc/tests/liveliness.c | 470 ++++++++++++++++++++++
src/core/ddsi/CMakeLists.txt | 1 +
src/core/ddsi/include/dds/ddsi/ddsi_pmd.h | 35 ++
src/core/ddsi/include/dds/ddsi/q_entity.h | 30 +-
src/core/ddsi/include/dds/ddsi/q_ephash.h | 18 +-
src/core/ddsi/include/dds/ddsi/q_lease.h | 18 +-
src/core/ddsi/src/ddsi_pmd.c | 161 ++++++++
src/core/ddsi/src/q_ddsi_discovery.c | 18 +-
src/core/ddsi/src/q_entity.c | 290 +++++++++++--
src/core/ddsi/src/q_lease.c | 135 ++-----
src/core/ddsi/src/q_receive.c | 89 ++--
src/core/ddsi/src/q_xevent.c | 52 +--
src/ddsrt/include/dds/ddsrt/time.h | 3 +
16 files changed, 1116 insertions(+), 259 deletions(-)
create mode 100644 src/core/ddsc/tests/liveliness.c
create mode 100644 src/core/ddsi/include/dds/ddsi/ddsi_pmd.h
create mode 100644 src/core/ddsi/src/ddsi_pmd.c
diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h
index a2bdb5c..23b81b2 100644
--- a/src/core/ddsc/include/dds/dds.h
+++ b/src/core/ddsc/include/dds/dds.h
@@ -3260,6 +3260,29 @@ dds_get_matched_publication_data (
dds_entity_t reader,
dds_instance_handle_t ih);
+/**
+ * @brief This operation manually asserts the liveliness of a writer
+ * or domain participant.
+ *
+ * This operation manually asserts the liveliness of a writer
+ * or domain participant. This is used in combination with the Liveliness
+ * QoS policy to indicate that the entity remains active. This operation need
+ * only be used if the liveliness kind in the QoS is either
+ * DDS_LIVELINESS_MANUAL_BY_PARTICIPANT or DDS_LIVELINESS_MANUAL_BY_TOPIC.
+ *
+ * @param[in] entity A domain participant or writer
+ *
+ * @returns A dds_return_t indicating success or failure.
+ *
+ * @retval DDS_RETCODE_OK
+ * The operation was successful.
+ * @retval DDS_RETCODE_ILLEGAL_OPERATION
+ * The operation is invoked on an inappropriate object.
+ */
+DDS_EXPORT dds_return_t
+dds_assert_liveliness (
+ dds_entity_t entity);
+
#if defined (__cplusplus)
}
#endif
diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c
index e1166fb..724948a 100644
--- a/src/core/ddsc/src/dds_entity.c
+++ b/src/core/ddsc/src/dds_entity.c
@@ -22,6 +22,7 @@
#include "dds__qos.h"
#include "dds__topic.h"
#include "dds/version.h"
+#include "dds/ddsi/ddsi_pmd.h"
#include "dds/ddsi/q_xqos.h"
extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink);
@@ -1383,3 +1384,29 @@ dds_return_t dds_generic_unimplemented_operation (dds_entity_t handle, dds_entit
return dds_generic_unimplemented_operation_manykinds (handle, 1, &kind);
}
+dds_return_t dds_assert_liveliness (dds_entity_t entity)
+{
+ dds_return_t rc;
+ dds_entity *e;
+
+ if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
+ return rc;
+ switch (dds_entity_kind (e))
+ {
+ case DDS_KIND_PARTICIPANT: {
+ write_pmd_message_guid (&e->m_domain->gv, &e->m_guid, PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE);
+ break;
+ }
+ case DDS_KIND_WRITER: {
+ /* FIXME: implement liveliness manual-by-topic */
+ rc = DDS_RETCODE_UNSUPPORTED;
+ break;
+ }
+ default: {
+ rc = DDS_RETCODE_ILLEGAL_OPERATION;
+ break;
+ }
+ }
+ dds_entity_unlock (e);
+ return rc;
+}
diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt
index af2ee77..a05efd0 100644
--- a/src/core/ddsc/tests/CMakeLists.txt
+++ b/src/core/ddsc/tests/CMakeLists.txt
@@ -28,6 +28,7 @@ set(ddsc_test_sources
"err.c"
"instance_get_key.c"
"listener.c"
+ "liveliness.c"
"participant.c"
"publisher.c"
"qos.c"
@@ -55,7 +56,9 @@ set(ddsc_test_sources
add_cunit_executable(cunit_ddsc ${ddsc_test_sources})
target_include_directories(
cunit_ddsc PRIVATE
- "$")
+ "$"
+ "$"
+ "$")
target_link_libraries(cunit_ddsc PRIVATE RoundTrip Space TypesArrayKey ddsc)
# Setup environment for config-tests
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
new file mode 100644
index 0000000..c5bfe49
--- /dev/null
+++ b/src/core/ddsc/tests/liveliness.c
@@ -0,0 +1,470 @@
+/*
+ * 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
+#include
+
+#include "dds/dds.h"
+#include "CUnit/Theory.h"
+#include "Space.h"
+#include "config_env.h"
+
+#include "dds/version.h"
+#include "dds__entity.h"
+#include "dds/ddsi/q_entity.h"
+#include "dds/ddsrt/cdtors.h"
+#include "dds/ddsrt/misc.h"
+#include "dds/ddsrt/process.h"
+#include "dds/ddsrt/threads.h"
+#include "dds/ddsrt/environ.h"
+#include "dds/ddsrt/atomics.h"
+#include "dds/ddsrt/time.h"
+
+#define DDS_DOMAINID_PUB 0
+#define DDS_DOMAINID_SUB 1
+#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}127.0.0.10"
+#define DDS_CONFIG_NO_PORT_GAIN_LOG_PUB "<"DDS_PROJECT_NAME">0cyclonedds_liveliness_pub.logfinest"DDS_PROJECT_NAME">"
+#define DDS_CONFIG_NO_PORT_GAIN_LOG_SUB "<"DDS_PROJECT_NAME">0cyclonedds_liveliness_sub.logfinest"DDS_PROJECT_NAME">"
+
+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;
+
+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 semi random 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)
+{
+ char *conf = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, UINT32_MAX);
+ g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf);
+ g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf);
+ dds_free(conf);
+
+ g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_participant > 0);
+ g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_participant > 0);
+
+ g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_publisher > 0);
+ g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_subscriber > 0);
+}
+
+static void liveliness_fini(void)
+{
+ dds_delete(g_sub_subscriber);
+ dds_delete(g_pub_publisher);
+ dds_delete(g_sub_participant);
+ dds_delete(g_pub_participant);
+ dds_delete(g_sub_domain);
+ dds_delete(g_pub_domain);
+}
+
+static seqno_t get_pmd_seqno(dds_entity_t participant)
+{
+ seqno_t seqno;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ struct writer *wr;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
+ CU_ASSERT_FATAL(wr != NULL);
+ seqno = wr->seq;
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return seqno;
+}
+
+static dds_duration_t get_pmd_interval(dds_entity_t participant)
+{
+ dds_duration_t intv;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ intv = pp_get_pmd_interval(pp);
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return intv;
+}
+
+static dds_duration_t get_ldur_config(dds_entity_t participant)
+{
+ struct dds_entity *pp_entity;
+ dds_duration_t ldur;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
+ dds_entity_unpin(pp_entity);
+ return ldur;
+}
+
+#define A DDS_LIVELINESS_AUTOMATIC
+#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
+CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
+ CU_DataPoints(dds_liveliness_kind_t, A, A, MP), /* liveliness kind */
+ CU_DataPoints(uint32_t, 200, 200, 200), /* lease duration */
+ CU_DataPoints(double, 5, 10, 5), /* delay (n times lease duration) */
+};
+#undef A
+#undef MP
+CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 10)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ seqno_t start_seqno, end_seqno;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ char name[100];
+ dds_time_t t;
+
+ t = dds_time();
+ printf("%d.%06d running test: kind %s, lease duration %d, delay %f\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ kind == 0 ? "A" : "MP", ldur, mult);
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_test", g_topic_nr++, 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);
+
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* waitset on reader */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
+
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* check no of PMD messages sent */
+ start_seqno = get_pmd_seqno(g_pub_participant);
+ dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
+ end_seqno = get_pmd_seqno(g_pub_participant);
+
+ t = dds_time();
+ printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ start_seqno, end_seqno);
+
+ CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 1 : 0))
+ if (kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT)
+ CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
+
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+}
+
+/* FIXME: add DDS_LIVELINESS_MANUAL_BY_TOPIC */
+#define A DDS_LIVELINESS_AUTOMATIC
+#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
+CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
+ CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration */
+ CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
+ CU_DataPoints(size_t, 1, 0, 2, 0, 1, 0, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
+ CU_DataPoints(size_t, 1, 1, 2, 2, 1, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
+};
+#undef A
+#undef MP
+CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t *writers;
+ dds_qos_t *rqos, *wqos_auto, *wqos_man_pp;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ struct dds_liveliness_changed_status lstatus;
+ uint32_t status;
+ size_t n, run = 1;
+ char name[100];
+ size_t wr_cnt = wr_cnt_auto + wr_cnt_man_pp;
+ dds_time_t tstart, t;
+ bool test_finished = false;
+
+ do
+ {
+ tstart = dds_time();
+ printf("%d.%06d running test: lease duration %d, delay %f, auto/manual-by-participant %zu/%zu\n",
+ (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
+ ldur, mult, wr_cnt_auto, wr_cnt_man_pp);
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_test", g_topic_nr++, 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);
+
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* writers */
+ CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
+
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+
+ writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
+ for (n = 0; n < wr_cnt; n++)
+ {
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, n < wr_cnt_auto ? wqos_auto : wqos_man_pp, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ }
+ dds_delete_qos(wqos_auto);
+ dds_delete_qos(wqos_man_pp);
+
+ t = dds_time();
+ if (t - tstart > DDS_MSECS(0.5 * ldur))
+ {
+ ldur *= 10;
+ printf("%d.%06d failed to create writers in time\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count before proxy writers are expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
+
+ dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
+ size_t stopped = 0;
+ do
+ {
+ dds_duration_t w = tstop - dds_time();
+ CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ } while (dds_time() < tstop);
+ t = dds_time();
+ printf("%d.%06d writers stopped: %zu\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
+
+ size_t exp_stopped = mult < 1 ? 0 : wr_cnt_man_pp;
+ if (stopped != exp_stopped)
+ {
+ ldur *= 10;
+ printf("%d.%06d incorrect number of stopped writers\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count */
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
+ test_finished = true;
+ }
+ }
+
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ dds_free(writers);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+
+ if (!test_finished)
+ {
+ if (run++ > 2)
+ {
+ printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
+ CU_FAIL_FATAL("Run limit reached");
+ test_finished = true;
+ continue;
+ }
+ else
+ {
+ printf("%d.%06d restarting test with ldur %d\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
+ }
+ }
+ } while (!test_finished);
+}
+
+static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader)
+{
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ uint32_t status;
+
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, ldur);
+ CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
+
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+}
+
+#define MAX_WRITERS 10
+CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ size_t wr_cnt = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ uint32_t n;
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldur", 1, 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);
+
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* check if pmd defaults to configured duration */
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
+
+ /* create writers and check pmd interval in publishing participant */
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+
+ /* cleanup */
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+}
+#undef MAX_WRITERS
+
+CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ char name[100];
+ dds_qos_t *rqos, *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ dds_duration_t ldur;
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldurpwr", 1, 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);
+
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* writer */
+ ldur = 1000;
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+
+ /* wait for writer to be alive */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* check pwr lease duration in matched publication */
+ dds_instance_handle_t wrs[1];
+ CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
+ dds_builtintopic_endpoint_t *ep;
+ ep = dds_get_matched_publication_data(reader, wrs[0]);
+ CU_ASSERT_FATAL(ep != NULL);
+ CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
+ dds_delete_qos(ep->qos);
+ dds_free(ep->topic_name);
+ dds_free(ep->type_name);
+ dds_free(ep);
+
+ /* cleanup */
+ dds_delete_qos(wqos);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+}
\ No newline at end of file
diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt
index 933762a..84fa190 100644
--- a/src/core/ddsi/CMakeLists.txt
+++ b/src/core/ddsi/CMakeLists.txt
@@ -28,6 +28,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_vendor.c
ddsi_threadmon.c
ddsi_rhc.c
+ ddsi_pmd.c
q_addrset.c
q_bitset_inlines.c
q_bswap.c
diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h
new file mode 100644
index 0000000..c2638f2
--- /dev/null
+++ b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright(c) 2006 to 2019 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
+ */
+#ifndef DDSI_PMD_H
+#define DDSI_PMD_H
+
+#include "dds/ddsi/q_time.h"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+struct q_globals;
+struct thread_state1;
+struct ddsi_guid;
+struct nn_xpack;
+struct participant;
+struct receiver_state;
+
+void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind);
+void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind);
+void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* DDSI_PMD_H */
diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h
index a694140..b6b0877 100644
--- a/src/core/ddsi/include/dds/ddsi/q_entity.h
+++ b/src/core/ddsi/include/dds/ddsi/q_entity.h
@@ -12,8 +12,10 @@
#ifndef Q_ENTITY_H
#define Q_ENTITY_H
+#include "dds/export.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/avl.h"
+#include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_protocol.h"
@@ -184,6 +186,7 @@ struct participant
int32_t user_refc; /* number of non-built-in endpoints in this participant [refc_lock] */
int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */
int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */
+ ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */
};
struct endpoint_common {
@@ -205,6 +208,11 @@ enum writer_state {
typedef ddsrt_atomic_uint64_t seq_xmit_t;
+struct ldur_fhnode {
+ ddsrt_fibheap_node_t heapnode;
+ dds_duration_t ldur;
+};
+
struct writer
{
struct entity_common e;
@@ -234,7 +242,7 @@ struct writer
struct addrset *as; /* set of addresses to publish to */
struct addrset *as_group; /* alternate case, used for SPDP, when using Cloud with multiple bootstrap locators */
struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */
- dds_duration_t lease_duration;
+ struct ldur_fhnode *lease_duration; /* fibheap node to keep lease duration for this writer, NULL in case of automatic liveliness with inifite duration */
struct whc *whc; /* WHC tracking history, T-L durability service history + samples by sequence number for retransmit */
uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */
nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */
@@ -300,7 +308,11 @@ struct proxy_participant
unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
struct nn_plist *plist; /* settings/QoS for this participant */
- ddsrt_atomic_voidp_t lease; /* lease object for this participant, for automatic leases */
+ ddsrt_atomic_voidp_t minl_auto; /* lease object for shortest automatic liveliness pwr's lease (includes this proxypp's lease) */
+ ddsrt_fibheap_t leaseheap_auto; /* keeps leases for this proxypp and leases for pwrs (with liveliness automatic) */
+ ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness pwr's lease */
+ ddsrt_fibheap_t leaseheap_man; /* keeps leases for this proxypp and leases for pwrs (with liveliness manual-by-participant) */
+ struct lease *lease; /* lease for this proxypp */
struct addrset *as_default; /* default address set to use for user data traffic */
struct addrset *as_meta; /* default address set to use for discovery traffic */
struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */
@@ -357,6 +369,7 @@ struct proxy_writer {
unsigned deliver_synchronously: 1; /* iff 1, delivery happens straight from receive thread for non-historical data; else through delivery queue "dqueue" */
unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */
unsigned local_matching_inprogress: 1; /* iff 1, we are still busy matching local readers; this is so we don't deliver incoming data to some but not all readers initially */
+ unsigned alive: 1; /* iff 1, the proxy writer is alive (lease for this proxy writer is not expired) */
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif
@@ -367,6 +380,7 @@ struct proxy_writer {
struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */
ddsi2direct_directread_cb_t ddsi2direct_cb;
void *ddsi2direct_cbarg;
+ struct lease *lease;
};
struct proxy_reader {
@@ -537,10 +551,14 @@ dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *p
void update_participant_plist (struct participant *pp, const struct nn_plist *plist);
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid);
+/* Gets the interval for PMD messages, which is the minimal lease duration for writers
+ with auto liveliness in this participant, or the participants lease duration if shorter */
+DDS_EXPORT dds_duration_t pp_get_pmd_interval(struct participant *pp);
+
/* To obtain the builtin writer to be used for publishing SPDP, SEDP,
PMD stuff for PP and its endpoints, given the entityid. If PP has
its own writer, use it; else use the privileged participant. */
-struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid);
+DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid);
/* To create a new DDSI writer or reader belonging to participant with
GUID "ppguid". May return NULL if participant unknown or
@@ -612,6 +630,7 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bool delete_from_as_disc);
+
/* To create a new proxy writer or reader; the proxy participant is
determined from the GUID and must exist. */
int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq);
@@ -626,12 +645,15 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
reader or writer. Actual deletion is scheduled in the future, when
no outstanding references may still exist (determined by checking
thread progress, &c.). */
-int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
+int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit, bool proxypp_locked);
int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
+int proxy_writer_set_alive_locked (struct q_globals *gv, struct proxy_writer *pwr, bool alive);
+int proxy_writer_set_alive_guid (struct q_globals *gv, const struct ddsi_guid *guid, bool alive);
+
int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
diff --git a/src/core/ddsi/include/dds/ddsi/q_ephash.h b/src/core/ddsi/include/dds/ddsi/q_ephash.h
index c0a613e..630d6ad 100644
--- a/src/core/ddsi/include/dds/ddsi/q_ephash.h
+++ b/src/core/ddsi/include/dds/ddsi/q_ephash.h
@@ -36,7 +36,7 @@ struct ddsi_guid;
EK_PROXY_READER
};
#define EK_NKINDS ((int) EK_PROXY_READER + 1)
-
+
struct ephash_enum
{
struct ddsrt_chh_iter it;
@@ -80,15 +80,15 @@ void ephash_remove_reader_guid (struct ephash *eh, struct reader *rd);
void ephash_remove_proxy_writer_guid (struct ephash *eh, struct proxy_writer *pwr);
void ephash_remove_proxy_reader_guid (struct ephash *eh, struct proxy_reader *prd);
-void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct ddsi_guid *guid);
-void *ephash_lookup_guid (const struct ephash *eh, const struct ddsi_guid *guid, enum entity_kind kind);
+DDS_EXPORT void *ephash_lookup_guid_untyped (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT void *ephash_lookup_guid (const struct ephash *eh, const struct ddsi_guid *guid, enum entity_kind kind);
-struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
-struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
-struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
-struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
-struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
-struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct ddsi_guid *guid);
+DDS_EXPORT struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct ddsi_guid *guid);
/* Enumeration of entries in the hash table:
diff --git a/src/core/ddsi/include/dds/ddsi/q_lease.h b/src/core/ddsi/include/dds/ddsi/q_lease.h
index c9a8831..d8f2964 100644
--- a/src/core/ddsi/include/dds/ddsi/q_lease.h
+++ b/src/core/ddsi/include/dds/ddsi/q_lease.h
@@ -12,6 +12,9 @@
#ifndef Q_LEASE_H
#define Q_LEASE_H
+#include "dds/ddsrt/atomics.h"
+#include "dds/ddsrt/fibheap.h"
+#include "dds/ddsrt/time.h"
#include "dds/ddsi/q_time.h"
#if defined (__cplusplus)
@@ -20,21 +23,30 @@ extern "C" {
struct receiver_state;
struct participant;
-struct lease;
struct entity_common;
struct q_globals; /* FIXME: make a special for the lease admin */
+struct lease {
+ ddsrt_fibheap_node_t heapnode;
+ ddsrt_fibheap_node_t pp_heapnode;
+ nn_etime_t tsched; /* access guarded by leaseheap_lock */
+ ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */
+ dds_duration_t tdur; /* constant (renew depends on it) */
+ struct entity_common *entity; /* constant */
+};
+
+int compare_lease_tsched (const void *va, const void *vb);
+int compare_lease_tdur (const void *va, const void *vb);
void lease_management_init (struct q_globals *gv);
void lease_management_term (struct q_globals *gv);
struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e);
+struct lease *lease_clone (const struct lease *l);
void lease_register (struct lease *l);
void lease_free (struct lease *l);
void lease_renew (struct lease *l, nn_etime_t tnow);
void lease_set_expiry (struct lease *l, nn_etime_t when);
int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow);
-void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len);
-
#if defined (__cplusplus)
}
#endif
diff --git a/src/core/ddsi/src/ddsi_pmd.c b/src/core/ddsi/src/ddsi_pmd.c
new file mode 100644
index 0000000..f187abb
--- /dev/null
+++ b/src/core/ddsi/src/ddsi_pmd.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright(c) 2006 to 2019 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
+#include "dds/ddsi/ddsi_pmd.h"
+#include "dds/ddsi/ddsi_serdata.h"
+#include "dds/ddsi/ddsi_serdata_default.h"
+#include "dds/ddsi/ddsi_tkmap.h"
+#include "dds/ddsi/q_bswap.h"
+#include "dds/ddsi/q_entity.h"
+#include "dds/ddsi/q_globals.h"
+#include "dds/ddsi/q_lease.h"
+#include "dds/ddsi/q_log.h"
+#include "dds/ddsi/q_misc.h"
+#include "dds/ddsi/q_protocol.h"
+#include "dds/ddsi/q_radmin.h"
+#include "dds/ddsi/q_rtps.h"
+#include "dds/ddsi/q_time.h"
+#include "dds/ddsi/q_transmit.h"
+#include "dds/ddsi/q_xmsg.h"
+
+#include "dds/ddsi/sysdeps.h"
+
+static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len)
+{
+ const unsigned char *c = data;
+ size_t i;
+ GVTRACE ("%s<", msg);
+ for (i = 0; i < len; i++)
+ {
+ if (32 < c[i] && c[i] <= 127)
+ GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
+ else
+ GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
+ }
+ GVTRACE (">");
+}
+
+void write_pmd_message_guid (struct q_globals * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind)
+{
+ struct thread_state1 * const ts1 = lookup_thread_state ();
+ thread_state_awake (ts1, gv);
+ struct participant *pp = ephash_lookup_participant_guid (gv->guid_hash, pp_guid);
+ if (pp == NULL)
+ GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (*pp_guid));
+ else
+ write_pmd_message (ts1, NULL, pp, pmd_kind);
+ thread_state_asleep (ts1);
+}
+
+void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind)
+{
+#define PMD_DATA_LENGTH 1
+ struct q_globals * const gv = pp->e.gv;
+ struct writer *wr;
+ union {
+ ParticipantMessageData_t pmd;
+ char pad[offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH];
+ } u;
+ struct ddsi_serdata *serdata;
+ struct ddsi_tkmap_instance *tk;
+
+ if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER)) == NULL)
+ {
+ GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid));
+ return;
+ }
+
+ u.pmd.participantGuidPrefix = nn_hton_guid_prefix (pp->e.guid.prefix);
+ u.pmd.kind = ddsrt_toBE4u (pmd_kind);
+ u.pmd.length = PMD_DATA_LENGTH;
+ memset (u.pmd.value, 0, u.pmd.length);
+
+ struct ddsi_rawcdr_sample raw = {
+ .blob = &u,
+ .size = offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH,
+ .key = &u.pmd,
+ .keysize = 16
+ };
+ serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw);
+ serdata->timestamp = now ();
+
+ tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata);
+ write_sample_nogc (ts1, xp, wr, serdata, tk);
+ ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
+#undef PMD_DATA_LENGTH
+}
+
+void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
+{
+ const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
+ const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN);
+ struct proxy_participant *proxypp;
+ ddsi_guid_t ppguid;
+ struct lease *l;
+ RSTTRACE (" PMD ST%x", statusinfo);
+ if (data->identifier != CDR_LE && data->identifier != CDR_BE)
+ {
+ RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier));
+ return;
+ }
+
+ switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER))
+ {
+ case 0:
+ if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader))
+ debug_print_rawdata (rst->gv, " SHORT1", data, len);
+ else
+ {
+ const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
+ ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
+ uint32_t kind = ntohl (pmd->kind);
+ uint32_t length = bswap ? ddsrt_bswap4u (pmd->length) : pmd->length;
+ RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length);
+ if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length)
+ debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value));
+ else
+ debug_print_rawdata (rst->gv, "", pmd->value, length);
+ ppguid.prefix = p;
+ ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
+ if ((proxypp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL)
+ RSTTRACE (" PPunknown");
+
+ if (kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE &&
+ (l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL)
+ {
+ /* Renew lease for entity with shortest manual-by-participant lease */
+ lease_renew (l, now_et ());
+ }
+ }
+ break;
+
+ case NN_STATUSINFO_DISPOSE:
+ case NN_STATUSINFO_UNREGISTER:
+ case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
+ /* Serialized key; BE or LE doesn't matter as both fields are
+ defined as octets. */
+ if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t))
+ debug_print_rawdata (rst->gv, " SHORT3", data, len);
+ else
+ {
+ ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1)));
+ ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
+ if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0)
+ RSTTRACE (" unknown");
+ else
+ RSTTRACE (" delete");
+ }
+ break;
+ }
+ RSTTRACE ("\n");
+}
diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c
index dc07149..b53b35b 100644
--- a/src/core/ddsi/src/q_ddsi_discovery.c
+++ b/src/core/ddsi/src/q_ddsi_discovery.c
@@ -43,6 +43,7 @@
#include "dds/ddsi/q_lease.h"
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/q_feature_check.h"
+#include "dds/ddsi/ddsi_pmd.h"
static int get_locator (const struct q_globals *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet)
{
@@ -486,10 +487,8 @@ static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const dd
{
struct ephash_enum_proxy_participant it;
struct proxy_participant *pp, *d2pp;
- struct lease *d2pp_lease;
if ((d2pp = ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid)) == NULL)
return;
- d2pp_lease = ddsrt_atomic_ldvoidp (&d2pp->lease);
ephash_enum_proxy_participant_init (&it, gv->guid_hash);
while ((pp = ephash_enum_proxy_participant_next (&it)) != NULL)
{
@@ -499,7 +498,7 @@ static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const dd
ddsrt_mutex_lock (&pp->e.lock);
pp->privileged_pp_guid = *ddsi2guid;
ddsrt_mutex_unlock (&pp->e.lock);
- proxy_participant_reassign_lease (pp, d2pp_lease);
+ proxy_participant_reassign_lease (pp, d2pp->lease);
GVTRACE ("\n");
if (ephash_lookup_proxy_participant_guid (gv->guid_hash, ddsi2guid) == NULL)
@@ -614,9 +613,10 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
int interesting = 0;
RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid));
/* SPDP processing is so different from normal processing that we are
- even skipping the automatic lease renewal. Therefore do it regardless
- of gv.config.arrival_of_data_asserts_pp_and_ep_liveliness. */
- lease_renew (ddsrt_atomic_ldvoidp (&proxypp->lease), now_et ());
+ even skipping the automatic lease renewal. Note that proxy writers
+ that are not alive are not set alive here. This is done only when
+ data is received from a particular pwr (in handle_regular) */
+ lease_renew (ddsrt_atomic_ldvoidp (&proxypp->minl_auto), now_et ());
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->implicitly_created || seq > proxypp->seq)
{
@@ -1247,7 +1247,7 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn
GVLOGDISC (" "PGUIDFMT" attach-to-DS "PGUIDFMT, PGUID(pp->e.guid), PGUIDPREFIX(*src_guid_prefix), pp->privileged_pp_guid.entityid.u);
ddsrt_mutex_lock (&pp->e.lock);
pp->privileged_pp_guid.prefix = *src_guid_prefix;
- lease_set_expiry(ddsrt_atomic_ldvoidp(&pp->lease), never);
+ lease_set_expiry(pp->lease, never);
ddsrt_mutex_unlock (&pp->e.lock);
}
GVLOGDISC ("\n");
@@ -1358,7 +1358,7 @@ static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *data
GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid));
if (is_writer_entityid (datap->endpoint_guid.entityid))
{
- res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0);
+ res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0, false);
}
else
{
@@ -1768,7 +1768,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
handle_SEDP (sampleinfo->rst, sampleinfo->seq, timestamp, statusinfo, datap, datasz);
break;
case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
- handle_PMD (sampleinfo->rst, timestamp, statusinfo, datap, datasz);
+ handle_pmd_message (sampleinfo->rst, timestamp, statusinfo, datap, datasz);
break;
case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER:
handle_SEDP_CM (sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz);
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index 85ae9c3..8967abb 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -13,6 +13,7 @@
#include
#include
+#include "dds/ddsrt/fibheap.h"
#include "dds/ddsrt/heap.h"
#include "dds/ddsrt/log.h"
#include "dds/ddsrt/sockets.h"
@@ -403,6 +404,16 @@ static void remove_deleted_participant_guid (struct deleted_participants_admin *
/* PARTICIPANT ------------------------------------------------------ */
+static int compare_ldur (const void *va, const void *vb)
+{
+ const struct ldur_fhnode *a = va;
+ const struct ldur_fhnode *b = vb;
+ return (a->ldur == b->ldur) ? 0 : (a->ldur < b->ldur) ? -1 : 1;
+}
+
+/* used in participant for keeping writer liveliness renewal */
+const ddsrt_fibheap_def_t ldur_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct ldur_fhnode, heapnode), compare_ldur);
+
static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, const dds_qos_t *xqos, nn_wctime_t timestamp)
{
uint64_t mask;
@@ -515,6 +526,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *
ddsrt_mutex_init (&pp->refc_lock);
inverse_uint32_set_init(&pp->avail_entityids.x, 1, UINT32_MAX / NN_ENTITYID_ALLOCSTEP);
pp->lease_duration = gv->config.lease_duration;
+ ddsrt_fibheap_init (&ldur_fhdef, &pp->ldur_auto_wr);
pp->plist = ddsrt_malloc (sizeof (*pp->plist));
nn_plist_copy (pp->plist, plist);
nn_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0);
@@ -1003,6 +1015,19 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
return ephash_lookup_writer_guid (pp->e.gv->guid_hash, &bwr_guid);
}
+dds_duration_t pp_get_pmd_interval (struct participant *pp)
+{
+ struct ldur_fhnode *ldur_node;
+ dds_duration_t intv;
+ ddsrt_mutex_lock (&pp->e.lock);
+ ldur_node = ddsrt_fibheap_min (&ldur_fhdef, &pp->ldur_auto_wr);
+ intv = (ldur_node != NULL) ? ldur_node->ldur : T_NEVER;
+ if (pp->lease_duration < intv)
+ intv = pp->lease_duration;
+ ddsrt_mutex_unlock (&pp->e.lock);
+ return intv;
+}
+
/* WRITER/READER/PROXY-WRITER/PROXY-READER CONNECTION ---------------
These are all located in a separate section because they are so
@@ -1463,14 +1488,14 @@ static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struc
}
}
-static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr)
+static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
{
struct rd_pwr_match *m;
ddsrt_mutex_lock (&rd->e.lock);
- if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL)
+ if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL && unmatch)
ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m);
ddsrt_mutex_unlock (&rd->e.lock);
if (m != NULL)
@@ -1491,11 +1516,15 @@ static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struc
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
- data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
- (rd->status_cb) (rd->status_cb_entity, &data);
+ if (unmatch)
+ {
+ data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
+ }
}
}
- free_rd_pwr_match (pwr->e.gv, m);
+ if (unmatch)
+ free_rd_pwr_match (pwr->e.gv, m);
}
}
@@ -2857,13 +2886,17 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se
{
wr->heartbeat_xevent = NULL;
}
+
assert (wr->xqos->present & QP_LIVELINESS);
- if (wr->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || wr->xqos->liveliness.lease_duration != T_NEVER)
+ if (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC && wr->xqos->liveliness.lease_duration != T_NEVER)
{
- ELOGDISC (wr, "writer "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n",
- PGUID (wr->e.guid), (int) wr->xqos->liveliness.kind, wr->xqos->liveliness.lease_duration);
+ wr->lease_duration = ddsrt_malloc (sizeof(*wr->lease_duration));
+ wr->lease_duration->ldur = wr->xqos->liveliness.lease_duration;
+ }
+ else
+ {
+ wr->lease_duration = NULL;
}
- wr->lease_duration = T_NEVER; /* FIXME */
wr->whc = whc;
if (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST)
@@ -2930,10 +2963,18 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g
match_writer_with_local_readers (wr, tnow);
sedp_write_writer (wr);
- if (wr->lease_duration != T_NEVER)
+ if (wr->lease_duration != NULL && wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC)
{
- nn_mtime_t tsched = { 0 };
- (void) resched_xevent_if_earlier (pp->pmd_update_xevent, tsched);
+ assert (wr->lease_duration->ldur != T_NEVER);
+ assert (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE));
+
+ /* Store writer lease duration in participant's heap in case of automatic liveliness */
+ ddsrt_mutex_lock (&pp->e.lock);
+ ddsrt_fibheap_insert (&ldur_fhdef, &pp->ldur_auto_wr, wr->lease_duration);
+ ddsrt_mutex_unlock (&pp->e.lock);
+
+ /* Trigger pmd update */
+ (void) resched_xevent_if_earlier (pp->pmd_update_xevent, now_mt ());
}
return 0;
@@ -3026,6 +3067,11 @@ static void gc_delete_writer (struct gcreq *gcreq)
reader_drop_local_connection (&m->rd_guid, wr);
free_wr_rd_match (m);
}
+ if (wr->lease_duration != NULL)
+ {
+ assert (wr->lease_duration->ldur == DDS_DURATION_INVALID);
+ ddsrt_free (wr->lease_duration);
+ }
/* Do last gasp on SEDP and free writer. */
if (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE))
@@ -3106,6 +3152,13 @@ dds_return_t delete_writer_nolinger_locked (struct writer *wr)
local_reader_ary_setinvalid (&wr->rdary);
ephash_remove_writer_guid (wr->e.gv->guid_hash, wr);
writer_set_state (wr, WRST_DELETING);
+ if (wr->lease_duration != NULL) {
+ ddsrt_mutex_lock (&wr->c.pp->e.lock);
+ ddsrt_fibheap_delete (&ldur_fhdef, &wr->c.pp->ldur_auto_wr, wr->lease_duration);
+ ddsrt_mutex_unlock (&wr->c.pp->e.lock);
+ wr->lease_duration->ldur = DDS_DURATION_INVALID;
+ resched_xevent_if_earlier (wr->c.pp->pmd_update_xevent, now_mt ());
+ }
gcreq_writer (wr);
return 0;
}
@@ -3352,11 +3405,6 @@ static dds_return_t new_reader_guid
ddsi_rhc_set_qos (rd->rhc, rd->xqos);
}
assert (rd->xqos->present & QP_LIVELINESS);
- if (rd->xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC || rd->xqos->liveliness.lease_duration != T_NEVER)
- {
- ELOGDISC (rd, "reader "PGUIDFMT": incorrectly treating it as of automatic liveliness kind with lease duration = inf (%d, %"PRId64")\n",
- PGUID (rd->e.guid), (int) rd->xqos->liveliness.kind, rd->xqos->liveliness.lease_duration);
- }
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
rd->as = new_addrset ();
@@ -3533,6 +3581,8 @@ void update_reader_qos (struct reader *rd, const dds_qos_t *xqos)
}
/* PROXY-PARTICIPANT ------------------------------------------------ */
+const ddsrt_fibheap_def_t lease_fhdef_proxypp = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, pp_heapnode), compare_lease_tdur);
+
static void gc_proxy_participant_lease (struct gcreq *gcreq)
{
lease_free (gcreq->arg);
@@ -3558,13 +3608,99 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
{
const nn_etime_t never = { T_NEVER };
struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
- struct lease *oldlease = ddsrt_atomic_ldvoidp (&proxypp->lease);
+ struct lease *oldlease = proxypp->lease;
lease_renew (oldlease, never);
gcreq->arg = oldlease;
gcreq_enqueue (gcreq);
proxypp->owns_lease = 0;
}
- ddsrt_atomic_stvoidp (&proxypp->lease, newlease);
+ proxypp->lease = newlease;
+ /* FIXME: replace proxypp lease in leaseheap_auto? */
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+}
+
+static void proxy_participant_replace_minl (struct proxy_participant *proxypp, bool manbypp, struct lease *lnew)
+{
+ const nn_etime_t never = { T_NEVER };
+ struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
+ struct lease *lease_old = (struct lease *) ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto);
+ lease_renew (lease_old, never);
+ gcreq->arg = (void *) lease_old;
+ gcreq_enqueue (gcreq);
+ ddsrt_atomic_stvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto, (void *) lnew);
+}
+
+static void proxy_participant_add_pwr_lease (struct proxy_participant * proxypp, const struct proxy_writer * pwr)
+{
+ struct lease *minl_prev;
+ struct lease *minl_new;
+ ddsrt_fibheap_t *lh;
+ bool manbypp;
+
+ assert (pwr->lease != NULL);
+ manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT);
+ ddsrt_mutex_lock (&proxypp->e.lock);
+ lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto;
+ minl_prev = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
+ ddsrt_fibheap_insert (&lease_fhdef_proxypp, lh, pwr->lease);
+ minl_new = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
+ /* if inserted lease is new shortest lease */
+ if (proxypp->owns_lease && minl_prev != minl_new)
+ {
+ nn_etime_t texp = add_duration_to_etime (now_et (), minl_new->tdur);
+ struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity);
+ if (manbypp && minl_prev == NULL)
+ {
+ assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
+ ddsrt_atomic_stvoidp (&proxypp->minl_man, (void *) lnew);
+ }
+ else
+ {
+ proxy_participant_replace_minl (proxypp, manbypp, lnew);
+ }
+ lease_register (lnew);
+ }
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+}
+
+static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant * proxypp, struct proxy_writer * pwr)
+{
+ struct lease *minl;
+ bool manbypp;
+ ddsrt_fibheap_t *lh;
+
+ assert (pwr->lease != NULL);
+ manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT);
+ lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto;
+ minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
+ ddsrt_fibheap_delete (&lease_fhdef_proxypp, lh, pwr->lease);
+ /* if pwr with min lease is removed: update proxypp lease to use new minimal duration */
+ if (proxypp->owns_lease && pwr->lease == minl)
+ {
+ if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh)) != NULL)
+ {
+ dds_duration_t trem = minl->tdur - pwr->lease->tdur;
+ nn_etime_t texp = add_duration_to_etime (now_et(), trem >= 0 ? trem : 0);
+ struct lease *lnew = lease_new (texp, minl->tdur, minl->entity);
+ proxy_participant_replace_minl (proxypp, manbypp, lnew);
+ lease_register (lnew);
+ }
+ else if (manbypp)
+ {
+ proxy_participant_replace_minl (proxypp, manbypp, NULL);
+ }
+ else
+ {
+ /* minl should not be null for leaseheap_auto because proxypp's lease is in */
+ assert (false);
+ }
+ }
+}
+
+static void proxy_participant_remove_pwr_lease (struct proxy_participant * proxypp, struct proxy_writer * pwr)
+{
+ ddsrt_mutex_lock (&proxypp->e.lock);
+ proxy_participant_remove_pwr_lease_locked (proxypp, pwr);
ddsrt_mutex_unlock (&proxypp->e.lock);
}
@@ -3628,16 +3764,36 @@ void new_proxy_participant
privpp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &proxypp->privileged_pp_guid);
if (privpp != NULL && privpp->is_ddsi2_pp)
{
- ddsrt_atomic_stvoidp (&proxypp->lease, ddsrt_atomic_ldvoidp (&privpp->lease));
+ proxypp->lease = privpp->lease;
proxypp->owns_lease = 0;
}
else
{
- /* Lease duration is meaningless when the lease never expires, but when proxy participants are created implicitly because of endpoint discovery from a cloud service, we do want the lease to expire eventually when the cloud discovery service disappears and never reappears. The normal data path renews the lease, so if the lease expiry is changed after the DS disappears but data continues to flow (even if it is only a single sample) the proxy participant would immediately go back to a non-expiring lease with no further triggers for deleting it. Instead, we take tlease_dur == NEVER as a special value meaning a lease that doesn't expire now and that has a "reasonable" lease duration. That way the lease renewal in the data path is fine, and we only need to do something special in SEDP handling. */
+ /* Lease duration is meaningless when the lease never expires, but when proxy participants are
+ created implicitly because of endpoint discovery from a cloud service, we do want the lease to expire
+ eventually when the cloud discovery service disappears and never reappears. The normal data path renews
+ the lease, so if the lease expiry is changed after the DS disappears but data continues to flow (even if
+ it is only a single sample) the proxy participant would immediately go back to a non-expiring lease with
+ no further triggers for deleting it. Instead, we take tlease_dur == NEVER as a special value meaning a
+ lease that doesn't expire now and that has a "reasonable" lease duration. That way the lease renewal in
+ the data path is fine, and we only need to do something special in SEDP handling. */
nn_etime_t texp = add_duration_to_etime (now_et(), tlease_dur);
dds_duration_t dur = (tlease_dur == T_NEVER) ? gv->config.lease_duration : tlease_dur;
- ddsrt_atomic_stvoidp (&proxypp->lease, lease_new (texp, dur, &proxypp->e));
+ proxypp->lease = lease_new (texp, dur, &proxypp->e);
proxypp->owns_lease = 1;
+
+ /* Init heap for leases */
+ ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
+ ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_man);
+
+ /* Add the proxypp lease to heap so that monitoring liveliness will include this lease
+ and uses the shortest duration for proxypp and all its pwr's (with automatic liveliness) */
+ ddsrt_fibheap_insert (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
+
+ /* Set the shortest lease for auto liveliness: clone proxypp's lease (as there are no pwr's
+ at this point, this is the shortest lease) */
+ ddsrt_atomic_stvoidp (&proxypp->minl_auto, (void *) lease_clone (proxypp->lease));
+ ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL);
}
}
@@ -3746,15 +3902,12 @@ void new_proxy_participant
nn_plist_fini (&plist_rd);
}
- /* Register lease, but be careful not to accidentally re-register
- DDSI2's lease, as we may have become dependent on DDSI2 any time
- after ephash_insert_proxy_participant_guid even if
- privileged_pp_guid was NULL originally */
+ /* Register lease for auto liveliness, but be careful not to accidentally re-register
+ DDSI2's lease, as we may have become dependent on DDSI2 any time after
+ ephash_insert_proxy_participant_guid even if privileged_pp_guid was NULL originally */
ddsrt_mutex_lock (&proxypp->e.lock);
-
if (proxypp->owns_lease)
- lease_register (ddsrt_atomic_ldvoidp (&proxypp->lease));
-
+ lease_register (ddsrt_atomic_ldvoidp (&proxypp->minl_auto));
builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true);
ddsrt_mutex_unlock (&proxypp->e.lock);
}
@@ -3840,7 +3993,15 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
nn_plist_fini (proxypp->plist);
ddsrt_free (proxypp->plist);
if (proxypp->owns_lease)
- lease_free (ddsrt_atomic_ldvoidp (&proxypp->lease));
+ {
+ ddsrt_mutex_lock (&proxypp->e.lock);
+ ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
+ assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL);
+ assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+ lease_free (ddsrt_atomic_ldvoidp (&proxypp->minl_auto));
+ lease_free (proxypp->lease);
+ }
entity_common_fini (&proxypp->e);
remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
ddsrt_free (proxypp);
@@ -3901,7 +4062,8 @@ static void delete_or_detach_dependent_pp (struct proxy_participant *p, struct p
/* Clear dependency (but don't touch entity id, which must be 0x1c1) and set the lease ticking */
ELOGDISC (p, PGUIDFMT" detach-from-DS "PGUIDFMT"\n", PGUID(p->e.guid), PGUID(proxypp->e.guid));
memset (&p->privileged_pp_guid.prefix, 0, sizeof (p->privileged_pp_guid.prefix));
- lease_set_expiry (ddsrt_atomic_ldvoidp (&p->lease), texp);
+ lease_set_expiry (p->lease, texp);
+ /* FIXME: replace in p->leaseheap_auto and get new minl_auto */
ddsrt_mutex_unlock (&p->e.lock);
}
}
@@ -3936,7 +4098,7 @@ static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp
struct entity_common *e = entity_common_from_proxy_endpoint_common (c);
if (is_writer_entityid (e->guid.entityid))
{
- ret = delete_proxy_writer (proxypp->e.gv, &e->guid, timestamp, isimplicit);
+ ret = delete_proxy_writer (proxypp->e.gv, &e->guid, timestamp, isimplicit, true);
}
else
{
@@ -4084,6 +4246,7 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
pwr->last_fragnum = ~0u;
pwr->nackfragcount = 0;
pwr->last_fragnum_reset = 0;
+ pwr->alive = 1;
ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, 1);
if (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor)) {
/* The DDSI built-in proxy writers always deliver
@@ -4107,17 +4270,13 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
#endif
assert (pwr->c.xqos->present & QP_LIVELINESS);
- if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_AUTOMATIC)
- GVLOGDISC (" FIXME: only AUTOMATIC liveliness supported");
-#if 0
- pwr->tlease_dur = nn_from_ddsi_duration (pwr->c.xqos->liveliness.lease_duration);
- if (pwr->tlease_dur == 0)
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
{
- GVLOGDISC (" FIXME: treating lease_duration=0 as inf");
- pwr->tlease_dur = T_NEVER;
+ nn_etime_t texpire = add_duration_to_etime (now_et (), pwr->c.xqos->liveliness.lease_duration);
+ pwr->lease = lease_new (texpire, pwr->c.xqos->liveliness.lease_duration, &pwr->e);
+ if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxy_participant_add_pwr_lease (proxypp, pwr);
}
- pwr->tlease_end = add_duration_to_wctime (tnow, pwr->tlease_dur);
-#endif
if (isreliable)
{
@@ -4251,12 +4410,11 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
struct proxy_writer *pwr = gcreq->arg;
ELOGDISC (pwr, "gc_delete_proxy_writer(%p, "PGUIDFMT")\n", (void *) gcreq, PGUID (pwr->e.guid));
gcreq_free (gcreq);
-
while (!ddsrt_avl_is_empty (&pwr->readers))
{
struct pwr_rd_match *m = ddsrt_avl_root_non_empty (&pwr_readers_treedef, &pwr->readers);
ddsrt_avl_delete (&pwr_readers_treedef, &pwr->readers, m);
- reader_drop_connection (&m->rd_guid, pwr);
+ reader_drop_connection (&m->rd_guid, pwr, true);
update_reader_init_acknack_count (&pwr->e.gv->logconfig, pwr->e.gv->guid_hash, &m->rd_guid, m->count);
free_pwr_rd_match (m);
}
@@ -4267,7 +4425,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
ddsrt_free (pwr);
}
-int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
+int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit, bool proxypp_locked)
{
struct proxy_writer *pwr;
(void)isimplicit;
@@ -4288,10 +4446,54 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false);
ephash_remove_proxy_writer_guid (gv->guid_hash, pwr);
ddsrt_mutex_unlock (&gv->lock);
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
+ {
+ ddsrt_mutex_lock (&pwr->e.lock);
+ if (pwr->alive && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxypp_locked ? proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr) : proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
+ ddsrt_mutex_unlock (&pwr->e.lock);
+ lease_free (pwr->lease);
+ }
gcreq_proxy_writer (pwr);
return 0;
}
+int proxy_writer_set_alive_locked (struct q_globals *gv, struct proxy_writer *pwr, bool alive)
+{
+ ddsrt_avl_iter_t it;
+ GVLOGDISC ("proxy_writer_set_alive_locked ("PGUIDFMT") ", PGUID (pwr->e.guid));
+ assert (pwr->alive != alive);
+ pwr->alive = alive;
+ GVLOGDISC ("- alive=%d\n", pwr->alive);
+ if (!pwr->alive)
+ {
+ for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
+ reader_drop_connection (&m->rd_guid, pwr, false);
+ }
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ pwr->alive ? proxy_participant_add_pwr_lease (pwr->c.proxypp, pwr) : proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
+ return 0;
+}
+
+int proxy_writer_set_alive_guid (struct q_globals *gv, const struct ddsi_guid *guid, bool alive)
+{
+ struct proxy_writer *pwr;
+ int ret;
+ ddsrt_mutex_lock (&gv->lock);
+ if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL)
+ {
+ ddsrt_mutex_unlock (&gv->lock);
+ GVLOGDISC ("proxy_writer_set_alive_guid ("PGUIDFMT") - unknown\n", PGUID (*guid));
+ return DDS_RETCODE_BAD_PARAMETER;
+ }
+ ddsrt_mutex_unlock (&gv->lock);
+
+ ddsrt_mutex_lock (&pwr->e.lock);
+ ret = proxy_writer_set_alive_locked (gv, pwr, alive);
+ ddsrt_mutex_unlock (&pwr->e.lock);
+ return ret;
+}
+
/* PROXY-READER ----------------------------------------------------- */
int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index 18a0fbf..f86d3f7 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -43,30 +43,27 @@
!= 0 -- and note that it had better be 2's complement machine! */
#define TSCHED_NOT_ON_HEAP INT64_MIN
-struct lease {
- ddsrt_fibheap_node_t heapnode;
- nn_etime_t tsched; /* access guarded by leaseheap_lock */
- ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */
- dds_duration_t tdur; /* constant (renew depends on it) */
- struct entity_common *entity; /* constant */
-};
-
-static int compare_lease_tsched (const void *va, const void *vb);
-
-static const ddsrt_fibheap_def_t lease_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, heapnode), compare_lease_tsched);
+const ddsrt_fibheap_def_t lease_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER (offsetof (struct lease, heapnode), compare_lease_tsched);
static void force_lease_check (struct gcreq_queue *gcreq_queue)
{
gcreq_enqueue (gcreq_new (gcreq_queue, gcreq_free));
}
-static int compare_lease_tsched (const void *va, const void *vb)
+int compare_lease_tsched (const void *va, const void *vb)
{
const struct lease *a = va;
const struct lease *b = vb;
return (a->tsched.v == b->tsched.v) ? 0 : (a->tsched.v < b->tsched.v) ? -1 : 1;
}
+int compare_lease_tdur (const void *va, const void *vb)
+{
+ const struct lease *a = va;
+ const struct lease *b = vb;
+ return (a->tdur == b->tdur) ? 0 : (a->tdur < b->tdur) ? -1 : 1;
+}
+
void lease_management_init (struct q_globals *gv)
{
ddsrt_mutex_init (&gv->leaseheap_lock);
@@ -92,6 +89,20 @@ struct lease *lease_new (nn_etime_t texpire, dds_duration_t tdur, struct entity_
return l;
}
+/**
+ * Returns a clone of the provided lease. Note that this function does not use
+ * locking and should therefore only be called from a context where lease 'l'
+ * cannot be changed by another thread during the function call.
+ */
+struct lease *lease_clone (const struct lease *l)
+{
+ nn_etime_t texp;
+ dds_duration_t tdur;
+ texp.v = (int64_t) ddsrt_atomic_ld64 (&l->tend);
+ tdur = l->tdur;
+ return lease_new (texp, tdur, l->entity);
+}
+
void lease_register (struct lease *l) /* FIXME: make lease admin struct */
{
struct q_globals * const gv = l->entity->gv;
@@ -116,7 +127,10 @@ void lease_free (struct lease *l)
GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
ddsrt_mutex_lock (&gv->leaseheap_lock);
if (l->tsched.v != TSCHED_NOT_ON_HEAP)
+ {
ddsrt_fibheap_delete (&lease_fhdef, &gv->leaseheap, l);
+ l->tsched.v = TSCHED_NOT_ON_HEAP;
+ }
ddsrt_mutex_unlock (&gv->leaseheap_lock);
ddsrt_free (l);
@@ -126,7 +140,7 @@ void lease_free (struct lease *l)
void lease_renew (struct lease *l, nn_etime_t tnowE)
{
- struct q_globals const * const gv = l->entity->gv;
+ struct q_globals const * gv;
nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur);
/* do not touch tend if moving forward or if already expired */
@@ -137,6 +151,7 @@ void lease_renew (struct lease *l, nn_etime_t tnowE)
return;
} while (!ddsrt_atomic_cas64 (&l->tend, (uint64_t) tend, (uint64_t) tend_new.v));
+ gv = l->entity->gv;
if (gv->logconfig.c.mask & DDS_LC_TRACE)
{
int32_t tsec, tusec;
@@ -253,23 +268,17 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
switch (k)
{
- case EK_PARTICIPANT:
- delete_participant (gv, &g);
- break;
case EK_PROXY_PARTICIPANT:
delete_proxy_participant_by_guid (gv, &g, now(), 1);
break;
- case EK_WRITER:
- delete_writer_nolinger (gv, &g);
- break;
case EK_PROXY_WRITER:
- (void) delete_proxy_writer (gv, &g, now(), 1);
+ (void) proxy_writer_set_alive_guid (gv, &g, false);
break;
+ case EK_PARTICIPANT:
case EK_READER:
- delete_reader (gv, &g);
- break;
+ case EK_WRITER:
case EK_PROXY_READER:
- (void) delete_proxy_reader (gv, &g, now(), 1);
+ assert (false);
break;
}
@@ -281,83 +290,3 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
return delay;
}
-/******/
-
-static void debug_print_rawdata (const struct q_globals *gv, const char *msg, const void *data, size_t len)
-{
- const unsigned char *c = data;
- size_t i;
- GVTRACE ("%s<", msg);
- for (i = 0; i < len; i++)
- {
- if (32 < c[i] && c[i] <= 127)
- GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
- else
- GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]);
- }
- GVTRACE (">");
-}
-
-void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
-{
- const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
- const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN);
- struct proxy_participant *pp;
- ddsi_guid_t ppguid;
- RSTTRACE (" PMD ST%x", statusinfo);
- if (data->identifier != CDR_LE && data->identifier != CDR_BE)
- {
- RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier));
- return;
- }
- switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER))
- {
- case 0:
- if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader))
- debug_print_rawdata (rst->gv, " SHORT1", data, len);
- else
- {
- const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
- ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
- uint32_t kind = ntohl (pmd->kind);
- uint32_t length = bswap ? ddsrt_bswap4u (pmd->length) : pmd->length;
- RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length);
- if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length)
- debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value));
- else
- debug_print_rawdata (rst->gv, "", pmd->value, length);
- ppguid.prefix = p;
- ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
- if ((pp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL)
- RSTTRACE (" PPunknown");
- else
- {
- /* Renew lease if arrival of this message didn't already do so, also renew the lease
- of the virtual participant used for DS-discovered endpoints */
-#if 0 // FIXME: superfluous ... receipt of the message already did it */
- lease_renew (ddsrt_atomic_ldvoidp (&pp->lease), now_et ());
-#endif
- }
- }
- break;
-
- case NN_STATUSINFO_DISPOSE:
- case NN_STATUSINFO_UNREGISTER:
- case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER:
- /* Serialized key; BE or LE doesn't matter as both fields are
- defined as octets. */
- if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t))
- debug_print_rawdata (rst->gv, " SHORT3", data, len);
- else
- {
- ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1)));
- ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
- if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0)
- RSTTRACE (" unknown");
- else
- RSTTRACE (" delete");
- }
- break;
- }
- RSTTRACE ("\n");
-}
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index 5ab6472..4bea8e8 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -668,9 +668,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
return 1;
}
- /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow);
-
+ lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto), tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer!)", PGUID (src), PGUID (dst));
@@ -1134,10 +1132,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
return 1;
}
- /* liveliness is still only implemented partially (with all set to AUTOMATIC,
- BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
-
+ lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
@@ -1271,9 +1266,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
return 1;
}
- /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
-
+ lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
@@ -1398,9 +1391,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
return 1;
}
- /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->lease), tnow);
-
+ lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto), tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer)", PGUID (src), PGUID (dst));
@@ -1645,9 +1636,7 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
return 1;
}
- /* liveliness is still only implemented partially (with all set to AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
-
+ lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
ddsrt_mutex_lock (&pwr->e.lock);
if ((wn = ddsrt_avl_lookup (&pwr_readers_treedef, &pwr->readers, &dst)) == NULL)
{
@@ -2098,11 +2087,12 @@ static void clean_defrag (struct proxy_writer *pwr)
nn_defrag_notegap (pwr->defrag, 1, seq);
}
-static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo, uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup)
+static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo, uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup, bool renew_manbypp_lease)
{
struct proxy_writer *pwr;
struct nn_rsample *rsample;
ddsi_guid_t dst;
+ struct lease *lease;
dst.prefix = rst->dst_guid_prefix;
dst.entityid = msg->readerId;
@@ -2117,14 +2107,21 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
return;
}
- /* liveliness is still only implemented partially (with all set to
- AUTOMATIC, BY_PARTICIPANT, &c.), so we simply renew the proxy
- participant's lease. */
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->lease), tnow);
+ lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL && renew_manbypp_lease)
+ lease_renew (lease, tnow);
/* Shouldn't lock the full writer, but will do so for now */
ddsrt_mutex_lock (&pwr->e.lock);
+ /* FIXME: implement liveliness manual-by-topic */
+ /* if (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ lease_renew (pwr->lease, tnow);
+ */
+
+ if (!pwr->alive)
+ proxy_writer_set_alive_locked (pwr->e.gv, pwr, true);
+
/* Don't accept data when reliable readers exist and we haven't yet seen
a heartbeat telling us what the "current" sequence number of the writer
is. If no reliable readers are present, we can't request a heartbeat and
@@ -2194,7 +2191,10 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
/* Enqueue or deliver with pwr->e.lock held: to ensure no other
receive thread's data gets interleaved -- arguably delivery
needn't be exactly in-order, which would allow us to do this
- without pwr->e.lock held. */
+ without pwr->e.lock held.
+ Note that PMD is also handled here, but the pwr for PMD does not
+ use no synchronous delivery, so deliver_user_data_synchronously
+ (which asserts pwr is not built-in) is not used for PMD handling. */
if (pwr->deliver_synchronously)
{
/* FIXME: just in case the synchronous delivery runs into a delay caused
@@ -2367,24 +2367,32 @@ static int handle_Data (struct receiver_state *rst, nn_etime_t tnow, struct nn_r
unsigned submsg_offset, payload_offset;
submsg_offset = (unsigned) ((unsigned char *) msg - NN_RMSG_PAYLOAD (rmsg));
if (datap)
- {
payload_offset = (unsigned) ((unsigned char *) datap - NN_RMSG_PAYLOAD (rmsg));
- }
else
- {
payload_offset = submsg_offset + (unsigned) size;
- }
+
rdata = nn_rdata_new (rmsg, 0, sampleinfo->size, submsg_offset, payload_offset);
- if (msg->x.writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)
- /* SPDP needs special treatment: there are no proxy writers for it
- and we accept data from unknown sources */
+ if ((msg->x.writerId.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
{
- handle_SPDP (sampleinfo, rdata);
+ bool renew_manbypp_lease = true;
+ switch (msg->x.writerId.u)
+ {
+ case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER:
+ /* SPDP needs special treatment: there are no proxy writers for it and we accept data from unknown sources */
+ handle_SPDP (sampleinfo, rdata);
+ break;
+ case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
+ /* Handle PMD as a regular message, but without renewing the leases on proxypp */
+ renew_manbypp_lease = false;
+ /* fall through */
+ default:
+ handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup, renew_manbypp_lease);
+ }
}
else
{
- handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup);
+ handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, ~0u, rdata, deferred_wakeup, true);
}
}
RSTTRACE (")");
@@ -2411,12 +2419,19 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
struct nn_rdata *rdata;
unsigned submsg_offset, payload_offset;
uint32_t begin, endp1;
- if (msg->x.writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)
+ bool renew_manbypp_lease = true;
+ if ((msg->x.writerId.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
{
- DDS_CWARNING (&rst->gv->logconfig, "DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n",
- PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN),
- PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u);
- return 1;
+ switch (msg->x.writerId.u)
+ {
+ case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER:
+ DDS_CWARNING (&rst->gv->logconfig, "DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n",
+ PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN),
+ PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u);
+ return 1;
+ case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER:
+ renew_manbypp_lease = false;
+ }
}
submsg_offset = (unsigned) ((unsigned char *) msg - NN_RMSG_PAYLOAD (rmsg));
@@ -2457,7 +2472,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
wrong, it'll simply generate a request for retransmitting a
non-existent fragment. The other side SHOULD be capable of
dealing with that. */
- handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2, rdata, deferred_wakeup);
+ handle_regular (rst, tnow, rmsg, &msg->x, sampleinfo, msg->fragmentStartingNum + msg->fragmentsInSubmessage - 2, rdata, deferred_wakeup, renew_manbypp_lease);
}
RSTTRACE (")");
return 1;
diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c
index 0e939a3..de63b6f 100644
--- a/src/core/ddsi/src/q_xevent.c
+++ b/src/core/ddsi/src/q_xevent.c
@@ -37,9 +37,11 @@
#include "dds/ddsi/q_bitset.h"
#include "dds/ddsi/q_lease.h"
#include "dds/ddsi/q_xmsg.h"
+#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/ddsi_serdata_default.h"
#include "dds/ddsi/ddsi_tkmap.h"
+#include "dds/ddsi/ddsi_pmd.h"
#include "dds__whc.h"
#include "dds/ddsi/sysdeps.h"
@@ -1090,44 +1092,6 @@ static void handle_xevk_spdp (UNUSED_ARG (struct nn_xpack *xp), struct xevent *e
}
}
-static void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind)
-{
-#define PMD_DATA_LENGTH 1
- struct q_globals * const gv = pp->e.gv;
- struct writer *wr;
- union {
- ParticipantMessageData_t pmd;
- char pad[offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH];
- } u;
- struct ddsi_serdata *serdata;
- struct ddsi_tkmap_instance *tk;
-
- if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER)) == NULL)
- {
- GVTRACE ("write_pmd_message("PGUIDFMT") - builtin pmd writer not found\n", PGUID (pp->e.guid));
- return;
- }
-
- u.pmd.participantGuidPrefix = nn_hton_guid_prefix (pp->e.guid.prefix);
- u.pmd.kind = ddsrt_toBE4u (pmd_kind);
- u.pmd.length = PMD_DATA_LENGTH;
- memset (u.pmd.value, 0, u.pmd.length);
-
- struct ddsi_rawcdr_sample raw = {
- .blob = &u,
- .size = offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH,
- .key = &u.pmd,
- .keysize = 16
- };
- serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw);
- serdata->timestamp = now ();
-
- tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata);
- write_sample_nogc (ts1, xp, wr, serdata, tk);
- ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
-#undef PMD_DATA_LENGTH
-}
-
static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_xpack *xp, struct xevent *ev, nn_mtime_t tnow)
{
struct q_globals * const gv = ev->evq->gv;
@@ -1142,16 +1106,7 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_
write_pmd_message (ts1, xp, pp, PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE);
- /* QoS changes can't change lease durations. So the only thing that
- could cause trouble here is that the addition or removal of a
- writer cause the interval to change for this participant. If we
- lock pp for reading out the lease duration we are guaranteed a
- consistent value (can't assume 64-bit atomic reads on all support
- platforms!) */
- ddsrt_mutex_lock (&pp->e.lock);
- intv = pp->lease_duration;
-
- /* FIXME: need to use smallest liveliness duration of all automatic-liveliness writers */
+ intv = pp_get_pmd_interval (pp);
if (intv == T_NEVER)
{
tnext.v = T_NEVER;
@@ -1169,7 +1124,6 @@ static void handle_xevk_pmd_update (struct thread_state1 * const ts1, struct nn_
}
(void) resched_xevent_if_earlier (ev, tnext);
- ddsrt_mutex_unlock (&pp->e.lock);
}
static void handle_xevk_delete_writer (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, UNUSED_ARG (nn_mtime_t tnow))
diff --git a/src/ddsrt/include/dds/ddsrt/time.h b/src/ddsrt/include/dds/ddsrt/time.h
index a474fb4..3570801 100644
--- a/src/ddsrt/include/dds/ddsrt/time.h
+++ b/src/ddsrt/include/dds/ddsrt/time.h
@@ -59,6 +59,9 @@ typedef int64_t dds_duration_t;
/** @name Infinite timeout for relative time */
#define DDS_INFINITY ((dds_duration_t) INT64_MAX)
+/** @name Invalid duration value */
+#define DDS_DURATION_INVALID ((dds_duration_t) INT64_MIN)
+
/** @name Macro definition for time conversion to nanoseconds
@{**/
#define DDS_SECS(n) ((n) * DDS_NSECS_IN_SEC)
From 32c5a59c8fdcd22114d96be0286549a12ea16daa Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Mon, 11 Nov 2019 14:47:26 +0100
Subject: [PATCH 44/55] Additional tests for liveliness QoS and minor
refactoring
Added unit tests for (1) testing the scenario that a proxy writer writes data
after its lease is expired, to check that the status for the pwr is set to alive
again and (2) stress-testing the creation and deletetion of writers with
decreasing lease duration. In addition I've optimized the locking in
unref_proxy_participant a bit and fixed the liveliness changed callback
when a writer with expired lease (not-alive) gets alive again.
Signed-off-by: Dennis Potman
---
src/core/ddsc/src/dds_rhc_default.c | 2 +-
src/core/ddsc/tests/liveliness.c | 162 ++++++++++++++++++++++++++--
src/core/ddsi/src/q_entity.c | 54 ++++++----
src/core/ddsi/src/q_lease.c | 2 +
4 files changed, 191 insertions(+), 29 deletions(-)
diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c
index 9f84ec3..ff19588 100644
--- a/src/core/ddsc/src/dds_rhc_default.c
+++ b/src/core/ddsc/src/dds_rhc_default.c
@@ -2394,7 +2394,7 @@ static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_
ddsrt_atomic_st32 (&cond->m_entity.m_status.m_trigger, trigger);
dds_entity_status_signal (&cond->m_entity, DDS_DATA_AVAILABLE_STATUS);
}
-
+
TRACE ("add_readcondition(%p, %"PRIx32", %"PRIx32", %"PRIx32") => %p qminv %"PRIx32" ; rhc %"PRIu32" conds\n",
(void *) rhc, cond->m_sample_states, cond->m_view_states,
cond->m_instance_states, (void *) cond, cond->m_qminv, rhc->nconds);
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index c5bfe49..a706568 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -31,8 +31,7 @@
#define DDS_DOMAINID_PUB 0
#define DDS_DOMAINID_SUB 1
#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}127.0.0.10"
-#define DDS_CONFIG_NO_PORT_GAIN_LOG_PUB "<"DDS_PROJECT_NAME">0cyclonedds_liveliness_pub.logfinest"DDS_PROJECT_NAME">"
-#define DDS_CONFIG_NO_PORT_GAIN_LOG_SUB "<"DDS_PROJECT_NAME">0cyclonedds_liveliness_sub.logfinest"DDS_PROJECT_NAME">"
+#define DDS_CONFIG_NO_PORT_GAIN_LOG "<"DDS_PROJECT_NAME">0cyclonedds_liveliness.logfinest"DDS_PROJECT_NAME">"
uint32_t g_topic_nr = 0;
static dds_entity_t g_pub_domain = 0;
@@ -130,7 +129,7 @@ CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
};
#undef A
#undef MP
-CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 10)
+CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
@@ -186,7 +185,8 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
start_seqno, end_seqno);
- CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 1 : 0))
+ /* end-start should be mult - 1, but allow 1 pmd sample to be lost */
+ CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 2 : 0))
if (kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT)
CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
@@ -198,16 +198,12 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
}
/* FIXME: add DDS_LIVELINESS_MANUAL_BY_TOPIC */
-#define A DDS_LIVELINESS_AUTOMATIC
-#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration */
CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
CU_DataPoints(size_t, 1, 0, 2, 0, 1, 0, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
CU_DataPoints(size_t, 1, 1, 2, 2, 1, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
};
-#undef A
-#undef MP
CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
{
dds_entity_t pub_topic;
@@ -467,4 +463,152 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
-}
\ No newline at end of file
+}
+
+#define MAX_WRITERS 100
+CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ struct dds_liveliness_changed_status lstatus;
+ size_t wr_cnt = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ dds_attach_t triggered;
+ uint32_t n, status;
+ Space_Type1 sample = { 0, 0, 0 };
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_wr_stress", 1, 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);
+
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+
+ /* create 1st writer and wait for it to become alive */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
+ CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* create writers */
+ for (n = 1; n < MAX_WRITERS; n++)
+ {
+ dds_qset_liveliness(wqos, n % 1 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500 - n));
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_write (writers[n], &sample);
+ if (n % 3 == 2)
+ dds_delete(writers[n]);
+ }
+ dds_delete_qos(wqos);
+
+ /* wait for all writers to become alive */
+ while (wr_cnt < MAX_WRITERS)
+ {
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
+ wr_cnt += (uint32_t)lstatus.alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ }
+ CU_ASSERT_EQUAL_FATAL (wr_cnt, MAX_WRITERS);
+
+ /* cleanup remaining writers */
+ for (n = 0; n < wr_cnt; n++)
+ {
+ if (n % 3 != 2)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ }
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+}
+#undef MAX_WRITERS
+
+CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ dds_entity_t waitset;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ uint32_t status = 0;
+ struct dds_liveliness_changed_status lstatus;
+ struct dds_subscription_matched_status sstatus;
+ char name[100];
+ dds_duration_t ldur = DDS_MSECS (500);
+ Space_Type1 sample = { 1, 0, 0 };
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, 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);
+
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
+
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+
+ /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
+ dds_sleepfor(ldur + DDS_MSECS(100));
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+
+ /* write sample and re-check status counts */
+ dds_write (writer, &sample);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+}
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index 8967abb..f9adc0b 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -1509,10 +1509,8 @@ static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struc
if (rd->status_cb)
{
status_cb_data_t data;
-
data.add = false;
data.handle = pwr->e.iid;
-
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
@@ -3680,7 +3678,8 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant
if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh)) != NULL)
{
dds_duration_t trem = minl->tdur - pwr->lease->tdur;
- nn_etime_t texp = add_duration_to_etime (now_et(), trem >= 0 ? trem : 0);
+ assert (trem >= 0);
+ nn_etime_t texp = add_duration_to_etime (now_et(), trem);
struct lease *lnew = lease_new (texp, minl->tdur, minl->entity);
proxy_participant_replace_minl (proxypp, manbypp, lnew);
lease_register (lnew);
@@ -3986,22 +3985,23 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
if (refc == 0)
{
assert (proxypp->endpoints == NULL);
+ if (proxypp->owns_lease)
+ {
+ struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto);
+ ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
+ assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL);
+ assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
+ assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
+ assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid));
+ lease_free (minl_auto);
+ lease_free (proxypp->lease);
+ }
ddsrt_mutex_unlock (&proxypp->e.lock);
ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid));
unref_addrset (proxypp->as_default);
unref_addrset (proxypp->as_meta);
nn_plist_fini (proxypp->plist);
ddsrt_free (proxypp->plist);
- if (proxypp->owns_lease)
- {
- ddsrt_mutex_lock (&proxypp->e.lock);
- ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
- assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto) == NULL);
- assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
- ddsrt_mutex_unlock (&proxypp->e.lock);
- lease_free (ddsrt_atomic_ldvoidp (&proxypp->minl_auto));
- lease_free (proxypp->lease);
- }
entity_common_fini (&proxypp->e);
remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
ddsrt_free (proxypp);
@@ -4461,17 +4461,33 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
int proxy_writer_set_alive_locked (struct q_globals *gv, struct proxy_writer *pwr, bool alive)
{
ddsrt_avl_iter_t it;
- GVLOGDISC ("proxy_writer_set_alive_locked ("PGUIDFMT") ", PGUID (pwr->e.guid));
assert (pwr->alive != alive);
pwr->alive = alive;
- GVLOGDISC ("- alive=%d\n", pwr->alive);
- if (!pwr->alive)
+ GVLOGDISC (" alive=%d", pwr->alive);
+ if (pwr->alive)
+ {
+ for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
+ {
+ struct reader *rd;
+ if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
+ {
+ status_cb_data_t data;
+ data.add = true;
+ data.handle = pwr->e.iid;
+ data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
+ }
+ }
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxy_participant_add_pwr_lease (pwr->c.proxypp, pwr);
+ }
+ else
{
for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
reader_drop_connection (&m->rd_guid, pwr, false);
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
}
- if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- pwr->alive ? proxy_participant_add_pwr_lease (pwr->c.proxypp, pwr) : proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
return 0;
}
@@ -4483,7 +4499,7 @@ int proxy_writer_set_alive_guid (struct q_globals *gv, const struct ddsi_guid *g
if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL)
{
ddsrt_mutex_unlock (&gv->lock);
- GVLOGDISC ("proxy_writer_set_alive_guid ("PGUIDFMT") - unknown\n", PGUID (*guid));
+ GVLOGDISC (" "PGUIDFMT"?\n", PGUID (*guid));
return DDS_RETCODE_BAD_PARAMETER;
}
ddsrt_mutex_unlock (&gv->lock);
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index f86d3f7..f107855 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -272,7 +272,9 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
delete_proxy_participant_by_guid (gv, &g, now(), 1);
break;
case EK_PROXY_WRITER:
+ GVLOGDISC ("proxy_writer_set_alive ("PGUIDFMT")", PGUID (g));
(void) proxy_writer_set_alive_guid (gv, &g, false);
+ GVLOGDISC ("\n");
break;
case EK_PARTICIPANT:
case EK_READER:
From 476507fd5da29857718e87ab7a7de0dadf95335c Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Wed, 13 Nov 2019 16:32:21 +0100
Subject: [PATCH 45/55] Liveliness QoS implementation for kind manual_by_topic
This commit adds the implementation for the liveliness kind manual-by-topic.
With these changes, the api function dds_assert_liveliness now accepts a
writer as entity. Asserting liveliness on a writer triggers sending a
heartbeat message with the liveliness flag set.
The code for handling reception of a heartbeat message checks for this flag and
if set the lease for the proxy writer is renewed (and the shortest manual-by-participant
lease on the proxy participant as well, because the message also indicates that the
remote participant is alive). Receiving data (handle_regular) also renews the
lease on the proxy writer in case it has the manual-by-topic liveliness kind.
Signed-off-by: Dennis Potman
Refactored locking for pwr->alive so that locking order is consistent (locking
pwr->c.proxypp->e.lock while holding pwr->e.lock is the expected order). And
processed other review comments: removed lock for ephash_lookup, added
additional comments, set pwr->lease to null if not initialised.
Because of intermittent timing issues with liveliness expiry test in Travis, I've
increase the time-out and retry limit for this test.
Signed-off-by: Dennis Potman
Check that proxy writer is still alive (could be not-alive due to deleting) in code path for proxy writer's lease expiry
Signed-off-by: Dennis Potman
Some additional refactoring in locking for pwr->alive for liveliness qos, moved lease free to gc_delete_pwr, refactored the set pwr alive/not alive functions and some minor changes in liveliness tests
Signed-off-by: Dennis Potman
Fixed building liveliness tests on Windows and some cleaning up in liveliness test code
Signed-off-by: Dennis Potman
---
src/core/ddsc/src/dds_entity.c | 14 +-
src/core/ddsc/tests/liveliness.c | 222 +++++++++++++++----
src/core/ddsi/include/dds/ddsi/q_entity.h | 11 +-
src/core/ddsi/include/dds/ddsi/q_transmit.h | 3 +-
src/core/ddsi/src/q_ddsi_discovery.c | 6 +-
src/core/ddsi/src/q_entity.c | 234 ++++++++++++--------
src/core/ddsi/src/q_lease.c | 29 ++-
src/core/ddsi/src/q_receive.c | 23 +-
src/core/ddsi/src/q_transmit.c | 37 +++-
9 files changed, 409 insertions(+), 170 deletions(-)
diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c
index 724948a..4e6a225 100644
--- a/src/core/ddsc/src/dds_entity.c
+++ b/src/core/ddsc/src/dds_entity.c
@@ -24,6 +24,7 @@
#include "dds/version.h"
#include "dds/ddsi/ddsi_pmd.h"
#include "dds/ddsi/q_xqos.h"
+#include "dds/ddsi/q_transmit.h"
extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink);
extern inline bool dds_entity_is_enabled (const dds_entity *e);
@@ -1387,9 +1388,9 @@ dds_return_t dds_generic_unimplemented_operation (dds_entity_t handle, dds_entit
dds_return_t dds_assert_liveliness (dds_entity_t entity)
{
dds_return_t rc;
- dds_entity *e;
+ dds_entity *e, *ewr;
- if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
+ if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
return rc;
switch (dds_entity_kind (e))
{
@@ -1398,8 +1399,11 @@ dds_return_t dds_assert_liveliness (dds_entity_t entity)
break;
}
case DDS_KIND_WRITER: {
- /* FIXME: implement liveliness manual-by-topic */
- rc = DDS_RETCODE_UNSUPPORTED;
+ if ((rc = dds_entity_lock (entity, DDS_KIND_WRITER, &ewr)) != DDS_RETCODE_OK)
+ return rc;
+ if ((rc = write_hb_liveliness (&e->m_domain->gv, &e->m_guid, ((struct dds_writer *)ewr)->m_xp)) != DDS_RETCODE_OK)
+ return rc;
+ dds_entity_unlock (e);
break;
}
default: {
@@ -1407,6 +1411,6 @@ dds_return_t dds_assert_liveliness (dds_entity_t entity)
break;
}
}
- dds_entity_unlock (e);
+ dds_entity_unpin (e);
return rc;
}
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index a706568..7063410 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -30,8 +30,8 @@
#define DDS_DOMAINID_PUB 0
#define DDS_DOMAINID_SUB 1
-#define DDS_CONFIG_NO_PORT_GAIN "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}127.0.0.10"
-#define DDS_CONFIG_NO_PORT_GAIN_LOG "<"DDS_PROJECT_NAME">0cyclonedds_liveliness.logfinest"DDS_PROJECT_NAME">"
+#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;
@@ -44,7 +44,7 @@ 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 semi random g_topic name. */
+ /* 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);
@@ -53,10 +53,15 @@ static char *create_topic_name(const char *prefix, uint32_t nr, char *name, size
static void liveliness_init(void)
{
- char *conf = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, UINT32_MAX);
- g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf);
- g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf);
- dds_free(conf);
+ /* Domains for pub and sub use a different domain id, but the portgain setting
+ * in configuration is 0, so that both domains will map to the same port number.
+ * This allows to create two domains in a single test process. */
+ char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
+ char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
+ g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
+ g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
+ dds_free(conf_pub);
+ dds_free(conf_sub);
g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
CU_ASSERT_FATAL(g_pub_participant > 0);
@@ -79,6 +84,11 @@ static void liveliness_fini(void)
dds_delete(g_pub_domain);
}
+/**
+ * Gets the current PMD sequence number for the participant. This
+ * can be used to count the number of PMD messages that is sent by
+ * the participant.
+ */
static seqno_t get_pmd_seqno(dds_entity_t participant)
{
seqno_t seqno;
@@ -96,6 +106,9 @@ static seqno_t get_pmd_seqno(dds_entity_t participant)
return seqno;
}
+/**
+ * Gets the current PMD interval for the participant
+ */
static dds_duration_t get_pmd_interval(dds_entity_t participant)
{
dds_duration_t intv;
@@ -110,6 +123,9 @@ static dds_duration_t get_pmd_interval(dds_entity_t participant)
return intv;
}
+/**
+ * Gets the current lease duration for the participant
+ */
static dds_duration_t get_ldur_config(dds_entity_t participant)
{
struct dds_entity *pp_entity;
@@ -120,15 +136,22 @@ static dds_duration_t get_ldur_config(dds_entity_t participant)
return ldur;
}
+
+/**
+ * Test that the correct number of PMD messages is sent for
+ * the various liveliness kinds.
+ */
#define A DDS_LIVELINESS_AUTOMATIC
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
+#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
- CU_DataPoints(dds_liveliness_kind_t, A, A, MP), /* liveliness kind */
- CU_DataPoints(uint32_t, 200, 200, 200), /* lease duration */
- CU_DataPoints(double, 5, 10, 5), /* delay (n times lease duration) */
+ CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
+ CU_DataPoints(uint32_t, 200, 200, 200, 200), /* lease duration */
+ CU_DataPoints(double, 5, 10, 5, 5), /* delay (n times lease duration) */
};
-#undef A
+#undef MT
#undef MP
+#undef A
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
dds_entity_t pub_topic;
@@ -150,7 +173,7 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
kind == 0 ? "A" : "MP", ldur, mult);
/* topics */
- create_topic_name("ddsc_liveliness_test", g_topic_nr++, name, sizeof name);
+ create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
@@ -187,7 +210,7 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
/* end-start should be mult - 1, but allow 1 pmd sample to be lost */
CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 2 : 0))
- if (kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT)
+ if (kind != DDS_LIVELINESS_AUTOMATIC)
CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
/* cleanup */
@@ -197,39 +220,42 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
-/* FIXME: add DDS_LIVELINESS_MANUAL_BY_TOPIC */
+/**
+ * Test that the expected number of proxy writers expires (set to not-alive)
+ * after a certain delay for various combinations of writers with different
+ * liveliness kinds.
+ */
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
- CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration */
- CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
- CU_DataPoints(size_t, 1, 0, 2, 0, 1, 0, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
- CU_DataPoints(size_t, 1, 1, 2, 2, 1, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
+ CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
+ CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
};
-CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
+CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t *writers;
- dds_qos_t *rqos, *wqos_auto, *wqos_man_pp;
+ dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
dds_entity_t waitset;
dds_attach_t triggered;
struct dds_liveliness_changed_status lstatus;
- uint32_t status;
- size_t n, run = 1;
+ uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
char name[100];
- size_t wr_cnt = wr_cnt_auto + wr_cnt_man_pp;
dds_time_t tstart, t;
bool test_finished = false;
do
{
tstart = dds_time();
- printf("%d.%06d running test: lease duration %d, delay %f, auto/manual-by-participant %zu/%zu\n",
+ printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
(int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
- ldur, mult, wr_cnt_auto, wr_cnt_man_pp);
+ ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
/* topics */
- create_topic_name("ddsc_liveliness_test", g_topic_nr++, name, sizeof name);
+ create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, 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);
@@ -245,6 +271,8 @@ CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp)
dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
@@ -252,17 +280,20 @@ CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp)
writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
for (n = 0; n < wr_cnt; n++)
{
- CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, n < wr_cnt_auto ? wqos_auto : wqos_man_pp, NULL)) > 0);
+ dds_qos_t *wqos;
+ wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
}
dds_delete_qos(wqos_auto);
dds_delete_qos(wqos_man_pp);
+ dds_delete_qos(wqos_man_tp);
t = dds_time();
if (t - tstart > DDS_MSECS(0.5 * ldur))
{
- ldur *= 10;
+ ldur *= 10 / (run + 1);
printf("%d.%06d failed to create writers in time\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
}
@@ -274,7 +305,7 @@ CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp)
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
- size_t stopped = 0;
+ uint32_t stopped = 0;
do
{
dds_duration_t w = tstop - dds_time();
@@ -283,13 +314,13 @@ CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp)
stopped += (uint32_t)lstatus.not_alive_count_change;
} while (dds_time() < tstop);
t = dds_time();
- printf("%d.%06d writers stopped: %zu\n",
+ printf("%d.%06d writers stopped: %u\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
- size_t exp_stopped = mult < 1 ? 0 : wr_cnt_man_pp;
+ size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
if (stopped != exp_stopped)
{
- ldur *= 10;
+ ldur *= 10 / (run + 1);
printf("%d.%06d incorrect number of stopped writers\n",
(int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
}
@@ -315,7 +346,7 @@ CU_Theory((uint32_t ldur, double mult, size_t wr_cnt_auto, size_t wr_cnt_man_pp)
if (!test_finished)
{
- if (run++ > 2)
+ if (++run > 3)
{
printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
CU_FAIL_FATAL("Run limit reached");
@@ -354,6 +385,10 @@ static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
}
+/**
+ * Test that the correct PMD interval is set for the participant
+ * based on the lease duration of the writers.
+ */
#define MAX_WRITERS 10
CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
{
@@ -361,7 +396,7 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli
dds_entity_t sub_topic;
dds_entity_t reader;
dds_entity_t writers[MAX_WRITERS];
- size_t wr_cnt = 0;
+ uint32_t wr_cnt = 0;
char name[100];
dds_qos_t *rqos;
uint32_t n;
@@ -397,6 +432,9 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli
add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+
/* cleanup */
for (n = 0; n < wr_cnt; n++)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
@@ -406,6 +444,9 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli
}
#undef MAX_WRITERS
+/**
+ * Check that the correct lease duration is set in the matched
+ * publications in the readers. */
CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
{
dds_entity_t pub_topic;
@@ -465,6 +506,12 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
+/**
+ * Create a relative large number of writers with liveliness kinds automatic and
+ * manual-by-participant and with decreasing lease duration, and check that all
+ * writers become alive. During the writer creation loop, every third writer
+ * is deleted immediately after creating.
+ */
#define MAX_WRITERS 100
CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini)
{
@@ -475,11 +522,11 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
dds_entity_t waitset;
dds_qos_t *wqos;
struct dds_liveliness_changed_status lstatus;
- size_t wr_cnt = 0;
+ uint32_t wr_cnt = 0;
char name[100];
dds_qos_t *rqos;
dds_attach_t triggered;
- uint32_t n, status;
+ uint32_t n;
Space_Type1 sample = { 0, 0, 0 };
/* topics */
@@ -501,12 +548,11 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* create writers */
for (n = 1; n < MAX_WRITERS; n++)
{
- dds_qset_liveliness(wqos, n % 1 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500 - n));
+ dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (n % 3 ? 500 + n : 500 - n));
CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
dds_write (writers[n], &sample);
if (n % 3 == 2)
@@ -537,6 +583,9 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
}
#undef MAX_WRITERS
+/**
+ * Check the counts in liveliness_changed_status result.
+ */
CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
{
dds_entity_t pub_topic;
@@ -547,7 +596,6 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
dds_qos_t *rqos;
dds_qos_t *wqos;
dds_attach_t triggered;
- uint32_t status = 0;
struct dds_liveliness_changed_status lstatus;
struct dds_subscription_matched_status sstatus;
char name[100];
@@ -576,7 +624,6 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
/* wait for writer to be alive */
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
/* check status counts before proxy writer is expired */
dds_get_liveliness_changed_status(reader, &lstatus);
@@ -587,7 +634,6 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
/* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
dds_sleepfor(ldur + DDS_MSECS(100));
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
@@ -597,7 +643,6 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
/* write sample and re-check status counts */
dds_write (writer, &sample);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
dds_get_liveliness_changed_status(reader, &lstatus);
CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
@@ -612,3 +657,96 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
+
+/**
+ * Test that dds_assert_liveliness works as expected for liveliness
+ * kinds manual-by-participant and manual-by-topic.
+ */
+#define MAX_WRITERS 100
+CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
+ CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
+};
+CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout=30)
+{
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ dds_qos_t *rqos;
+ struct dds_liveliness_changed_status lstatus;
+ char name[100];
+ dds_duration_t ldur = DDS_MSECS (300);
+ uint32_t wr_cnt = 0;
+ dds_time_t tstop;
+ uint32_t stopped;
+
+ assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
+ printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u\n", wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
+
+ /* topics */
+ create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
+
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+
+ /* writers */
+ for (size_t n = 0; n < wr_cnt_auto; n++)
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, ldur, &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_pp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur, &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_tp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, ldur, &writers[wr_cnt++], pub_topic, reader);
+
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+
+ /* delay for more than lease duration and assert liveliness on writers:
+ all writers (including man-by-pp) should be kept alive */
+ tstop = dds_time() + 4 * ldur / 3;
+ stopped = 0;
+ do
+ {
+ for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
+ dds_assert_liveliness (writers[n]);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ CU_ASSERT_EQUAL_FATAL(stopped, 0);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+
+ /* delay for more than lease duration and assert liveliness on participant:
+ writers with liveliness man-by-pp should be kept alive, man-by-topic writers
+ should stop */
+ tstop = dds_time() + 4 * ldur / 3;
+ stopped = 0;
+ do
+ {
+ dds_assert_liveliness (g_pub_participant);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ CU_ASSERT_EQUAL_FATAL(stopped, wr_cnt_man_tp);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive_count: %d\n", lstatus.alive_count);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp);
+
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (size_t n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+}
+#undef MAX_WRITERS
diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h
index b6b0877..12e62dd 100644
--- a/src/core/ddsi/include/dds/ddsi/q_entity.h
+++ b/src/core/ddsi/include/dds/ddsi/q_entity.h
@@ -323,6 +323,7 @@ struct proxy_participant
unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */
unsigned minimal_bes_mode: 1;
unsigned lease_expired: 1;
+ unsigned deleting: 1;
unsigned proxypp_have_spdp: 1;
unsigned proxypp_have_cm: 1;
unsigned owns_lease: 1;
@@ -369,7 +370,7 @@ struct proxy_writer {
unsigned deliver_synchronously: 1; /* iff 1, delivery happens straight from receive thread for non-historical data; else through delivery queue "dqueue" */
unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */
unsigned local_matching_inprogress: 1; /* iff 1, we are still busy matching local readers; this is so we don't deliver incoming data to some but not all readers initially */
- unsigned alive: 1; /* iff 1, the proxy writer is alive (lease for this proxy writer is not expired) */
+ unsigned alive: 1; /* iff 1, the proxy writer is alive (lease for this proxy writer is not expired); field may be modified only when holding both pwr->e.lock and pwr->c.proxypp->e.lock */
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif
@@ -645,14 +646,14 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
reader or writer. Actual deletion is scheduled in the future, when
no outstanding references may still exist (determined by checking
thread progress, &c.). */
-int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit, bool proxypp_locked);
+int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
-int proxy_writer_set_alive_locked (struct q_globals *gv, struct proxy_writer *pwr, bool alive);
-int proxy_writer_set_alive_guid (struct q_globals *gv, const struct ddsi_guid *guid, bool alive);
+int proxy_writer_set_alive (struct proxy_writer *pwr);
+int proxy_writer_set_notalive (struct proxy_writer *pwr);
int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
@@ -661,6 +662,8 @@ void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid,
rebuild them all (which only makes sense after previously having emptied them all). */
void rebuild_or_clear_writer_addrsets(struct q_globals *gv, int rebuild);
+void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch);
+
void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
struct ddsi_writer_info;
diff --git a/src/core/ddsi/include/dds/ddsi/q_transmit.h b/src/core/ddsi/include/dds/ddsi/q_transmit.h
index c7899e6..b88b999 100644
--- a/src/core/ddsi/include/dds/ddsi/q_transmit.h
+++ b/src/core/ddsi/include/dds/ddsi/q_transmit.h
@@ -42,7 +42,8 @@ int write_sample_nogc_notk (struct thread_state1 * const ts1, struct nn_xpack *x
/* When calling the following functions, wr->lock must be held */
dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, unsigned fragnum, struct proxy_reader *prd,struct nn_xmsg **msg, int isnew);
int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct nn_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew);
-void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync);
+void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync);
+dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp);
#if defined (__cplusplus)
}
diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c
index b53b35b..f9f13c2 100644
--- a/src/core/ddsi/src/q_ddsi_discovery.c
+++ b/src/core/ddsi/src/q_ddsi_discovery.c
@@ -1357,13 +1357,9 @@ static void handle_SEDP_dead (const struct receiver_state *rst, nn_plist_t *data
}
GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid));
if (is_writer_entityid (datap->endpoint_guid.entityid))
- {
- res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0, false);
- }
+ res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0);
else
- {
res = delete_proxy_reader (gv, &datap->endpoint_guid, timestamp, 0);
- }
GVLOGDISC (" %s\n", (res < 0) ? " unknown" : " delete");
}
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index f9adc0b..475d690 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -1488,7 +1488,7 @@ static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struc
}
}
-static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch)
+void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
@@ -3619,16 +3619,20 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
static void proxy_participant_replace_minl (struct proxy_participant *proxypp, bool manbypp, struct lease *lnew)
{
+ /* By loading/storing the pointer atomically, we ensure we always
+ read a valid (or once valid) lease. By delaying freeing the lease
+ through the garbage collector, we ensure whatever lease update
+ occurs in parallel completes before the memory is released. */
const nn_etime_t never = { T_NEVER };
struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
- struct lease *lease_old = (struct lease *) ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto);
- lease_renew (lease_old, never);
- gcreq->arg = (void *) lease_old;
+ struct lease *lease_old = ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto);
+ lease_renew (lease_old, never); /* ensures lease will not expire while it is replaced */
+ gcreq->arg = lease_old;
gcreq_enqueue (gcreq);
- ddsrt_atomic_stvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto, (void *) lnew);
+ ddsrt_atomic_stvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto, lnew);
}
-static void proxy_participant_add_pwr_lease (struct proxy_participant * proxypp, const struct proxy_writer * pwr)
+static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * proxypp, const struct proxy_writer * pwr)
{
struct lease *minl_prev;
struct lease *minl_new;
@@ -3637,7 +3641,6 @@ static void proxy_participant_add_pwr_lease (struct proxy_participant * proxypp,
assert (pwr->lease != NULL);
manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT);
- ddsrt_mutex_lock (&proxypp->e.lock);
lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto;
minl_prev = ddsrt_fibheap_min (&lease_fhdef_proxypp, lh);
ddsrt_fibheap_insert (&lease_fhdef_proxypp, lh, pwr->lease);
@@ -3647,10 +3650,11 @@ static void proxy_participant_add_pwr_lease (struct proxy_participant * proxypp,
{
nn_etime_t texp = add_duration_to_etime (now_et (), minl_new->tdur);
struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity);
- if (manbypp && minl_prev == NULL)
+ if (minl_prev == NULL)
{
+ assert (manbypp);
assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
- ddsrt_atomic_stvoidp (&proxypp->minl_man, (void *) lnew);
+ ddsrt_atomic_stvoidp (&proxypp->minl_man, lnew);
}
else
{
@@ -3658,7 +3662,6 @@ static void proxy_participant_add_pwr_lease (struct proxy_participant * proxypp,
}
lease_register (lnew);
}
- ddsrt_mutex_unlock (&proxypp->e.lock);
}
static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant * proxypp, struct proxy_writer * pwr)
@@ -3684,25 +3687,14 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant
proxy_participant_replace_minl (proxypp, manbypp, lnew);
lease_register (lnew);
}
- else if (manbypp)
- {
- proxy_participant_replace_minl (proxypp, manbypp, NULL);
- }
else
{
- /* minl should not be null for leaseheap_auto because proxypp's lease is in */
- assert (false);
+ assert (manbypp);
+ proxy_participant_replace_minl (proxypp, manbypp, NULL);
}
}
}
-static void proxy_participant_remove_pwr_lease (struct proxy_participant * proxypp, struct proxy_writer * pwr)
-{
- ddsrt_mutex_lock (&proxypp->e.lock);
- proxy_participant_remove_pwr_lease_locked (proxypp, pwr);
- ddsrt_mutex_unlock (&proxypp->e.lock);
-}
-
void new_proxy_participant
(
struct q_globals *gv,
@@ -3736,6 +3728,7 @@ void new_proxy_participant
entity_common_init (&proxypp->e, gv, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false);
proxypp->refc = 1;
proxypp->lease_expired = 0;
+ proxypp->deleting = 0;
proxypp->vendor = vendor;
proxypp->bes = bes;
proxypp->prismtech_bes = prismtech_bes;
@@ -3789,8 +3782,11 @@ void new_proxy_participant
and uses the shortest duration for proxypp and all its pwr's (with automatic liveliness) */
ddsrt_fibheap_insert (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
- /* Set the shortest lease for auto liveliness: clone proxypp's lease (as there are no pwr's
- at this point, this is the shortest lease) */
+ /* Set the shortest lease for auto liveliness: clone proxypp's lease and store the clone in
+ proxypp->minl_auto. As there are no pwr's at this point, the proxy pp's lease is the
+ shortest lease. When a pwr with a shorter is added, the lease in minl_auto is replaced
+ by the lease from the proxy writer in proxy_participant_add_pwr_lease_locked. This old shortest
+ lease is freed, so that's why we need a clone and not the proxypp's lease in the heap. */
ddsrt_atomic_stvoidp (&proxypp->minl_auto, (void *) lease_clone (proxypp->lease));
ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL);
}
@@ -3948,9 +3944,14 @@ int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t s
return 0;
}
-static void ref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
+static int ref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
{
ddsrt_mutex_lock (&proxypp->e.lock);
+ if (proxypp->deleting)
+ {
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+ return DDS_RETCODE_PRECONDITION_NOT_MET;
+ }
c->proxypp = proxypp;
proxypp->refc++;
@@ -3962,6 +3963,8 @@ static void ref_proxy_participant (struct proxy_participant *proxypp, struct pro
}
proxypp->endpoints = c;
ddsrt_mutex_unlock (&proxypp->e.lock);
+
+ return DDS_RETCODE_OK;
}
static void unref_proxy_participant (struct proxy_participant *proxypp, struct proxy_endpoint_common *c)
@@ -4070,8 +4073,9 @@ static void delete_or_detach_dependent_pp (struct proxy_participant *p, struct p
static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp, int isimplicit)
{
- struct proxy_endpoint_common * c;
- int ret;
+ ddsi_entityid_t *eps;
+ ddsi_guid_t ep_guid;
+ uint32_t ep_count = 0;
/* if any proxy participants depend on this participant, delete them */
ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting dependent proxy participants\n", PGUID (proxypp->e.guid));
@@ -4084,31 +4088,38 @@ static void delete_ppt (struct proxy_participant *proxypp, nn_wctime_t timestamp
ephash_enum_proxy_participant_fini (&est);
}
- /* delete_proxy_{reader,writer} merely schedules the actual delete
- operation, so we can hold the lock -- at least, for now. */
-
ddsrt_mutex_lock (&proxypp->e.lock);
+ proxypp->deleting = 1;
if (isimplicit)
proxypp->lease_expired = 1;
- ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid));
- c = proxypp->endpoints;
- while (c)
+ /* Get snapshot of endpoints list so that we can release proxypp->e.lock
+ Pwrs/prds may be deleted during the iteration over the entities,
+ but resolving the guid will fail for these entities and the our
+ call to delete_proxy_writer/reader returns. */
{
- struct entity_common *e = entity_common_from_proxy_endpoint_common (c);
- if (is_writer_entityid (e->guid.entityid))
+ eps = ddsrt_malloc (proxypp->refc * sizeof(ddsi_entityid_t));
+ struct proxy_endpoint_common *cep = proxypp->endpoints;
+ while (cep)
{
- ret = delete_proxy_writer (proxypp->e.gv, &e->guid, timestamp, isimplicit, true);
+ const struct entity_common *entc = entity_common_from_proxy_endpoint_common (cep);
+ eps[ep_count++] = entc->guid.entityid;
+ cep = cep->next_ep;
}
- else
- {
- ret = delete_proxy_reader (proxypp->e.gv, &e->guid, timestamp, isimplicit);
- }
- (void) ret;
- c = c->next_ep;
}
ddsrt_mutex_unlock (&proxypp->e.lock);
+ ELOGDISC (proxypp, "delete_ppt("PGUIDFMT") - deleting endpoints\n", PGUID (proxypp->e.guid));
+ ep_guid.prefix = proxypp->e.guid.prefix;
+ for (uint32_t n = 0; n < ep_count; n++)
+ {
+ ep_guid.entityid = eps[n];
+ if (is_writer_entityid (ep_guid.entityid))
+ delete_proxy_writer (proxypp->e.gv, &ep_guid, timestamp, isimplicit);
+ else
+ delete_proxy_reader (proxypp->e.gv, &ep_guid, timestamp, isimplicit);
+ }
+ ddsrt_free (eps);
gcreq_proxy_participant (proxypp);
}
@@ -4185,9 +4196,10 @@ uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_g
/* PROXY-ENDPOINT --------------------------------------------------- */
-static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
+static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct ddsi_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
{
const char *name;
+ int ret;
if (is_builtin_entityid (guid->entityid, proxypp->vendor))
assert ((plist->qos.present & (QP_TOPIC_NAME | QP_TYPE_NAME)) == 0);
@@ -4206,7 +4218,16 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
else
memset (&c->group_guid, 0, sizeof (c->group_guid));
- ref_proxy_participant (proxypp, c);
+ if ((ret = ref_proxy_participant (proxypp, c)) != DDS_RETCODE_OK)
+ {
+ nn_xqos_fini (c->xqos);
+ ddsrt_free (c->xqos);
+ unref_addrset (c->as);
+ entity_common_fini (e);
+ return ret;
+ }
+
+ return DDS_RETCODE_OK;
}
static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_endpoint_common *c)
@@ -4226,6 +4247,7 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
struct proxy_writer *pwr;
int isreliable;
nn_mtime_t tnow = now_mt ();
+ int ret;
assert (is_writer_entityid (guid->entityid));
assert (ephash_lookup_proxy_writer_guid (gv->guid_hash, guid) == NULL);
@@ -4237,7 +4259,11 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
}
pwr = ddsrt_malloc (sizeof (*pwr));
- proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, seq, proxypp, as, plist);
+ if ((ret = proxy_endpoint_common_init (&pwr->e, &pwr->c, EK_PROXY_WRITER, guid, timestamp, seq, proxypp, as, plist)) != DDS_RETCODE_OK)
+ {
+ ddsrt_free (pwr);
+ return ret;
+ }
ddsrt_avl_init (&pwr_readers_treedef, &pwr->readers);
pwr->n_reliable_readers = 0;
@@ -4275,7 +4301,19 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
nn_etime_t texpire = add_duration_to_etime (now_et (), pwr->c.xqos->liveliness.lease_duration);
pwr->lease = lease_new (texpire, pwr->c.xqos->liveliness.lease_duration, &pwr->e);
if (pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- proxy_participant_add_pwr_lease (proxypp, pwr);
+ {
+ ddsrt_mutex_lock (&proxypp->e.lock);
+ proxy_participant_add_pwr_lease_locked (proxypp, pwr);
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+ }
+ else
+ {
+ lease_register (pwr->lease);
+ }
+ }
+ else
+ {
+ pwr->lease = NULL;
}
if (isreliable)
@@ -4419,17 +4457,22 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
free_pwr_rd_match (m);
}
local_reader_ary_fini (&pwr->rdary);
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
+ lease_free (pwr->lease);
proxy_endpoint_common_fini (&pwr->e, &pwr->c);
nn_defrag_free (pwr->defrag);
nn_reorder_free (pwr->reorder);
ddsrt_free (pwr);
}
-int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit, bool proxypp_locked)
+/* First stage in deleting the proxy writer. In this function the pwr and its member pointers
+ will remain valid. The real cleaning-up is done async in gc_delete_proxy_writer. */
+int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
{
struct proxy_writer *pwr;
- (void)isimplicit;
+ DDSRT_UNUSED_ARG (isimplicit);
GVLOGDISC ("delete_proxy_writer ("PGUIDFMT") ", PGUID (*guid));
+
ddsrt_mutex_lock (&gv->lock);
if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL)
{
@@ -4446,66 +4489,60 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false);
ephash_remove_proxy_writer_guid (gv->guid_hash, pwr);
ddsrt_mutex_unlock (&gv->lock);
+ if (proxy_writer_set_notalive (pwr) != DDS_RETCODE_OK)
+ GVLOGDISC ("proxy_writer_set_notalive failed for "PGUIDFMT"\n", PGUID(*guid));
+ /* Set lease expiry for this pwr to never so that the pwr will not be set
+ to alive again while it is scheduled for being deleted. */
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
- {
- ddsrt_mutex_lock (&pwr->e.lock);
- if (pwr->alive && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- proxypp_locked ? proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr) : proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
- ddsrt_mutex_unlock (&pwr->e.lock);
- lease_free (pwr->lease);
- }
+ lease_renew (pwr->lease, (nn_etime_t){ T_NEVER });
gcreq_proxy_writer (pwr);
- return 0;
+ return DDS_RETCODE_OK;
}
-int proxy_writer_set_alive_locked (struct q_globals *gv, struct proxy_writer *pwr, bool alive)
+int proxy_writer_set_alive (struct proxy_writer *pwr)
{
+ /* Caller has pwr->e.lock, so we can safely read pwr->alive. For updating
+ * this field this function is also taking pwr->c.proxypp->e.lock */
ddsrt_avl_iter_t it;
- assert (pwr->alive != alive);
- pwr->alive = alive;
- GVLOGDISC (" alive=%d", pwr->alive);
if (pwr->alive)
+ return DDS_RETCODE_PRECONDITION_NOT_MET;
+ ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
+ pwr->alive = true;
+
+ for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
{
- for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
+ struct reader *rd;
+ if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
{
- struct reader *rd;
- if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
- {
- status_cb_data_t data;
- data.add = true;
- data.handle = pwr->e.iid;
- data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
- (rd->status_cb) (rd->status_cb_entity, &data);
- }
+ status_cb_data_t data;
+ data.add = true;
+ data.handle = pwr->e.iid;
+ data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
}
- if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- proxy_participant_add_pwr_lease (pwr->c.proxypp, pwr);
}
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxy_participant_add_pwr_lease_locked (pwr->c.proxypp, pwr);
+ ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
+ return DDS_RETCODE_OK;
+}
+
+int proxy_writer_set_notalive (struct proxy_writer *pwr)
+{
+ /* Caller should not have taken pwr->e.lock and pwr->c.proxypp->e.lock;
+ * this function takes both locks to update pwr->alive value */
+ int ret = DDS_RETCODE_OK;
+ ddsrt_mutex_lock (&pwr->e.lock);
+ if (!pwr->alive)
+ ret = DDS_RETCODE_PRECONDITION_NOT_MET;
else
{
- for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
- reader_drop_connection (&m->rd_guid, pwr, false);
+ ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
+ pwr->alive = false;
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- proxy_participant_remove_pwr_lease (pwr->c.proxypp, pwr);
+ proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr);
+ ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
}
- return 0;
-}
-
-int proxy_writer_set_alive_guid (struct q_globals *gv, const struct ddsi_guid *guid, bool alive)
-{
- struct proxy_writer *pwr;
- int ret;
- ddsrt_mutex_lock (&gv->lock);
- if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, guid)) == NULL)
- {
- ddsrt_mutex_unlock (&gv->lock);
- GVLOGDISC (" "PGUIDFMT"?\n", PGUID (*guid));
- return DDS_RETCODE_BAD_PARAMETER;
- }
- ddsrt_mutex_unlock (&gv->lock);
-
- ddsrt_mutex_lock (&pwr->e.lock);
- ret = proxy_writer_set_alive_locked (gv, pwr, alive);
ddsrt_mutex_unlock (&pwr->e.lock);
return ret;
}
@@ -4521,6 +4558,7 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
struct proxy_participant *proxypp;
struct proxy_reader *prd;
nn_mtime_t tnow = now_mt ();
+ int ret;
assert (!is_writer_entityid (guid->entityid));
assert (ephash_lookup_proxy_reader_guid (gv->guid_hash, guid) == NULL);
@@ -4532,7 +4570,11 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
}
prd = ddsrt_malloc (sizeof (*prd));
- proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, seq, proxypp, as, plist);
+ if ((ret = proxy_endpoint_common_init (&prd->e, &prd->c, EK_PROXY_READER, guid, timestamp, seq, proxypp, as, plist)) != DDS_RETCODE_OK)
+ {
+ ddsrt_free (prd);
+ return ret;
+ }
prd->deleting = 0;
#ifdef DDSI_INCLUDE_SSM
@@ -4549,7 +4591,7 @@ int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
ddsrt_mutex_unlock (&prd->e.lock);
match_proxy_reader_with_writers (prd, tnow);
- return 0;
+ return DDS_RETCODE_OK;
}
static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *prd)
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index f107855..0db530c 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -140,7 +140,6 @@ void lease_free (struct lease *l)
void lease_renew (struct lease *l, nn_etime_t tnowE)
{
- struct q_globals const * gv;
nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur);
/* do not touch tend if moving forward or if already expired */
@@ -151,7 +150,11 @@ void lease_renew (struct lease *l, nn_etime_t tnowE)
return;
} while (!ddsrt_atomic_cas64 (&l->tend, (uint64_t) tend, (uint64_t) tend_new.v));
- gv = l->entity->gv;
+ /* Only at this point we can assume that gv can be recovered from the entity in the
+ * lease (i.e. the entity still exists). In cases where dereferencing l->entity->gv
+ * is not safe (e.g. the deletion of entities), the early out in the loop above
+ * will be the case because tend is set to T_NEVER. */
+ struct q_globals const * gv = l->entity->gv;
if (gv->logconfig.c.mask & DDS_LC_TRACE)
{
int32_t tsec, tusec;
@@ -272,10 +275,27 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
delete_proxy_participant_by_guid (gv, &g, now(), 1);
break;
case EK_PROXY_WRITER:
- GVLOGDISC ("proxy_writer_set_alive ("PGUIDFMT")", PGUID (g));
- (void) proxy_writer_set_alive_guid (gv, &g, false);
+ {
+ struct proxy_writer *pwr;
+ ddsrt_avl_iter_t it;
+ if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, &g)) == NULL)
+ {
+ GVLOGDISC (" "PGUIDFMT"?\n", PGUID (g));
+ ddsrt_mutex_lock (&gv->leaseheap_lock);
+ continue;
+ }
+ GVLOGDISC ("proxy_writer_set_notalive ("PGUIDFMT")", PGUID (g));
+ if (proxy_writer_set_notalive (pwr) == DDS_RETCODE_PRECONDITION_NOT_MET)
+ {
+ GVLOGDISC (" pwr was not alive");
+ ddsrt_mutex_lock (&gv->leaseheap_lock);
+ continue;
+ }
GVLOGDISC ("\n");
+ for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
+ reader_drop_connection (&m->rd_guid, pwr, false);
break;
+ }
case EK_PARTICIPANT:
case EK_READER:
case EK_WRITER:
@@ -283,7 +303,6 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
assert (false);
break;
}
-
ddsrt_mutex_lock (&gv->leaseheap_lock);
}
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index 4bea8e8..b026022 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -548,7 +548,7 @@ static void force_heartbeat_to_peer (struct writer *wr, const struct whc_state *
}
/* Send a Heartbeat just to this peer */
- add_Heartbeat (m, wr, whcst, hbansreq, prd->e.guid.entityid, 0);
+ add_Heartbeat (m, wr, whcst, hbansreq, 0, prd->e.guid.entityid, 0);
ETRACE (wr, "force_heartbeat_to_peer: "PGUIDFMT" -> "PGUIDFMT" - queue for transmit\n",
PGUID (wr->e.guid), PGUID (prd->e.guid));
qxev_msg (wr->evq, m);
@@ -1131,12 +1131,18 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
RSTTRACE (PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst));
return 1;
}
-
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst));
-
ddsrt_mutex_lock (&pwr->e.lock);
-
+ if (msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS &&
+ pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC &&
+ pwr->c.xqos->liveliness.lease_duration != T_NEVER)
+ {
+ struct lease *lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man);
+ if (lease != NULL)
+ lease_renew (lease, tnow);
+ lease_renew (pwr->lease, tnow);
+ }
if (pwr->n_reliable_readers == 0)
{
RSTTRACE (PGUIDFMT" -> "PGUIDFMT" no-reliable-readers)", PGUID (src), PGUID (dst));
@@ -2087,7 +2093,8 @@ static void clean_defrag (struct proxy_writer *pwr)
nn_defrag_notegap (pwr->defrag, 1, seq);
}
-static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo, uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup, bool renew_manbypp_lease)
+static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct nn_rmsg *rmsg, const Data_DataFrag_common_t *msg, const struct nn_rsample_info *sampleinfo,
+ uint32_t fragnum, struct nn_rdata *rdata, struct nn_dqueue **deferred_wakeup, bool renew_manbypp_lease)
{
struct proxy_writer *pwr;
struct nn_rsample *rsample;
@@ -2114,13 +2121,11 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
/* Shouldn't lock the full writer, but will do so for now */
ddsrt_mutex_lock (&pwr->e.lock);
- /* FIXME: implement liveliness manual-by-topic */
- /* if (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ if (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && pwr->c.xqos->liveliness.lease_duration != T_NEVER)
lease_renew (pwr->lease, tnow);
- */
if (!pwr->alive)
- proxy_writer_set_alive_locked (pwr->e.gv, pwr, true);
+ proxy_writer_set_alive (pwr);
/* Don't accept data when reliable readers exist and we haven't yet seen
a heartbeat telling us what the "current" sequence number of the writer
diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c
index 7afd1fe..6d2a69a 100644
--- a/src/core/ddsi/src/q_transmit.c
+++ b/src/core/ddsi/src/q_transmit.c
@@ -194,7 +194,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
- add_Heartbeat (msg, wr, whcst, hbansreq, to_entityid (NN_ENTITYID_UNKNOWN), issync);
+ add_Heartbeat (msg, wr, whcst, hbansreq, 0, to_entityid (NN_ENTITYID_UNKNOWN), issync);
}
else
{
@@ -215,7 +215,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
nn_xmsg_setencoderid (msg, wr->partition_id);
#endif
- add_Heartbeat (msg, wr, whcst, hbansreq, prd_guid->entityid, issync);
+ add_Heartbeat (msg, wr, whcst, hbansreq, 0, prd_guid->entityid, issync);
}
writer_hbcontrol_note_hb (wr, tnow, hbansreq);
@@ -313,7 +313,7 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_
return msg;
}
-void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync)
+void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync)
{
struct q_globals const * const gv = wr->e.gv;
struct nn_xmsg_marker sm_marker;
@@ -324,6 +324,7 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta
assert (wr->reliable);
assert (hbansreq >= 0);
+ assert (hbliveliness >= 0);
if (gv->config.meas_hb_to_ack_latency)
{
@@ -337,6 +338,8 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta
if (!hbansreq)
hb->smhdr.flags |= HEARTBEAT_FLAG_FINAL;
+ if (hbliveliness)
+ hb->smhdr.flags |= HEARTBEAT_FLAG_LIVELINESS;
hb->readerId = nn_hton_entityid (dst);
hb->writerId = nn_hton_entityid (wr->e.guid.entityid);
@@ -666,6 +669,34 @@ static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragn
nn_xmsg_submsg_setnext (*pmsg, sm_marker);
}
+dds_return_t write_hb_liveliness (struct q_globals * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp)
+{
+ struct nn_xmsg *msg = NULL;
+ struct whc_state whcst;
+ struct thread_state1 * const ts1 = lookup_thread_state ();
+ thread_state_awake (ts1, gv);
+ struct writer *wr = ephash_lookup_writer_guid (gv->guid_hash, wr_guid);
+ if (wr == NULL)
+ {
+ GVTRACE ("write_hb_liveliness("PGUIDFMT") - writer not found\n", PGUID (*wr_guid));
+ return DDS_RETCODE_PRECONDITION_NOT_MET;
+ }
+ if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL)
+ return DDS_RETCODE_OUT_OF_RESOURCES;
+ ddsrt_mutex_lock (&wr->e.lock);
+ nn_xmsg_setdstN (msg, wr->as, wr->as_group);
+#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
+ nn_xmsg_setencoderid (msg, wr->partition_id);
+#endif
+ whc_get_state (wr->whc, &whcst);
+ add_Heartbeat (msg, wr, &whcst, 0, 1, to_entityid (NN_ENTITYID_UNKNOWN), 1);
+ ddsrt_mutex_unlock (&wr->e.lock);
+ nn_xpack_addmsg (xp, msg, 0);
+ nn_xpack_send (xp, true);
+ thread_state_asleep (ts1);
+ return DDS_RETCODE_OK;
+}
+
#if 0
static int must_skip_frag (const char *frags_to_skip, unsigned frag)
{
From 1699103b375d7d9c5cf0fae9cadb41be8183e940 Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Tue, 19 Nov 2019 16:39:33 +0100
Subject: [PATCH 46/55] Consistent checks for inserting and deleting writer
lease duration in participants fibheap
Signed-off-by: Dennis Potman
---
src/core/ddsi/src/q_entity.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index 475d690..b55606e 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -2961,9 +2961,10 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g
match_writer_with_local_readers (wr, tnow);
sedp_write_writer (wr);
- if (wr->lease_duration != NULL && wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC)
+ if (wr->lease_duration != NULL)
{
assert (wr->lease_duration->ldur != T_NEVER);
+ assert (wr->xqos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC);
assert (!is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE));
/* Store writer lease duration in participant's heap in case of automatic liveliness */
From fd103a8d6aa5cbff43b5a8b622369b6cd9b346a0 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 21 Nov 2019 10:55:07 +0100
Subject: [PATCH 47/55] Remove dead store triggering Clang static analyzer
Signed-off-by: Erik Boasson
---
src/core/ddsc/src/dds_handles.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/core/ddsc/src/dds_handles.c b/src/core/ddsc/src/dds_handles.c
index a2bbb0a..3a6f1b3 100644
--- a/src/core/ddsc/src/dds_handles.c
+++ b/src/core/ddsc/src/dds_handles.c
@@ -277,7 +277,6 @@ int32_t dds_handle_pin_for_delete (dds_handle_t hdl, bool explicit, struct dds_h
uint32_t cf, cf1;
/* Assume success; bail out if the object turns out to be in the process of
being deleted */
- rc = DDS_RETCODE_OK;
do {
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
From e781cda9e5883fd69ff85d3beca937db944d93a7 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 21 Nov 2019 10:56:40 +0100
Subject: [PATCH 48/55] Update liveliness tests to use ExternalDomainId
Signed-off-by: Erik Boasson
---
src/core/ddsc/tests/liveliness.c | 1058 +++++++++++++++---------------
1 file changed, 530 insertions(+), 528 deletions(-)
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index 7063410..3bee980 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -30,8 +30,8 @@
#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"
+#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;
@@ -44,44 +44,44 @@ 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;
+ /* 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
- * in configuration is 0, so that both domains will map to the same port number.
- * This allows to create two domains in a single test process. */
- char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
- char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
- g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
- g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
- dds_free(conf_pub);
- dds_free(conf_sub);
+ /* Domains for pub and sub use a different domain id, but the portgain setting
+ * in configuration is 0, so that both domains will map to the same port number.
+ * This allows to create two domains in a single test process. */
+ char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
+ char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
+ g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
+ g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
+ dds_free(conf_pub);
+ dds_free(conf_sub);
- g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
- CU_ASSERT_FATAL(g_pub_participant > 0);
- g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
- CU_ASSERT_FATAL(g_sub_participant > 0);
+ g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_participant > 0);
+ g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_participant > 0);
- g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
- CU_ASSERT_FATAL(g_pub_publisher > 0);
- g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
- CU_ASSERT_FATAL(g_sub_subscriber > 0);
+ g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_publisher > 0);
+ g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_subscriber > 0);
}
static void liveliness_fini(void)
{
- dds_delete(g_sub_subscriber);
- dds_delete(g_pub_publisher);
- dds_delete(g_sub_participant);
- dds_delete(g_pub_participant);
- dds_delete(g_sub_domain);
- dds_delete(g_pub_domain);
+ dds_delete(g_sub_subscriber);
+ dds_delete(g_pub_publisher);
+ dds_delete(g_sub_participant);
+ dds_delete(g_pub_participant);
+ dds_delete(g_sub_domain);
+ dds_delete(g_pub_domain);
}
/**
@@ -91,19 +91,20 @@ static void liveliness_fini(void)
*/
static seqno_t get_pmd_seqno(dds_entity_t participant)
{
- seqno_t seqno;
- struct dds_entity *pp_entity;
- struct participant *pp;
- struct writer *wr;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
- pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
- wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
- CU_ASSERT_FATAL(wr != NULL);
- seqno = wr->seq;
- thread_state_asleep(lookup_thread_state());
- dds_entity_unpin(pp_entity);
- return seqno;
+ seqno_t seqno;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ struct writer *wr;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
+ CU_ASSERT_FATAL(wr != NULL);
+ assert(wr != NULL); /* for Clang's static analyzer */
+ seqno = wr->seq;
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return seqno;
}
/**
@@ -111,16 +112,16 @@ static seqno_t get_pmd_seqno(dds_entity_t participant)
*/
static dds_duration_t get_pmd_interval(dds_entity_t participant)
{
- dds_duration_t intv;
- struct dds_entity *pp_entity;
- struct participant *pp;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
- pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
- intv = pp_get_pmd_interval(pp);
- thread_state_asleep(lookup_thread_state());
- dds_entity_unpin(pp_entity);
- return intv;
+ dds_duration_t intv;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ intv = pp_get_pmd_interval(pp);
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return intv;
}
/**
@@ -128,12 +129,12 @@ static dds_duration_t get_pmd_interval(dds_entity_t participant)
*/
static dds_duration_t get_ldur_config(dds_entity_t participant)
{
- struct dds_entity *pp_entity;
- dds_duration_t ldur;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
- dds_entity_unpin(pp_entity);
- return ldur;
+ struct dds_entity *pp_entity;
+ dds_duration_t ldur;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
+ dds_entity_unpin(pp_entity);
+ return ldur;
}
@@ -145,79 +146,79 @@ static dds_duration_t get_ldur_config(dds_entity_t participant)
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
- CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
- CU_DataPoints(uint32_t, 200, 200, 200, 200), /* lease duration */
- CU_DataPoints(double, 5, 10, 5, 5), /* delay (n times lease duration) */
+ CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
+ CU_DataPoints(uint32_t, 200, 200, 200, 200), /* lease duration */
+ CU_DataPoints(double, 5, 10, 5, 5), /* delay (n times lease duration) */
};
#undef MT
#undef MP
#undef A
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- seqno_t start_seqno, end_seqno;
- dds_qos_t *rqos;
- dds_qos_t *wqos;
- dds_entity_t waitset;
- dds_attach_t triggered;
- uint32_t status;
- char name[100];
- dds_time_t t;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ seqno_t start_seqno, end_seqno;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ char name[100];
+ dds_time_t t;
- t = dds_time();
- printf("%d.%06d running test: kind %s, lease duration %d, delay %f\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- kind == 0 ? "A" : "MP", ldur, mult);
+ t = dds_time();
+ printf("%d.%06d running test: kind %s, lease duration %d, delay %f\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ kind == 0 ? "A" : "MP", ldur, mult);
- /* topics */
- create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* waitset on reader */
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* waitset on reader */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* writer */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check no of PMD messages sent */
- start_seqno = get_pmd_seqno(g_pub_participant);
- dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
- end_seqno = get_pmd_seqno(g_pub_participant);
+ /* check no of PMD messages sent */
+ start_seqno = get_pmd_seqno(g_pub_participant);
+ dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
+ end_seqno = get_pmd_seqno(g_pub_participant);
- t = dds_time();
- printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- start_seqno, end_seqno);
+ t = dds_time();
+ printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ start_seqno, end_seqno);
- /* end-start should be mult - 1, but allow 1 pmd sample to be lost */
- CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 2 : 0))
- if (kind != DDS_LIVELINESS_AUTOMATIC)
- CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
+ /* end-start should be mult - 1, but allow 1 pmd sample to be lost */
+ CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 2 : 0))
+ if (kind != DDS_LIVELINESS_AUTOMATIC)
+ CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
@@ -226,163 +227,163 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
* liveliness kinds.
*/
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
- CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
- CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
- CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
- CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
- CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
+ CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
+ CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
+ CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
};
CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t *writers;
- dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
- dds_entity_t waitset;
- dds_attach_t triggered;
- struct dds_liveliness_changed_status lstatus;
- uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
- char name[100];
- dds_time_t tstart, t;
- bool test_finished = false;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t *writers;
+ dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ struct dds_liveliness_changed_status lstatus;
+ uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
+ char name[100];
+ dds_time_t tstart, t;
+ bool test_finished = false;
- do
- {
- tstart = dds_time();
- printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
- (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
- ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
+ do
+ {
+ tstart = dds_time();
+ printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
+ (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
+ ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
- /* topics */
- create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writers */
- CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
+ /* writers */
+ CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
- for (n = 0; n < wr_cnt; n++)
- {
- dds_qos_t *wqos;
- wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
- CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- }
- dds_delete_qos(wqos_auto);
- dds_delete_qos(wqos_man_pp);
- dds_delete_qos(wqos_man_tp);
+ writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
+ for (n = 0; n < wr_cnt; n++)
+ {
+ dds_qos_t *wqos;
+ wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ }
+ dds_delete_qos(wqos_auto);
+ dds_delete_qos(wqos_man_pp);
+ dds_delete_qos(wqos_man_tp);
- t = dds_time();
- if (t - tstart > DDS_MSECS(0.5 * ldur))
- {
- ldur *= 10 / (run + 1);
- printf("%d.%06d failed to create writers in time\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
- }
- else
- {
- /* check alive count before proxy writers are expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
+ t = dds_time();
+ if (t - tstart > DDS_MSECS(0.5 * ldur))
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d failed to create writers in time\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count before proxy writers are expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
- dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
- uint32_t stopped = 0;
- do
- {
- dds_duration_t w = tstop - dds_time();
- CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- } while (dds_time() < tstop);
- t = dds_time();
- printf("%d.%06d writers stopped: %u\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
+ dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
+ uint32_t stopped = 0;
+ do
+ {
+ dds_duration_t w = tstop - dds_time();
+ CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ } while (dds_time() < tstop);
+ t = dds_time();
+ printf("%d.%06d writers stopped: %u\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
- size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
- if (stopped != exp_stopped)
- {
- ldur *= 10 / (run + 1);
- printf("%d.%06d incorrect number of stopped writers\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
- }
- else
- {
- /* check alive count */
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
- test_finished = true;
- }
- }
+ size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
+ if (stopped != exp_stopped)
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d incorrect number of stopped writers\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count */
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
+ test_finished = true;
+ }
+ }
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- for (n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- dds_free(writers);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ dds_free(writers);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- if (!test_finished)
- {
- if (++run > 3)
- {
- printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
- CU_FAIL_FATAL("Run limit reached");
- test_finished = true;
- continue;
- }
- else
- {
- printf("%d.%06d restarting test with ldur %d\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
- }
- }
- } while (!test_finished);
+ if (!test_finished)
+ {
+ if (++run > 3)
+ {
+ printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
+ CU_FAIL_FATAL("Run limit reached");
+ test_finished = true;
+ continue;
+ }
+ else
+ {
+ printf("%d.%06d restarting test with ldur %d\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
+ }
+ }
+ } while (!test_finished);
}
static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader)
{
- dds_entity_t waitset;
- dds_qos_t *wqos;
- dds_attach_t triggered;
- uint32_t status;
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ uint32_t status;
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, kind, ldur);
- CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, ldur);
+ CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
}
/**
@@ -392,55 +393,55 @@ static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur
#define MAX_WRITERS 10
CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- uint32_t wr_cnt = 0;
- char name[100];
- dds_qos_t *rqos;
- uint32_t n;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ uint32_t wr_cnt = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ uint32_t n;
- /* topics */
- create_topic_name("ddsc_liveliness_ldur", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldur", 1, 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);
- /* reader and waitset */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check if pmd defaults to configured duration */
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
+ /* check if pmd defaults to configured duration */
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
- /* create writers and check pmd interval in publishing participant */
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ /* create writers and check pmd interval in publishing participant */
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- /* cleanup */
- for (n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
@@ -449,61 +450,62 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli
* publications in the readers. */
CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- char name[100];
- dds_qos_t *rqos, *wqos;
- dds_entity_t waitset;
- dds_attach_t triggered;
- uint32_t status;
- dds_duration_t ldur;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ char name[100];
+ dds_qos_t *rqos, *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ dds_duration_t ldur;
- /* topics */
- create_topic_name("ddsc_liveliness_ldurpwr", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldurpwr", 1, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writer */
- ldur = 1000;
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ /* writer */
+ ldur = 1000;
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- /* wait for writer to be alive */
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check pwr lease duration in matched publication */
- dds_instance_handle_t wrs[1];
- CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
- dds_builtintopic_endpoint_t *ep;
- ep = dds_get_matched_publication_data(reader, wrs[0]);
- CU_ASSERT_FATAL(ep != NULL);
- CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
- dds_delete_qos(ep->qos);
- dds_free(ep->topic_name);
- dds_free(ep->type_name);
- dds_free(ep);
+ /* check pwr lease duration in matched publication */
+ dds_instance_handle_t wrs[1];
+ CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
+ dds_builtintopic_endpoint_t *ep;
+ ep = dds_get_matched_publication_data(reader, wrs[0]);
+ CU_ASSERT_FATAL(ep != NULL);
+ assert(ep != NULL); /* for Clang's static analyzer */
+ CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
+ dds_delete_qos(ep->qos);
+ dds_free(ep->topic_name);
+ dds_free(ep->type_name);
+ dds_free(ep);
- /* cleanup */
- dds_delete_qos(wqos);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ dds_delete_qos(wqos);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
@@ -515,71 +517,71 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li
#define MAX_WRITERS 100
CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- dds_entity_t waitset;
- dds_qos_t *wqos;
- struct dds_liveliness_changed_status lstatus;
- uint32_t wr_cnt = 0;
- char name[100];
- dds_qos_t *rqos;
- dds_attach_t triggered;
- uint32_t n;
- Space_Type1 sample = { 0, 0, 0 };
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ struct dds_liveliness_changed_status lstatus;
+ uint32_t wr_cnt = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ dds_attach_t triggered;
+ uint32_t n;
+ Space_Type1 sample = { 0, 0, 0 };
- /* topics */
- create_topic_name("ddsc_liveliness_wr_stress", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_wr_stress", 1, 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);
- /* reader and waitset */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* create 1st writer and wait for it to become alive */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
- CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ /* create 1st writer and wait for it to become alive */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
+ CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- /* create writers */
- for (n = 1; n < MAX_WRITERS; n++)
- {
- dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (n % 3 ? 500 + n : 500 - n));
- CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_write (writers[n], &sample);
- if (n % 3 == 2)
- dds_delete(writers[n]);
- }
- dds_delete_qos(wqos);
+ /* create writers */
+ for (n = 1; n < MAX_WRITERS; n++)
+ {
+ dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (n % 3 ? 500 + n : 500 - n));
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_write (writers[n], &sample);
+ if (n % 3 == 2)
+ dds_delete(writers[n]);
+ }
+ dds_delete_qos(wqos);
- /* wait for all writers to become alive */
- while (wr_cnt < MAX_WRITERS)
- {
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
- wr_cnt += (uint32_t)lstatus.alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- }
- CU_ASSERT_EQUAL_FATAL (wr_cnt, MAX_WRITERS);
+ /* wait for all writers to become alive */
+ while (wr_cnt < MAX_WRITERS)
+ {
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
+ wr_cnt += (uint32_t)lstatus.alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ }
+ CU_ASSERT_EQUAL_FATAL (wr_cnt, MAX_WRITERS);
- /* cleanup remaining writers */
- for (n = 0; n < wr_cnt; n++)
- {
- if (n % 3 != 2)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- }
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* cleanup remaining writers */
+ for (n = 0; n < wr_cnt; n++)
+ {
+ if (n % 3 != 2)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ }
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
@@ -588,74 +590,74 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
*/
CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- dds_entity_t waitset;
- dds_qos_t *rqos;
- dds_qos_t *wqos;
- dds_attach_t triggered;
- struct dds_liveliness_changed_status lstatus;
- struct dds_subscription_matched_status sstatus;
- char name[100];
- dds_duration_t ldur = DDS_MSECS (500);
- Space_Type1 sample = { 1, 0, 0 };
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ dds_entity_t waitset;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ struct dds_liveliness_changed_status lstatus;
+ struct dds_subscription_matched_status sstatus;
+ char name[100];
+ dds_duration_t ldur = DDS_MSECS (500);
+ Space_Type1 sample = { 1, 0, 0 };
- /* topics */
- create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* writer */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- /* check status counts before proxy writer is expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
- dds_sleepfor(ldur + DDS_MSECS(100));
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
+ dds_sleepfor(ldur + DDS_MSECS(100));
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* write sample and re-check status counts */
- dds_write (writer, &sample);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* write sample and re-check status counts */
+ dds_write (writer, &sample);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
/**
@@ -664,89 +666,89 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
*/
#define MAX_WRITERS 100
CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
- CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
- CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
- CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
+ CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
};
CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout=30)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- dds_qos_t *rqos;
- struct dds_liveliness_changed_status lstatus;
- char name[100];
- dds_duration_t ldur = DDS_MSECS (300);
- uint32_t wr_cnt = 0;
- dds_time_t tstop;
- uint32_t stopped;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ dds_qos_t *rqos;
+ struct dds_liveliness_changed_status lstatus;
+ char name[100];
+ dds_duration_t ldur = DDS_MSECS (300);
+ uint32_t wr_cnt = 0;
+ dds_time_t tstop;
+ uint32_t stopped;
- assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
- printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u\n", wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
+ assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
+ printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u\n", wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
- /* topics */
- create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writers */
- for (size_t n = 0; n < wr_cnt_auto; n++)
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, ldur, &writers[wr_cnt++], pub_topic, reader);
- for (size_t n = 0; n < wr_cnt_man_pp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur, &writers[wr_cnt++], pub_topic, reader);
- for (size_t n = 0; n < wr_cnt_man_tp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, ldur, &writers[wr_cnt++], pub_topic, reader);
+ /* writers */
+ for (size_t n = 0; n < wr_cnt_auto; n++)
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, ldur, &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_pp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur, &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_tp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, ldur, &writers[wr_cnt++], pub_topic, reader);
- /* check status counts before proxy writer is expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
- /* delay for more than lease duration and assert liveliness on writers:
- all writers (including man-by-pp) should be kept alive */
- tstop = dds_time() + 4 * ldur / 3;
- stopped = 0;
- do
- {
- for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
- dds_assert_liveliness (writers[n]);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- CU_ASSERT_EQUAL_FATAL(stopped, 0);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+ /* delay for more than lease duration and assert liveliness on writers:
+ all writers (including man-by-pp) should be kept alive */
+ tstop = dds_time() + 4 * ldur / 3;
+ stopped = 0;
+ do
+ {
+ for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
+ dds_assert_liveliness (writers[n]);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ CU_ASSERT_EQUAL_FATAL(stopped, 0);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
- /* delay for more than lease duration and assert liveliness on participant:
- writers with liveliness man-by-pp should be kept alive, man-by-topic writers
- should stop */
- tstop = dds_time() + 4 * ldur / 3;
- stopped = 0;
- do
- {
- dds_assert_liveliness (g_pub_participant);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- CU_ASSERT_EQUAL_FATAL(stopped, wr_cnt_man_tp);
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("writers alive_count: %d\n", lstatus.alive_count);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp);
+ /* delay for more than lease duration and assert liveliness on participant:
+ writers with liveliness man-by-pp should be kept alive, man-by-topic writers
+ should stop */
+ tstop = dds_time() + 4 * ldur / 3;
+ stopped = 0;
+ do
+ {
+ dds_assert_liveliness (g_pub_participant);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ CU_ASSERT_EQUAL_FATAL(stopped, wr_cnt_man_tp);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive_count: %d\n", lstatus.alive_count);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp);
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- for (size_t n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (size_t n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
From 801def8bd563dc53b9d84516ff1eaa52c7f94682 Mon Sep 17 00:00:00 2001
From: Erik Boasson
Date: Thu, 21 Nov 2019 10:57:21 +0100
Subject: [PATCH 49/55] Invoke liveliness changed without holding pwr lock
Signed-off-by: Erik Boasson
---
src/core/ddsc/src/dds_reader.c | 48 ++++-
src/core/ddsi/include/dds/ddsi/q_entity.h | 25 ++-
src/core/ddsi/src/ddsi_pmd.c | 5 +-
src/core/ddsi/src/q_entity.c | 231 +++++++++++++++-------
src/core/ddsi/src/q_lease.c | 21 +-
src/core/ddsi/src/q_receive.c | 16 +-
6 files changed, 238 insertions(+), 108 deletions(-)
diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c
index d754f10..be1c045 100644
--- a/src/core/ddsc/src/dds_reader.c
+++ b/src/core/ddsc/src/dds_reader.c
@@ -233,16 +233,46 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
}
case DDS_LIVELINESS_CHANGED_STATUS_ID: {
struct dds_liveliness_changed_status * const st = vst = &rd->m_liveliness_changed_status;
- if (data->add) {
- st->alive_count++;
- st->alive_count_change++;
- if (st->not_alive_count > 0) {
+ DDSRT_STATIC_ASSERT ((uint32_t) LIVELINESS_CHANGED_ADD_ALIVE == 0 &&
+ LIVELINESS_CHANGED_ADD_ALIVE < LIVELINESS_CHANGED_ADD_NOT_ALIVE &&
+ LIVELINESS_CHANGED_ADD_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_NOT_ALIVE &&
+ LIVELINESS_CHANGED_REMOVE_NOT_ALIVE < LIVELINESS_CHANGED_REMOVE_ALIVE &&
+ LIVELINESS_CHANGED_REMOVE_ALIVE < LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE &&
+ LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE < LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE &&
+ LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE < LIVELINESS_CHANGED_TWITCH &&
+ (uint32_t) LIVELINESS_CHANGED_TWITCH < UINT32_MAX);
+ assert (data->extra <= (uint32_t) LIVELINESS_CHANGED_TWITCH);
+ switch ((enum liveliness_changed_data_extra) data->extra)
+ {
+ case LIVELINESS_CHANGED_ADD_ALIVE:
+ st->alive_count++;
+ st->alive_count_change++;
+ break;
+ case LIVELINESS_CHANGED_ADD_NOT_ALIVE:
+ st->not_alive_count++;
+ st->not_alive_count_change++;
+ break;
+ case LIVELINESS_CHANGED_REMOVE_NOT_ALIVE:
+ break;
+ case LIVELINESS_CHANGED_REMOVE_ALIVE:
+ st->alive_count--;
+ st->not_alive_count++;
+ st->not_alive_count_change++;
+ break;
+ case LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE:
+ st->alive_count--;
+ st->not_alive_count++;
+ st->not_alive_count_change++;
+ break;
+ case LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE:
st->not_alive_count--;
- }
- } else {
- st->alive_count--;
- st->not_alive_count++;
- st->not_alive_count_change++;
+ st->alive_count++;
+ st->alive_count_change++;
+ break;
+ case LIVELINESS_CHANGED_TWITCH:
+ st->alive_count_change++;
+ st->not_alive_count_change++;
+ break;
}
st->last_publication_handle = data->handle;
invoke = (lst->on_liveliness_changed != 0);
diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h
index 12e62dd..c899296 100644
--- a/src/core/ddsi/include/dds/ddsi/q_entity.h
+++ b/src/core/ddsi/include/dds/ddsi/q_entity.h
@@ -48,14 +48,25 @@ struct proxy_group;
struct proxy_endpoint_common;
typedef void (*ddsi2direct_directread_cb_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, void *arg);
+/* Liveliness changed is more complicated than just add/remove. Encode the event
+ in status_cb_data_t::extra and ignore status_cb_data_t::add */
+enum liveliness_changed_data_extra {
+ LIVELINESS_CHANGED_ADD_ALIVE,
+ LIVELINESS_CHANGED_ADD_NOT_ALIVE,
+ LIVELINESS_CHANGED_REMOVE_NOT_ALIVE,
+ LIVELINESS_CHANGED_REMOVE_ALIVE,
+ LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE,
+ LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE,
+ LIVELINESS_CHANGED_TWITCH
+};
+
typedef struct status_cb_data
{
int raw_status_id;
uint32_t extra;
uint64_t handle;
bool add;
-}
-status_cb_data_t;
+} status_cb_data_t;
typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data);
@@ -67,6 +78,8 @@ struct prd_wr_match {
struct rd_pwr_match {
ddsrt_avl_node_t avlnode;
ddsi_guid_t pwr_guid;
+ unsigned pwr_alive: 1; /* tracks pwr's alive state */
+ uint32_t pwr_alive_vclock; /* used to ensure progress */
#ifdef DDSI_INCLUDE_SSM
nn_locator_t ssm_mc_loc;
nn_locator_t ssm_src_loc;
@@ -374,6 +387,7 @@ struct proxy_writer {
#ifdef DDSI_INCLUDE_SSM
unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */
#endif
+ uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */
struct nn_defrag *defrag; /* defragmenter for this proxy writer; FIXME: perhaps shouldn't be for historical data */
struct nn_reorder *reorder; /* message reordering for this proxy writer, out-of-sync readers can have their own, see pwr_rd_match */
struct nn_dqueue *dqueue; /* delivery queue for asynchronous delivery (historical data is always delivered asynchronously) */
@@ -652,8 +666,9 @@ int delete_proxy_reader (struct q_globals *gv, const struct ddsi_guid *guid, nn_
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp);
-int proxy_writer_set_alive (struct proxy_writer *pwr);
-int proxy_writer_set_notalive (struct proxy_writer *pwr);
+void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify);
+int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify);
+void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify);
int new_proxy_group (const struct ddsi_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
@@ -662,8 +677,6 @@ void delete_proxy_group (struct ephash *guid_hash, const struct ddsi_guid *guid,
rebuild them all (which only makes sense after previously having emptied them all). */
void rebuild_or_clear_writer_addrsets(struct q_globals *gv, int rebuild);
-void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch);
-
void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
struct ddsi_writer_info;
diff --git a/src/core/ddsi/src/ddsi_pmd.c b/src/core/ddsi/src/ddsi_pmd.c
index f187abb..035a9bf 100644
--- a/src/core/ddsi/src/ddsi_pmd.c
+++ b/src/core/ddsi/src/ddsi_pmd.c
@@ -129,9 +129,8 @@ void handle_pmd_message (const struct receiver_state *rst, nn_wctime_t timestamp
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
if ((proxypp = ephash_lookup_proxy_participant_guid (rst->gv->guid_hash, &ppguid)) == NULL)
RSTTRACE (" PPunknown");
-
- if (kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE &&
- (l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL)
+ else if (kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE &&
+ (l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL)
{
/* Renew lease for entity with shortest manual-by-participant lease */
lease_renew (l, now_et ());
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index b55606e..a199f63 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -64,6 +64,11 @@ struct deleted_participants_admin {
int64_t delay;
};
+struct proxy_writer_alive_state {
+ bool alive;
+ uint32_t vclock;
+};
+
static int compare_guid (const void *va, const void *vb);
static void augment_wr_prd_match (void *vnode, const void *vleft, const void *vright);
@@ -1431,6 +1436,19 @@ static void free_wr_rd_match (struct wr_rd_match *m)
if (m) ddsrt_free (m);
}
+static void proxy_writer_get_alive_state_locked (struct proxy_writer *pwr, struct proxy_writer_alive_state *st)
+{
+ st->alive = pwr->alive;
+ st->vclock = pwr->alive_vclock;
+}
+
+static void proxy_writer_get_alive_state (struct proxy_writer *pwr, struct proxy_writer_alive_state *st)
+{
+ ddsrt_mutex_lock (&pwr->e.lock);
+ proxy_writer_get_alive_state_locked (pwr, st);
+ ddsrt_mutex_unlock (&pwr->e.lock);
+}
+
static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struct proxy_reader *prd)
{
struct writer *wr;
@@ -1488,14 +1506,63 @@ static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struc
}
}
-void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, bool unmatch)
+static void reader_update_notify_pwr_alive_state (struct reader *rd, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state)
+{
+ struct rd_pwr_match *m;
+ bool notify = false;
+ int delta = 0; /* -1: alive -> not_alive; 0: unchanged; 1: not_alive -> alive */
+ ddsrt_mutex_lock (&rd->e.lock);
+ if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL)
+ {
+ if ((int32_t) (alive_state->vclock - m->pwr_alive_vclock) > 0)
+ {
+ delta = (int) alive_state->alive - (int) m->pwr_alive;
+ notify = true;
+ m->pwr_alive = alive_state->alive;
+ m->pwr_alive_vclock = alive_state->vclock;
+ }
+ }
+ ddsrt_mutex_unlock (&rd->e.lock);
+
+ if (delta < 0 && rd->rhc)
+ {
+ struct ddsi_writer_info wrinfo;
+ ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
+ ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
+ }
+
+ /* Liveliness changed events can race each other and can, potentially, be delivered
+ in a different order. */
+ if (notify && rd->status_cb)
+ {
+ status_cb_data_t data;
+ data.handle = pwr->e.iid;
+ if (delta == 0)
+ data.extra = (uint32_t) LIVELINESS_CHANGED_TWITCH;
+ else if (delta < 0)
+ data.extra = (uint32_t) LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE;
+ else
+ data.extra = (uint32_t) LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE;
+ data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
+ }
+}
+
+static void reader_update_notify_pwr_alive_state_guid (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr, const struct proxy_writer_alive_state *alive_state)
+{
+ struct reader *rd;
+ if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
+ reader_update_notify_pwr_alive_state (rd, pwr, alive_state);
+}
+
+static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy_writer *pwr)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rd_guid)) != NULL)
{
struct rd_pwr_match *m;
ddsrt_mutex_lock (&rd->e.lock);
- if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL && unmatch)
+ if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL)
ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m);
ddsrt_mutex_unlock (&rd->e.lock);
if (m != NULL)
@@ -1509,20 +1576,18 @@ void reader_drop_connection (const struct ddsi_guid *rd_guid, const struct proxy
if (rd->status_cb)
{
status_cb_data_t data;
- data.add = false;
data.handle = pwr->e.iid;
+ data.add = false;
+ data.extra = (uint32_t) (m->pwr_alive ? LIVELINESS_CHANGED_REMOVE_ALIVE : LIVELINESS_CHANGED_REMOVE_NOT_ALIVE);
+
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
- if (unmatch)
- {
- data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
- (rd->status_cb) (rd->status_cb_entity, &data);
- }
+ data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
}
}
- if (unmatch)
- free_rd_pwr_match (pwr->e.gv, m);
+ free_rd_pwr_match (pwr->e.gv, m);
}
}
@@ -1548,9 +1613,9 @@ static void reader_drop_local_connection (const struct ddsi_guid *rd_guid, const
if (rd->status_cb)
{
status_cb_data_t data;
-
- data.add = false;
data.handle = wr->e.iid;
+ data.add = false;
+ data.extra = (uint32_t) LIVELINESS_CHANGED_REMOVE_ALIVE;
data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
@@ -1789,12 +1854,14 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd)
}
}
-static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count)
+static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct proxy_writer_alive_state *alive_state)
{
struct rd_pwr_match *m = ddsrt_malloc (sizeof (*m));
ddsrt_avl_ipath_t path;
m->pwr_guid = pwr->e.guid;
+ m->pwr_alive = alive_state->alive;
+ m->pwr_alive_vclock = alive_state->vclock;
ddsrt_mutex_lock (&rd->e.lock);
@@ -1848,9 +1915,14 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr,
if (rd->status_cb)
{
status_cb_data_t data;
- data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
- data.add = true;
data.handle = pwr->e.iid;
+ data.add = true;
+ data.extra = (uint32_t) (alive_state->alive ? LIVELINESS_CHANGED_ADD_ALIVE : LIVELINESS_CHANGED_ADD_NOT_ALIVE);
+
+ data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
+
+ data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
@@ -1882,14 +1954,15 @@ static void reader_add_local_connection (struct reader *rd, struct writer *wr)
if (rd->status_cb)
{
status_cb_data_t data;
- data.add = true;
data.handle = wr->e.iid;
-
- data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
- (rd->status_cb) (rd->status_cb_entity, &data);
+ data.add = true;
+ data.extra = (uint32_t) LIVELINESS_CHANGED_ADD_ALIVE;
data.raw_status_id = (int) DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
(rd->status_cb) (rd->status_cb_entity, &data);
+
+ data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
+ (rd->status_cb) (rd->status_cb_entity, &data);
}
}
}
@@ -2007,16 +2080,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
qxev_pwr_entityid (pwr, &rd->e.guid.prefix);
ELOGDISC (pwr, "\n");
-
- if (rd->status_cb)
- {
- status_cb_data_t data;
- data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
- data.add = true;
- data.handle = pwr->e.iid;
- (rd->status_cb) (rd->status_cb_entity, &data);
- }
-
return;
already_matched:
@@ -2188,6 +2251,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
const int isb1 = (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0);
dds_qos_policy_id_t reason;
nn_count_t init_count;
+ struct proxy_writer_alive_state alive_state;
if (isb0 != isb1)
return;
if (rd->e.onlylocal)
@@ -2197,8 +2261,18 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
reader_qos_mismatch (rd, reason);
return;
}
- reader_add_connection (rd, pwr, &init_count);
+
+ /* Initialze the reader's tracking information for the writer liveliness state to something
+ sensible, but that may be outdated by the time the reader gets added to the writer's list
+ of matching readers. */
+ proxy_writer_get_alive_state (pwr, &alive_state);
+ reader_add_connection (rd, pwr, &init_count, &alive_state);
proxy_writer_add_connection (pwr, rd, tnow, init_count);
+
+ /* Once everything is set up: update with the latest state, any updates to the alive state
+ happening in parallel will cause this to become a no-op. */
+ proxy_writer_get_alive_state (pwr, &alive_state);
+ reader_update_notify_pwr_alive_state (rd, pwr, &alive_state);
}
static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
@@ -4274,6 +4348,7 @@ int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, cons
pwr->nackfragcount = 0;
pwr->last_fragnum_reset = 0;
pwr->alive = 1;
+ pwr->alive_vclock = 0;
ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, 1);
if (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor)) {
/* The DDSI built-in proxy writers always deliver
@@ -4453,7 +4528,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
{
struct pwr_rd_match *m = ddsrt_avl_root_non_empty (&pwr_readers_treedef, &pwr->readers);
ddsrt_avl_delete (&pwr_readers_treedef, &pwr->readers, m);
- reader_drop_connection (&m->rd_guid, pwr, true);
+ reader_drop_connection (&m->rd_guid, pwr);
update_reader_init_acknack_count (&pwr->e.gv->logconfig, pwr->e.gv->guid_hash, &m->rd_guid, m->count);
free_pwr_rd_match (m);
}
@@ -4490,62 +4565,86 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false);
ephash_remove_proxy_writer_guid (gv->guid_hash, pwr);
ddsrt_mutex_unlock (&gv->lock);
- if (proxy_writer_set_notalive (pwr) != DDS_RETCODE_OK)
+ if (proxy_writer_set_notalive (pwr, false) != DDS_RETCODE_OK)
GVLOGDISC ("proxy_writer_set_notalive failed for "PGUIDFMT"\n", PGUID(*guid));
- /* Set lease expiry for this pwr to never so that the pwr will not be set
- to alive again while it is scheduled for being deleted. */
- if (pwr->c.xqos->liveliness.lease_duration != T_NEVER)
- lease_renew (pwr->lease, (nn_etime_t){ T_NEVER });
gcreq_proxy_writer (pwr);
return DDS_RETCODE_OK;
}
-int proxy_writer_set_alive (struct proxy_writer *pwr)
+static void proxy_writer_notify_liveliness_change_may_unlock (struct proxy_writer *pwr)
{
- /* Caller has pwr->e.lock, so we can safely read pwr->alive. For updating
- * this field this function is also taking pwr->c.proxypp->e.lock */
- ddsrt_avl_iter_t it;
- if (pwr->alive)
- return DDS_RETCODE_PRECONDITION_NOT_MET;
+ struct proxy_writer_alive_state alive_state;
+ proxy_writer_get_alive_state_locked (pwr, &alive_state);
+
+ struct ddsi_guid rdguid;
+ struct pwr_rd_match *m;
+ memset (&rdguid, 0, sizeof (rdguid));
+ while (pwr->alive_vclock == alive_state.vclock &&
+ (m = ddsrt_avl_lookup_succ (&pwr_readers_treedef, &pwr->readers, &rdguid)) != NULL)
+ {
+ rdguid = m->rd_guid;
+ ddsrt_mutex_unlock (&pwr->e.lock);
+ /* unlocking pwr means alive state may have changed already; we break out of the loop once we
+ detect this but there for the reader in the current iteration, anything is possible */
+ reader_update_notify_pwr_alive_state_guid (&rdguid, pwr, &alive_state);
+ ddsrt_mutex_lock (&pwr->e.lock);
+ }
+}
+
+void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify)
+{
+ /* Caller has pwr->e.lock, so we can safely read pwr->alive. Updating pwr->alive requires
+ also taking pwr->c.proxypp->e.lock because pwr->alive <=> (pwr->lease in proxypp's lease
+ heap). */
+ assert (!pwr->alive);
+
ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
pwr->alive = true;
-
- for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
- {
- struct reader *rd;
- if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
- {
- status_cb_data_t data;
- data.add = true;
- data.handle = pwr->e.iid;
- data.raw_status_id = (int) DDS_LIVELINESS_CHANGED_STATUS_ID;
- (rd->status_cb) (rd->status_cb_entity, &data);
- }
- }
+ pwr->alive_vclock++;
if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
proxy_participant_add_pwr_lease_locked (pwr->c.proxypp, pwr);
ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
- return DDS_RETCODE_OK;
+
+ if (notify)
+ proxy_writer_notify_liveliness_change_may_unlock (pwr);
}
-int proxy_writer_set_notalive (struct proxy_writer *pwr)
+int proxy_writer_set_notalive (struct proxy_writer *pwr, bool notify)
{
/* Caller should not have taken pwr->e.lock and pwr->c.proxypp->e.lock;
* this function takes both locks to update pwr->alive value */
- int ret = DDS_RETCODE_OK;
ddsrt_mutex_lock (&pwr->e.lock);
if (!pwr->alive)
- ret = DDS_RETCODE_PRECONDITION_NOT_MET;
+ {
+ ddsrt_mutex_unlock (&pwr->e.lock);
+ return DDS_RETCODE_PRECONDITION_NOT_MET;
+ }
+
+ ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
+ pwr->alive = false;
+ pwr->alive_vclock++;
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr);
+ ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
+
+ if (notify)
+ proxy_writer_notify_liveliness_change_may_unlock (pwr);
+ ddsrt_mutex_unlock (&pwr->e.lock);
+ return DDS_RETCODE_OK;
+}
+
+void proxy_writer_set_notalive_guid (struct q_globals *gv, const struct ddsi_guid *pwrguid, bool notify)
+{
+ struct proxy_writer *pwr;
+ if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, pwrguid)) == NULL)
+ GVLOGDISC (" "PGUIDFMT"?\n", PGUID (*pwrguid));
else
{
- ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
- pwr->alive = false;
- if (pwr->c.xqos->liveliness.lease_duration != T_NEVER && pwr->c.xqos->liveliness.kind != DDS_LIVELINESS_MANUAL_BY_TOPIC)
- proxy_participant_remove_pwr_lease_locked (pwr->c.proxypp, pwr);
- ddsrt_mutex_unlock (&pwr->c.proxypp->e.lock);
+ GVLOGDISC ("proxy_writer_set_notalive_guid ("PGUIDFMT")", PGUID (*pwrguid));
+ if (proxy_writer_set_notalive (pwr, notify) == DDS_RETCODE_PRECONDITION_NOT_MET)
+ GVLOGDISC (" pwr was not alive");
+ GVLOGDISC ("\n");
}
- ddsrt_mutex_unlock (&pwr->e.lock);
- return ret;
}
/* PROXY-READER ----------------------------------------------------- */
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index 0db530c..ccd0306 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -275,27 +275,8 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
delete_proxy_participant_by_guid (gv, &g, now(), 1);
break;
case EK_PROXY_WRITER:
- {
- struct proxy_writer *pwr;
- ddsrt_avl_iter_t it;
- if ((pwr = ephash_lookup_proxy_writer_guid (gv->guid_hash, &g)) == NULL)
- {
- GVLOGDISC (" "PGUIDFMT"?\n", PGUID (g));
- ddsrt_mutex_lock (&gv->leaseheap_lock);
- continue;
- }
- GVLOGDISC ("proxy_writer_set_notalive ("PGUIDFMT")", PGUID (g));
- if (proxy_writer_set_notalive (pwr) == DDS_RETCODE_PRECONDITION_NOT_MET)
- {
- GVLOGDISC (" pwr was not alive");
- ddsrt_mutex_lock (&gv->leaseheap_lock);
- continue;
- }
- GVLOGDISC ("\n");
- for (struct pwr_rd_match *m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
- reader_drop_connection (&m->rd_guid, pwr, false);
+ proxy_writer_set_notalive_guid (gv, &g, true);
break;
- }
case EK_PARTICIPANT:
case EK_READER:
case EK_WRITER:
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index b026022..b20dd06 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -2114,18 +2114,26 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
return;
}
+ /* Proxy participant's "automatic" lease has to be renewed always, manual-by-participant one only
+ for data published by the application. If pwr->lease exists, it is in some manual lease mode,
+ so check whether it is actually in manual-by-topic mode before renewing it. As pwr->lease is
+ set once (during entity creation) we can read it outside the lock, keeping all the lease
+ renewals together. */
lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL && renew_manbypp_lease)
lease_renew (lease, tnow);
+ if (pwr->lease && pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ lease_renew (pwr->lease, tnow);
/* Shouldn't lock the full writer, but will do so for now */
ddsrt_mutex_lock (&pwr->e.lock);
- if (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && pwr->c.xqos->liveliness.lease_duration != T_NEVER)
- lease_renew (pwr->lease, tnow);
-
+ /* A change in transition from not-alive to alive is relatively complicated
+ and may involve temporarily unlocking the proxy writer during the process
+ (to avoid unnecessarily holding pwr->e.lock while invoking listeners on
+ the reader) */
if (!pwr->alive)
- proxy_writer_set_alive (pwr);
+ proxy_writer_set_alive_may_unlock (pwr, true);
/* Don't accept data when reliable readers exist and we haven't yet seen
a heartbeat telling us what the "current" sequence number of the writer
From 63df8cb38d24e6eea96f0bc2bddb70ccf72d8683 Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Thu, 21 Nov 2019 16:59:00 +0100
Subject: [PATCH 50/55] Fix to prevent proxy writer from getting alive while
deleting
Signed-off-by: Dennis Potman
---
src/core/ddsi/src/q_entity.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index a199f63..b15b807 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -4598,6 +4598,13 @@ void proxy_writer_set_alive_may_unlock (struct proxy_writer *pwr, bool notify)
heap). */
assert (!pwr->alive);
+ /* check that proxy writer still exists (when deleting it is removed from guid hash) */
+ if (ephash_lookup_proxy_writer_guid (pwr->e.gv->guid_hash, &pwr->e.guid) == NULL)
+ {
+ ELOGDISC (pwr, "proxy_writer_set_alive_may_unlock("PGUIDFMT") - not in guid_hash, pwr deleting\n", PGUID (pwr->e.guid));
+ return;
+ }
+
ddsrt_mutex_lock (&pwr->c.proxypp->e.lock);
pwr->alive = true;
pwr->alive_vclock++;
From 827fb76cf47a06c5e7d344991c7244e4c3c6966c Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Thu, 21 Nov 2019 17:06:46 +0100
Subject: [PATCH 51/55] Made the liveliness tests a bit more robust wrt timing
(retry with increased lease duration on failures that are probably caused by
load from other tests that are run in parallel)
Signed-off-by: Dennis Potman
---
src/core/ddsc/tests/liveliness.c | 304 ++++++++++++++++++-------------
1 file changed, 174 insertions(+), 130 deletions(-)
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index 3bee980..189752a 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -146,79 +146,85 @@ static dds_duration_t get_ldur_config(dds_entity_t participant)
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
- CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
- CU_DataPoints(uint32_t, 200, 200, 200, 200), /* lease duration */
- CU_DataPoints(double, 5, 10, 5, 5), /* delay (n times lease duration) */
+ CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
+ CU_DataPoints(uint32_t, 200, 500, 100, 100), /* lease duration */
+ CU_DataPoints(double, 10, 5, 5, 5), /* delay (n times lease duration) */
};
#undef MT
#undef MP
#undef A
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- seqno_t start_seqno, end_seqno;
- dds_qos_t *rqos;
- dds_qos_t *wqos;
- dds_entity_t waitset;
- dds_attach_t triggered;
- uint32_t status;
- char name[100];
- dds_time_t t;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ seqno_t start_seqno, end_seqno;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ char name[100];
+ dds_time_t t;
- t = dds_time();
- printf("%d.%06d running test: kind %s, lease duration %d, delay %f\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- kind == 0 ? "A" : "MP", ldur, mult);
+ t = dds_time();
+ printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur));
- /* topics */
- create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
+ /* wait for initial PMD to be sent by the participant */
+ while (get_pmd_seqno(g_pub_participant) < 1)
+ dds_sleepfor (DDS_MSECS(50));
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* topics */
+ create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
- /* waitset on reader */
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writer */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ /* waitset on reader */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* check no of PMD messages sent */
- start_seqno = get_pmd_seqno(g_pub_participant);
- dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
- end_seqno = get_pmd_seqno(g_pub_participant);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- t = dds_time();
- printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- start_seqno, end_seqno);
+ /* check no of PMD messages sent */
+ start_seqno = get_pmd_seqno(g_pub_participant);
+ dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
+ end_seqno = get_pmd_seqno(g_pub_participant);
- /* end-start should be mult - 1, but allow 1 pmd sample to be lost */
- CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? mult - 2 : 0))
- if (kind != DDS_LIVELINESS_AUTOMATIC)
- CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
+ t = dds_time();
+ printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ start_seqno, end_seqno);
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* End-start should be mult - 1 under ideal circumstances, but consider the test successful
+ when at least 50% of the expected PMD's was sent. This checks that the frequency for sending
+ PMDs was increased when the writer was added. */
+ CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0))
+ if (kind != DDS_LIVELINESS_AUTOMATIC)
+ CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
+
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
@@ -515,7 +521,7 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li
* is deleted immediately after creating.
*/
#define MAX_WRITERS 100
-CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini)
+CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
dds_entity_t pub_topic;
dds_entity_t sub_topic;
@@ -670,85 +676,123 @@ CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
};
-CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout=30)
+CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout=60)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- dds_qos_t *rqos;
- struct dds_liveliness_changed_status lstatus;
- char name[100];
- dds_duration_t ldur = DDS_MSECS (300);
- uint32_t wr_cnt = 0;
- dds_time_t tstop;
- uint32_t stopped;
+ dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS];
+ dds_qos_t *rqos;
+ struct dds_liveliness_changed_status lstatus;
+ char name[100];
+ uint32_t ldur = 100, wr_cnt, run = 1, stopped;
+ dds_time_t tstart, tstop, t;
+ bool test_finished = false;
- assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
- printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u\n", wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
+ do
+ {
+ wr_cnt = 0;
+ assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
+ printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n",
+ wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur);
- /* topics */
- create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writers */
- for (size_t n = 0; n < wr_cnt_auto; n++)
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, ldur, &writers[wr_cnt++], pub_topic, reader);
- for (size_t n = 0; n < wr_cnt_man_pp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur, &writers[wr_cnt++], pub_topic, reader);
- for (size_t n = 0; n < wr_cnt_man_tp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, ldur, &writers[wr_cnt++], pub_topic, reader);
+ /* writers */
+ for (size_t n = 0; n < wr_cnt_auto; n++)
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ tstart = dds_time();
+ for (size_t n = 0; n < wr_cnt_man_pp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_tp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ t = dds_time();
+ if (t - tstart > DDS_MSECS(0.5 * ldur))
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d failed to create writers with non-automatic liveliness kind in time\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
- /* check status counts before proxy writer is expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+ /* delay for more than lease duration and assert liveliness on writers:
+ all writers (including man-by-pp) should be kept alive */
+ tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
+ stopped = 0;
+ do
+ {
+ for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
+ dds_assert_liveliness (writers[n]);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
+ if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0)
+ {
+ ldur *= 10 / (run + 1);
+ printf("incorrect number of writers alive or stopped writers\n");
+ }
+ else
+ {
+ /* delay for more than lease duration and assert liveliness on participant:
+ writers with liveliness man-by-pp should be kept alive, man-by-topic writers
+ should stop */
+ tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
+ stopped = 0;
+ do
+ {
+ dds_assert_liveliness (g_pub_participant);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor (DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive with dds_assert_liveliness on participant: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
+ if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp || stopped != wr_cnt_man_tp)
+ {
+ ldur *= 10 / (run + 1);
+ printf("incorrect number of writers alive or stopped writers\n");
+ }
+ else
+ {
+ test_finished = true;
+ }
+ }
+ }
- /* delay for more than lease duration and assert liveliness on writers:
- all writers (including man-by-pp) should be kept alive */
- tstop = dds_time() + 4 * ldur / 3;
- stopped = 0;
- do
- {
- for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
- dds_assert_liveliness (writers[n]);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- CU_ASSERT_EQUAL_FATAL(stopped, 0);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (size_t n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- /* delay for more than lease duration and assert liveliness on participant:
- writers with liveliness man-by-pp should be kept alive, man-by-topic writers
- should stop */
- tstop = dds_time() + 4 * ldur / 3;
- stopped = 0;
- do
- {
- dds_assert_liveliness (g_pub_participant);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- CU_ASSERT_EQUAL_FATAL(stopped, wr_cnt_man_tp);
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("writers alive_count: %d\n", lstatus.alive_count);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp);
-
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- for (size_t n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ if (!test_finished)
+ {
+ if (++run > 3)
+ {
+ CU_FAIL_FATAL("Run limit reached");
+ test_finished = true;
+ continue;
+ }
+ else
+ {
+ printf("restarting test with ldur %d\n", ldur);
+ }
+ }
+ } while (!test_finished);
}
#undef MAX_WRITERS
From 9ae8af8254c2713ba6a48dcde3a4e674d96a5769 Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Thu, 21 Nov 2019 21:35:30 +0100
Subject: [PATCH 52/55] Changed the behaviour of the _change counters for
liveliness events and changed the tests accordingly.
Signed-off-by: Dennis Potman
---
src/core/ddsc/src/dds_reader.c | 9 +++++----
src/core/ddsc/tests/entity_status.c | 8 ++++----
src/core/ddsc/tests/listener.c | 8 ++++----
src/core/ddsc/tests/liveliness.c | 26 ++++++++++++++++++++------
4 files changed, 33 insertions(+), 18 deletions(-)
diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c
index be1c045..c969768 100644
--- a/src/core/ddsc/src/dds_reader.c
+++ b/src/core/ddsc/src/dds_reader.c
@@ -253,25 +253,26 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
st->not_alive_count_change++;
break;
case LIVELINESS_CHANGED_REMOVE_NOT_ALIVE:
+ st->not_alive_count--;
+ st->not_alive_count_change--;
break;
case LIVELINESS_CHANGED_REMOVE_ALIVE:
st->alive_count--;
- st->not_alive_count++;
- st->not_alive_count_change++;
+ st->alive_count_change--;
break;
case LIVELINESS_CHANGED_ALIVE_TO_NOT_ALIVE:
st->alive_count--;
+ st->alive_count_change--;
st->not_alive_count++;
st->not_alive_count_change++;
break;
case LIVELINESS_CHANGED_NOT_ALIVE_TO_ALIVE:
st->not_alive_count--;
+ st->not_alive_count_change--;
st->alive_count++;
st->alive_count_change++;
break;
case LIVELINESS_CHANGED_TWITCH:
- st->alive_count_change++;
- st->not_alive_count_change++;
break;
}
st->last_publication_handle = data->handle;
diff --git a/src/core/ddsc/tests/entity_status.c b/src/core/ddsc/tests/entity_status.c
index 4f1f94d..297f2cd 100644
--- a/src/core/ddsc/tests/entity_status.c
+++ b/src/core/ddsc/tests/entity_status.c
@@ -360,9 +360,9 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
ret = dds_get_liveliness_changed_status (rea, &liveliness_changed);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
- CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
- CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
- CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,1);
+ CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, -1);
+ CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
+ CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
/* Second call should reset the changed count. */
@@ -370,7 +370,7 @@ CU_Test(ddsc_entity, liveliness_changed, .init=init_entity_status, .fini=fini_en
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
- CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
+ CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change,0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_i_hdl);
}
diff --git a/src/core/ddsc/tests/listener.c b/src/core/ddsc/tests/listener.c
index 2b5aa00..49a2915 100644
--- a/src/core/ddsc/tests/listener.c
+++ b/src/core/ddsc/tests/listener.c
@@ -1196,9 +1196,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS);
CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count, 0);
- CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, 0);
- CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 1);
- CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 1);
+ CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, -1);
+ CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 0);
+ CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl);
/* The listener should have reset the count_change. */
@@ -1206,7 +1206,7 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0);
- CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 1);
+ CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0);
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
}
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index 189752a..cf876aa 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -530,7 +530,7 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
dds_entity_t waitset;
dds_qos_t *wqos;
struct dds_liveliness_changed_status lstatus;
- uint32_t wr_cnt = 0;
+ uint32_t alive_writers_auto = 0, alive_writers_man = 0;
char name[100];
dds_qos_t *rqos;
dds_attach_t triggered;
@@ -556,6 +556,7 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ alive_writers_man++;
/* create writers */
for (n = 1; n < MAX_WRITERS; n++)
@@ -565,24 +566,37 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
dds_write (writers[n], &sample);
if (n % 3 == 2)
dds_delete(writers[n]);
+ else if (n % 2)
+ alive_writers_auto++;
+ else
+ alive_writers_man++;
}
dds_delete_qos(wqos);
+ printf("alive_writers_auto: %d, alive_writers_man: %d\n", alive_writers_auto, alive_writers_man);
- /* wait for all writers to become alive */
- while (wr_cnt < MAX_WRITERS)
+ /* wait for auto liveliness writers to become alive and manual-by-pp writers to become not-alive */
+ do
{
CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
- wr_cnt += (uint32_t)lstatus.alive_count_change;
+ printf("alive: %d, not-alive: %d\n", lstatus.alive_count, lstatus.not_alive_count);
dds_sleepfor (DDS_MSECS(50));
}
- CU_ASSERT_EQUAL_FATAL (wr_cnt, MAX_WRITERS);
+ while (lstatus.alive_count != alive_writers_auto || lstatus.not_alive_count != alive_writers_man);
/* cleanup remaining writers */
- for (n = 0; n < wr_cnt; n++)
+ for (n = 0; n < MAX_WRITERS; n++)
{
if (n % 3 != 2)
CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
}
+ /* wait for alive_count and not_alive_count to become 0 */
+ do
+ {
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
+ printf("alive: %d, not: %d\n", lstatus.alive_count, lstatus.not_alive_count);
+ dds_sleepfor (DDS_MSECS(50));
+ }
+ while (lstatus.alive_count > 0 || lstatus.not_alive_count > 0);
CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
From e97e340650b29d7cdbb2fade40dab8147659e7be Mon Sep 17 00:00:00 2001
From: Dennis Potman
Date: Wed, 4 Dec 2019 09:12:48 +0100
Subject: [PATCH 53/55] A few fixes in the liveliness qos implementation: -
moved de-registration of a lease to a separate function, so that it is called
synchronously when a pwr is deleted, to prevent the lease from expiring
(before this change, the lease was renewed with t_never, but that does not
work because of a check with early out in lease_renew) - handle
proxypp->owns_lease correctly: when an OpenSplice instance was running in the
same network and participants from OpenSplice were discovered, the
lease-renewal fails in case the proxy participant's lease was not registered
in minl_auto, which happens when the proxypp depends on its parent (ddsi2)
participant. - increased lease duration in create_delete_writer stress test
to avoid failed tests due to delayed pmd messages - fixed the indenting in
liveliness tests source file
Signed-off-by: Dennis Potman
---
src/core/ddsc/tests/liveliness.c | 1167 +++++++++++-----------
src/core/ddsi/include/dds/ddsi/q_lease.h | 1 +
src/core/ddsi/src/q_ddsi_discovery.c | 4 +-
src/core/ddsi/src/q_entity.c | 97 +-
src/core/ddsi/src/q_lease.c | 12 +-
src/core/ddsi/src/q_receive.c | 26 +-
6 files changed, 675 insertions(+), 632 deletions(-)
diff --git a/src/core/ddsc/tests/liveliness.c b/src/core/ddsc/tests/liveliness.c
index cf876aa..32c5b3a 100644
--- a/src/core/ddsc/tests/liveliness.c
+++ b/src/core/ddsc/tests/liveliness.c
@@ -44,44 +44,44 @@ 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;
+ /* 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
+ /* Domains for pub and sub use a different domain id, but the portgain setting
* in configuration is 0, so that both domains will map to the same port number.
* This allows to create two domains in a single test process. */
- char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
- char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
- g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
- g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
- dds_free(conf_pub);
- dds_free(conf_sub);
+ char *conf_pub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_PUB);
+ char *conf_sub = ddsrt_expand_envvars(DDS_CONFIG_NO_PORT_GAIN, DDS_DOMAINID_SUB);
+ g_pub_domain = dds_create_domain(DDS_DOMAINID_PUB, conf_pub);
+ g_sub_domain = dds_create_domain(DDS_DOMAINID_SUB, conf_sub);
+ dds_free(conf_pub);
+ dds_free(conf_sub);
- g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
- CU_ASSERT_FATAL(g_pub_participant > 0);
- g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
- CU_ASSERT_FATAL(g_sub_participant > 0);
+ g_pub_participant = dds_create_participant(DDS_DOMAINID_PUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_participant > 0);
+ g_sub_participant = dds_create_participant(DDS_DOMAINID_SUB, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_participant > 0);
- g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
- CU_ASSERT_FATAL(g_pub_publisher > 0);
- g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
- CU_ASSERT_FATAL(g_sub_subscriber > 0);
+ g_pub_publisher = dds_create_publisher(g_pub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_pub_publisher > 0);
+ g_sub_subscriber = dds_create_subscriber(g_sub_participant, NULL, NULL);
+ CU_ASSERT_FATAL(g_sub_subscriber > 0);
}
static void liveliness_fini(void)
{
- dds_delete(g_sub_subscriber);
- dds_delete(g_pub_publisher);
- dds_delete(g_sub_participant);
- dds_delete(g_pub_participant);
- dds_delete(g_sub_domain);
- dds_delete(g_pub_domain);
+ dds_delete(g_sub_subscriber);
+ dds_delete(g_pub_publisher);
+ dds_delete(g_sub_participant);
+ dds_delete(g_pub_participant);
+ dds_delete(g_sub_domain);
+ dds_delete(g_pub_domain);
}
/**
@@ -91,20 +91,20 @@ static void liveliness_fini(void)
*/
static seqno_t get_pmd_seqno(dds_entity_t participant)
{
- seqno_t seqno;
- struct dds_entity *pp_entity;
- struct participant *pp;
- struct writer *wr;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
- pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
- wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
- CU_ASSERT_FATAL(wr != NULL);
- assert(wr != NULL); /* for Clang's static analyzer */
- seqno = wr->seq;
- thread_state_asleep(lookup_thread_state());
- dds_entity_unpin(pp_entity);
- return seqno;
+ seqno_t seqno;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ struct writer *wr;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ wr = get_builtin_writer(pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER);
+ CU_ASSERT_FATAL(wr != NULL);
+ assert(wr != NULL); /* for Clang's static analyzer */
+ seqno = wr->seq;
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return seqno;
}
/**
@@ -112,16 +112,16 @@ static seqno_t get_pmd_seqno(dds_entity_t participant)
*/
static dds_duration_t get_pmd_interval(dds_entity_t participant)
{
- dds_duration_t intv;
- struct dds_entity *pp_entity;
- struct participant *pp;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
- pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
- intv = pp_get_pmd_interval(pp);
- thread_state_asleep(lookup_thread_state());
- dds_entity_unpin(pp_entity);
- return intv;
+ dds_duration_t intv;
+ struct dds_entity *pp_entity;
+ struct participant *pp;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv);
+ pp = ephash_lookup_participant_guid(pp_entity->m_domain->gv.guid_hash, &pp_entity->m_guid);
+ intv = pp_get_pmd_interval(pp);
+ thread_state_asleep(lookup_thread_state());
+ dds_entity_unpin(pp_entity);
+ return intv;
}
/**
@@ -129,15 +129,14 @@ static dds_duration_t get_pmd_interval(dds_entity_t participant)
*/
static dds_duration_t get_ldur_config(dds_entity_t participant)
{
- struct dds_entity *pp_entity;
- dds_duration_t ldur;
- CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
- ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
- dds_entity_unpin(pp_entity);
- return ldur;
+ struct dds_entity *pp_entity;
+ dds_duration_t ldur;
+ CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0);
+ ldur = (dds_duration_t)pp_entity->m_domain->gv.config.lease_duration;
+ dds_entity_unpin(pp_entity);
+ return ldur;
}
-
/**
* Test that the correct number of PMD messages is sent for
* the various liveliness kinds.
@@ -146,85 +145,85 @@ static dds_duration_t get_ldur_config(dds_entity_t participant)
#define MP DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
#define MT DDS_LIVELINESS_MANUAL_BY_TOPIC
CU_TheoryDataPoints(ddsc_liveliness, pmd_count) = {
- CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
- CU_DataPoints(uint32_t, 200, 500, 100, 100), /* lease duration */
- CU_DataPoints(double, 10, 5, 5, 5), /* delay (n times lease duration) */
+ CU_DataPoints(dds_liveliness_kind_t, A, A, MP, MT), /* liveliness kind */
+ CU_DataPoints(uint32_t, 200, 500, 100, 100), /* lease duration */
+ CU_DataPoints(double, 10, 5, 5, 5), /* delay (n times lease duration) */
};
#undef MT
#undef MP
#undef A
CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_liveliness, pmd_count, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- seqno_t start_seqno, end_seqno;
- dds_qos_t *rqos;
- dds_qos_t *wqos;
- dds_entity_t waitset;
- dds_attach_t triggered;
- uint32_t status;
- char name[100];
- dds_time_t t;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ seqno_t start_seqno, end_seqno;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ char name[100];
+ dds_time_t t;
- t = dds_time();
- printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur));
+ t = dds_time();
+ printf("%d.%06d running test: kind %s, lease duration %d, delay %d\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ kind == 0 ? "A" : "MP", ldur, (int32_t)(mult * ldur));
- /* wait for initial PMD to be sent by the participant */
- while (get_pmd_seqno(g_pub_participant) < 1)
- dds_sleepfor (DDS_MSECS(50));
+ /* wait for initial PMD to be sent by the participant */
+ while (get_pmd_seqno(g_pub_participant) < 1)
+ dds_sleepfor(DDS_MSECS(50));
- /* topics */
- create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_pmd_count", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* waitset on reader */
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* waitset on reader */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* writer */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(1)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check no of PMD messages sent */
- start_seqno = get_pmd_seqno(g_pub_participant);
- dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
- end_seqno = get_pmd_seqno(g_pub_participant);
+ /* check no of PMD messages sent */
+ start_seqno = get_pmd_seqno(g_pub_participant);
+ dds_sleepfor(DDS_MSECS((dds_duration_t)(mult * ldur)));
+ end_seqno = get_pmd_seqno(g_pub_participant);
- t = dds_time();
- printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
- start_seqno, end_seqno);
+ t = dds_time();
+ printf("%d.%06d PMD sequence no: start %" PRId64 " -> end %" PRId64 "\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000,
+ start_seqno, end_seqno);
- /* End-start should be mult - 1 under ideal circumstances, but consider the test successful
+ /* End-start should be mult - 1 under ideal circumstances, but consider the test successful
when at least 50% of the expected PMD's was sent. This checks that the frequency for sending
PMDs was increased when the writer was added. */
- CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0))
- if (kind != DDS_LIVELINESS_AUTOMATIC)
- CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
+ CU_ASSERT(end_seqno - start_seqno >= (kind == DDS_LIVELINESS_AUTOMATIC ? (50 * (mult - 1)) / 100 : 0))
+ if (kind != DDS_LIVELINESS_AUTOMATIC)
+ CU_ASSERT(get_pmd_seqno(g_pub_participant) - start_seqno < mult)
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
@@ -233,163 +232,163 @@ CU_Theory((dds_liveliness_kind_t kind, uint32_t ldur, double mult), ddsc_livelin
* liveliness kinds.
*/
CU_TheoryDataPoints(ddsc_liveliness, expire_liveliness_kinds) = {
- CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
- CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
- CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
- CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
- CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
+ CU_DataPoints(uint32_t, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200), /* lease duration for initial test run (increased for each retry when test fails) */
+ CU_DataPoints(double, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 2, 2, 2, 2, 2, 2, 2, 2, 2), /* delay (n times lease duration) */
+ CU_DataPoints(uint32_t, 1, 0, 2, 0, 1, 0, 0, 1, 1, 2, 0, 5, 0, 15, 15), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 0, 0, 0, 1, 0, 2, 2, 5, 10, 0, 15), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 2, 2, 1, 1, 1, 1, 0, 1, 1, 2, 5, 0, 10), /* number of writers with manual-by-topic liveliness */
};
CU_Theory((uint32_t ldur, double mult, uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, expire_liveliness_kinds, .init = liveliness_init, .fini = liveliness_fini, .timeout = 120)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t *writers;
- dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
- dds_entity_t waitset;
- dds_attach_t triggered;
- struct dds_liveliness_changed_status lstatus;
- uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
- char name[100];
- dds_time_t tstart, t;
- bool test_finished = false;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t *writers;
+ dds_qos_t *rqos, *wqos_auto, *wqos_man_pp, *wqos_man_tp;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ struct dds_liveliness_changed_status lstatus;
+ uint32_t status, n, run = 1, wr_cnt = wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp;
+ char name[100];
+ dds_time_t tstart, t;
+ bool test_finished = false;
- do
- {
- tstart = dds_time();
- printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
- (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
- ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
+ do
+ {
+ tstart = dds_time();
+ printf("%d.%06d running test: lease duration %d, delay %f, auto/man-by-part/man-by-topic %u/%u/%u\n",
+ (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000,
+ ldur, mult, wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp);
- /* topics */
- create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_expire_kinds", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writers */
- CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
+ /* writers */
+ CU_ASSERT_FATAL((wqos_auto = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_auto, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_pp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_pp, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((wqos_man_tp = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos_man_tp, DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
- for (n = 0; n < wr_cnt; n++)
- {
- dds_qos_t *wqos;
- wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
- CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- }
- dds_delete_qos(wqos_auto);
- dds_delete_qos(wqos_man_pp);
- dds_delete_qos(wqos_man_tp);
+ writers = dds_alloc(wr_cnt * sizeof(dds_entity_t));
+ for (n = 0; n < wr_cnt; n++)
+ {
+ dds_qos_t *wqos;
+ wqos = n < wr_cnt_auto ? wqos_auto : (n < (wr_cnt_auto + wr_cnt_man_pp) ? wqos_man_pp : wqos_man_tp);
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ }
+ dds_delete_qos(wqos_auto);
+ dds_delete_qos(wqos_man_pp);
+ dds_delete_qos(wqos_man_tp);
- t = dds_time();
- if (t - tstart > DDS_MSECS(0.5 * ldur))
- {
- ldur *= 10 / (run + 1);
- printf("%d.%06d failed to create writers in time\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
- }
- else
- {
- /* check alive count before proxy writers are expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
+ t = dds_time();
+ if (t - tstart > DDS_MSECS(0.5 * ldur))
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d failed to create writers in time\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count before proxy writers are expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("%d.%06d writers alive: %d\n", (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, lstatus.alive_count);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt);
- dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
- uint32_t stopped = 0;
- do
- {
- dds_duration_t w = tstop - dds_time();
- CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- } while (dds_time() < tstop);
- t = dds_time();
- printf("%d.%06d writers stopped: %u\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
+ dds_time_t tstop = tstart + DDS_MSECS((dds_duration_t)(mult * ldur));
+ uint32_t stopped = 0;
+ do
+ {
+ dds_duration_t w = tstop - dds_time();
+ CU_ASSERT_FATAL((dds_waitset_wait(waitset, &triggered, 1, w > 0 ? w : 0)) >= 0);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ } while (dds_time() < tstop);
+ t = dds_time();
+ printf("%d.%06d writers stopped: %u\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, stopped);
- size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
- if (stopped != exp_stopped)
- {
- ldur *= 10 / (run + 1);
- printf("%d.%06d incorrect number of stopped writers\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
- }
- else
- {
- /* check alive count */
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
- test_finished = true;
- }
- }
+ size_t exp_stopped = mult < 1 ? 0 : (wr_cnt_man_pp + wr_cnt_man_tp);
+ if (stopped != exp_stopped)
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d incorrect number of stopped writers\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check alive count */
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL(lstatus.alive_count, mult < 1 ? wr_cnt : wr_cnt_auto);
+ test_finished = true;
+ }
+ }
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- for (n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- dds_free(writers);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ dds_free(writers);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- if (!test_finished)
- {
- if (++run > 3)
- {
- printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
- CU_FAIL_FATAL("Run limit reached");
- test_finished = true;
- continue;
- }
- else
- {
- printf("%d.%06d restarting test with ldur %d\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
- }
- }
- } while (!test_finished);
+ if (!test_finished)
+ {
+ if (++run > 3)
+ {
+ printf("%d.%06d run limit reached, test failed\n", (int32_t)(tstart / DDS_NSECS_IN_SEC), (int32_t)(tstart % DDS_NSECS_IN_SEC) / 1000);
+ CU_FAIL_FATAL("Run limit reached");
+ test_finished = true;
+ continue;
+ }
+ else
+ {
+ printf("%d.%06d restarting test with ldur %d\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000, ldur);
+ }
+ }
+ } while (!test_finished);
}
static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur, dds_entity_t *writer, dds_entity_t topic, dds_entity_t reader)
{
- dds_entity_t waitset;
- dds_qos_t *wqos;
- dds_attach_t triggered;
- uint32_t status;
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ uint32_t status;
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, kind, ldur);
- CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, kind, ldur);
+ CU_ASSERT_FATAL((*writer = dds_create_writer(g_pub_participant, topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
}
/**
@@ -399,55 +398,55 @@ static void add_and_check_writer(dds_liveliness_kind_t kind, dds_duration_t ldur
#define MAX_WRITERS 10
CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- uint32_t wr_cnt = 0;
- char name[100];
- dds_qos_t *rqos;
- uint32_t n;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ uint32_t wr_cnt = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ uint32_t n;
- /* topics */
- create_topic_name("ddsc_liveliness_ldur", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldur", 1, 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);
- /* reader and waitset */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check if pmd defaults to configured duration */
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
+ /* check if pmd defaults to configured duration */
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), get_ldur_config(g_pub_participant));
- /* create writers and check pmd interval in publishing participant */
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ /* create writers and check pmd interval in publishing participant */
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(1000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(2000), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(1000));
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(500), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
- CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(100), &writers[wr_cnt++], pub_topic, reader);
+ CU_ASSERT_EQUAL_FATAL(get_pmd_interval(g_pub_participant), DDS_MSECS(500));
- /* cleanup */
- for (n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ for (n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
@@ -456,62 +455,62 @@ CU_Test(ddsc_liveliness, lease_duration, .init = liveliness_init, .fini = liveli
* publications in the readers. */
CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- char name[100];
- dds_qos_t *rqos, *wqos;
- dds_entity_t waitset;
- dds_attach_t triggered;
- uint32_t status;
- dds_duration_t ldur;
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ char name[100];
+ dds_qos_t *rqos, *wqos;
+ dds_entity_t waitset;
+ dds_attach_t triggered;
+ uint32_t status;
+ dds_duration_t ldur;
- /* topics */
- create_topic_name("ddsc_liveliness_ldurpwr", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_ldurpwr", 1, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writer */
- ldur = 1000;
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ /* writer */
+ ldur = 1000;
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- /* wait for writer to be alive */
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* wait for writer to be alive */
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ CU_ASSERT_EQUAL_FATAL(dds_take_status(reader, &status, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* check pwr lease duration in matched publication */
- dds_instance_handle_t wrs[1];
- CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
- dds_builtintopic_endpoint_t *ep;
- ep = dds_get_matched_publication_data(reader, wrs[0]);
- CU_ASSERT_FATAL(ep != NULL);
- assert(ep != NULL); /* for Clang's static analyzer */
- CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
- dds_delete_qos(ep->qos);
- dds_free(ep->topic_name);
- dds_free(ep->type_name);
- dds_free(ep);
+ /* check pwr lease duration in matched publication */
+ dds_instance_handle_t wrs[1];
+ CU_ASSERT_EQUAL_FATAL(dds_get_matched_publications(reader, wrs, 1), 1);
+ dds_builtintopic_endpoint_t *ep;
+ ep = dds_get_matched_publication_data(reader, wrs[0]);
+ CU_ASSERT_FATAL(ep != NULL);
+ assert(ep != NULL); /* for Clang's static analyzer */
+ CU_ASSERT_EQUAL_FATAL(ep->qos->liveliness.lease_duration, DDS_MSECS(ldur));
+ dds_delete_qos(ep->qos);
+ dds_free(ep->topic_name);
+ dds_free(ep->type_name);
+ dds_free(ep);
- /* cleanup */
- dds_delete_qos(wqos);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ /* cleanup */
+ dds_delete_qos(wqos);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
}
/**
@@ -521,87 +520,91 @@ CU_Test(ddsc_liveliness, lease_duration_pwr, .init = liveliness_init, .fini = li
* is deleted immediately after creating.
*/
#define MAX_WRITERS 100
-CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 30)
+CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .fini = liveliness_fini, .timeout = 15)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writers[MAX_WRITERS];
- dds_entity_t waitset;
- dds_qos_t *wqos;
- struct dds_liveliness_changed_status lstatus;
- uint32_t alive_writers_auto = 0, alive_writers_man = 0;
- char name[100];
- dds_qos_t *rqos;
- dds_attach_t triggered;
- uint32_t n;
- Space_Type1 sample = { 0, 0, 0 };
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writers[MAX_WRITERS];
+ dds_entity_t waitset;
+ dds_qos_t *wqos;
+ struct dds_liveliness_changed_status lstatus;
+ uint32_t alive_writers_auto = 0, alive_writers_man = 0;
+ char name[100];
+ dds_qos_t *rqos;
+ dds_attach_t triggered;
+ uint32_t n;
+ Space_Type1 sample = {0, 0, 0};
+ int64_t ldur = 1000;
- /* topics */
- create_topic_name("ddsc_liveliness_wr_stress", 1, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_wr_stress", 1, 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);
- /* reader and waitset */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* reader and waitset */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* create 1st writer and wait for it to become alive */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (500));
- CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
- alive_writers_man++;
+ /* create 1st writer and wait for it to become alive */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur));
+ CU_ASSERT_FATAL((writers[0] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_MSECS(1000)), 1);
+ alive_writers_man++;
- /* create writers */
- for (n = 1; n < MAX_WRITERS; n++)
- {
- dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS (n % 3 ? 500 + n : 500 - n));
- CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_write (writers[n], &sample);
- if (n % 3 == 2)
- dds_delete(writers[n]);
- else if (n % 2)
- alive_writers_auto++;
- else
- alive_writers_man++;
- }
- dds_delete_qos(wqos);
- printf("alive_writers_auto: %d, alive_writers_man: %d\n", alive_writers_auto, alive_writers_man);
+ /* create writers */
+ for (n = 1; n < MAX_WRITERS; n++)
+ {
+ dds_qset_liveliness(wqos, n % 2 ? DDS_LIVELINESS_AUTOMATIC : DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(n % 3 ? ldur + n : ldur - n) + ((n % 3) == 2 ? 1 : 0));
+ CU_ASSERT_FATAL((writers[n] = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_write(writers[n], &sample);
+ if (n % 3 == 2)
+ dds_delete(writers[n]);
+ else if (n % 2)
+ alive_writers_auto++;
+ else
+ alive_writers_man++;
+ }
+ dds_delete_qos(wqos);
+ printf("alive_writers_auto: %d, alive_writers_man: %d\n", alive_writers_auto, alive_writers_man);
- /* wait for auto liveliness writers to become alive and manual-by-pp writers to become not-alive */
- do
- {
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
- printf("alive: %d, not-alive: %d\n", lstatus.alive_count, lstatus.not_alive_count);
- dds_sleepfor (DDS_MSECS(50));
- }
- while (lstatus.alive_count != alive_writers_auto || lstatus.not_alive_count != alive_writers_man);
+ /* wait for auto liveliness writers to become alive and manual-by-pp writers to become not-alive */
+ do
+ {
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ printf("alive: %d, not-alive: %d\n", lstatus.alive_count, lstatus.not_alive_count);
+ dds_sleepfor(DDS_MSECS(50));
+ } while (lstatus.alive_count != alive_writers_auto || lstatus.not_alive_count != alive_writers_man);
- /* cleanup remaining writers */
- for (n = 0; n < MAX_WRITERS; n++)
- {
- if (n % 3 != 2)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- }
- /* wait for alive_count and not_alive_count to become 0 */
- do
- {
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status (reader, &lstatus), DDS_RETCODE_OK);
- printf("alive: %d, not: %d\n", lstatus.alive_count, lstatus.not_alive_count);
- dds_sleepfor (DDS_MSECS(50));
- }
- while (lstatus.alive_count > 0 || lstatus.not_alive_count > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* check that counts are stable after a delay */
+ dds_sleepfor(DDS_MSECS(ldur / 2));
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL(lstatus.alive_count == alive_writers_auto && lstatus.not_alive_count == alive_writers_man);
+
+ /* cleanup remaining writers */
+ for (n = 0; n < MAX_WRITERS; n++)
+ {
+ if (n % 3 != 2)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ }
+ /* wait for alive_count and not_alive_count to become 0 */
+ do
+ {
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ printf("alive: %d, not: %d\n", lstatus.alive_count, lstatus.not_alive_count);
+ dds_sleepfor(DDS_MSECS(ldur / 10));
+ } while (lstatus.alive_count > 0 || lstatus.not_alive_count > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
#undef MAX_WRITERS
@@ -610,74 +613,74 @@ CU_Test(ddsc_liveliness, create_delete_writer_stress, .init = liveliness_init, .
*/
CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = liveliness_fini)
{
- dds_entity_t pub_topic;
- dds_entity_t sub_topic;
- dds_entity_t reader;
- dds_entity_t writer;
- dds_entity_t waitset;
- dds_qos_t *rqos;
- dds_qos_t *wqos;
- dds_attach_t triggered;
- struct dds_liveliness_changed_status lstatus;
- struct dds_subscription_matched_status sstatus;
- char name[100];
- dds_duration_t ldur = DDS_MSECS (500);
- Space_Type1 sample = { 1, 0, 0 };
+ dds_entity_t pub_topic;
+ dds_entity_t sub_topic;
+ dds_entity_t reader;
+ dds_entity_t writer;
+ dds_entity_t waitset;
+ dds_qos_t *rqos;
+ dds_qos_t *wqos;
+ dds_attach_t triggered;
+ struct dds_liveliness_changed_status lstatus;
+ struct dds_subscription_matched_status sstatus;
+ char name[100];
+ dds_duration_t ldur = DDS_MSECS(500);
+ Space_Type1 sample = {1, 0, 0};
- /* topics */
- create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_status_counts", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ CU_ASSERT_FATAL((waitset = dds_create_waitset(g_sub_participant)) > 0);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_attach(waitset, reader, reader), DDS_RETCODE_OK);
- /* writer */
- CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
- CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
- dds_delete_qos(wqos);
+ /* writer */
+ CU_ASSERT_FATAL((wqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(wqos, DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, ldur);
+ CU_ASSERT_FATAL((writer = dds_create_writer(g_pub_participant, pub_topic, wqos, NULL)) > 0);
+ dds_delete_qos(wqos);
- /* wait for writer to be alive */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* wait for writer to be alive */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- /* check status counts before proxy writer is expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
- dds_sleepfor(ldur + DDS_MSECS(100));
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* sleep for more than lease duration, writer should be set not-alive but subscription still matched */
+ dds_sleepfor(ldur + DDS_MSECS(100));
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 0);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* write sample and re-check status counts */
- dds_write (writer, &sample);
- CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
+ /* write sample and re-check status counts */
+ dds_write(writer, &sample);
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_wait(waitset, &triggered, 1, DDS_SECS(5)), 1);
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
- dds_get_subscription_matched_status(reader, &sstatus);
- CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, 1);
+ dds_get_subscription_matched_status(reader, &sstatus);
+ CU_ASSERT_EQUAL_FATAL(sstatus.current_count, 1);
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_waitset_detach(waitset, reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(waitset), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writer), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
}
/**
@@ -686,127 +689,127 @@ CU_Test(ddsc_liveliness, status_counts, .init = liveliness_init, .fini = livelin
*/
#define MAX_WRITERS 100
CU_TheoryDataPoints(ddsc_liveliness, assert_liveliness) = {
- CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
- CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
- CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
+ CU_DataPoints(uint32_t, 1, 0, 0, 1), /* number of writers with automatic liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 0, 0), /* number of writers with manual-by-participant liveliness */
+ CU_DataPoints(uint32_t, 1, 1, 1, 2), /* number of writers with manual-by-topic liveliness */
};
-CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout=60)
+CU_Theory((uint32_t wr_cnt_auto, uint32_t wr_cnt_man_pp, uint32_t wr_cnt_man_tp), ddsc_liveliness, assert_liveliness, .init = liveliness_init, .fini = liveliness_fini, .timeout = 60)
{
- dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS];
- dds_qos_t *rqos;
- struct dds_liveliness_changed_status lstatus;
- char name[100];
- uint32_t ldur = 100, wr_cnt, run = 1, stopped;
- dds_time_t tstart, tstop, t;
- bool test_finished = false;
+ dds_entity_t pub_topic, sub_topic, reader, writers[MAX_WRITERS];
+ dds_qos_t *rqos;
+ struct dds_liveliness_changed_status lstatus;
+ char name[100];
+ uint32_t ldur = 100, wr_cnt, run = 1, stopped;
+ dds_time_t tstart, tstop, t;
+ bool test_finished = false;
- do
- {
- wr_cnt = 0;
- assert (wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
- printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n",
- wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur);
+ do
+ {
+ wr_cnt = 0;
+ assert(wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp < MAX_WRITERS);
+ printf("running test assert_liveliness: auto/man-by-part/man-by-topic %u/%u/%u with ldur %d\n",
+ wr_cnt_auto, wr_cnt_man_pp, wr_cnt_man_tp, ldur);
- /* topics */
- create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
+ /* topics */
+ create_topic_name("ddsc_liveliness_assert", g_topic_nr++, 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);
- /* reader */
- CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
- dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
- CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
- dds_delete_qos(rqos);
- CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
+ /* reader */
+ CU_ASSERT_FATAL((rqos = dds_create_qos()) != NULL);
+ dds_qset_liveliness(rqos, DDS_LIVELINESS_AUTOMATIC, DDS_INFINITY);
+ CU_ASSERT_FATAL((reader = dds_create_reader(g_sub_participant, sub_topic, rqos, NULL)) > 0);
+ dds_delete_qos(rqos);
+ CU_ASSERT_EQUAL_FATAL(dds_set_status_mask(reader, DDS_LIVELINESS_CHANGED_STATUS), DDS_RETCODE_OK);
- /* writers */
- for (size_t n = 0; n < wr_cnt_auto; n++)
- add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
- tstart = dds_time();
- for (size_t n = 0; n < wr_cnt_man_pp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
- for (size_t n = 0; n < wr_cnt_man_tp; n++)
- add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
- t = dds_time();
- if (t - tstart > DDS_MSECS(0.5 * ldur))
- {
- ldur *= 10 / (run + 1);
- printf("%d.%06d failed to create writers with non-automatic liveliness kind in time\n",
- (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
- }
- else
- {
- /* check status counts before proxy writer is expired */
- dds_get_liveliness_changed_status(reader, &lstatus);
- CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
+ /* writers */
+ for (size_t n = 0; n < wr_cnt_auto; n++)
+ add_and_check_writer(DDS_LIVELINESS_AUTOMATIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ tstart = dds_time();
+ for (size_t n = 0; n < wr_cnt_man_pp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ for (size_t n = 0; n < wr_cnt_man_tp; n++)
+ add_and_check_writer(DDS_LIVELINESS_MANUAL_BY_TOPIC, DDS_MSECS(ldur), &writers[wr_cnt++], pub_topic, reader);
+ t = dds_time();
+ if (t - tstart > DDS_MSECS(0.5 * ldur))
+ {
+ ldur *= 10 / (run + 1);
+ printf("%d.%06d failed to create writers with non-automatic liveliness kind in time\n",
+ (int32_t)(t / DDS_NSECS_IN_SEC), (int32_t)(t % DDS_NSECS_IN_SEC) / 1000);
+ }
+ else
+ {
+ /* check status counts before proxy writer is expired */
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ CU_ASSERT_EQUAL_FATAL(lstatus.alive_count, wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp);
- /* delay for more than lease duration and assert liveliness on writers:
+ /* delay for more than lease duration and assert liveliness on writers:
all writers (including man-by-pp) should be kept alive */
- tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
- stopped = 0;
- do
- {
- for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
- dds_assert_liveliness (writers[n]);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
- if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0)
- {
- ldur *= 10 / (run + 1);
- printf("incorrect number of writers alive or stopped writers\n");
- }
- else
- {
- /* delay for more than lease duration and assert liveliness on participant:
+ tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
+ stopped = 0;
+ do
+ {
+ for (size_t n = wr_cnt - wr_cnt_man_tp; n < wr_cnt; n++)
+ dds_assert_liveliness(writers[n]);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor(DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive with dds_assert_liveliness on all writers: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
+ if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp + wr_cnt_man_tp || stopped != 0)
+ {
+ ldur *= 10 / (run + 1);
+ printf("incorrect number of writers alive or stopped writers\n");
+ }
+ else
+ {
+ /* delay for more than lease duration and assert liveliness on participant:
writers with liveliness man-by-pp should be kept alive, man-by-topic writers
should stop */
- tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
- stopped = 0;
- do
- {
- dds_assert_liveliness (g_pub_participant);
- CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
- stopped += (uint32_t)lstatus.not_alive_count_change;
- dds_sleepfor (DDS_MSECS(50));
- } while (dds_time() < tstop);
- dds_get_liveliness_changed_status(reader, &lstatus);
- printf("writers alive with dds_assert_liveliness on participant: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
- if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp || stopped != wr_cnt_man_tp)
- {
- ldur *= 10 / (run + 1);
- printf("incorrect number of writers alive or stopped writers\n");
- }
- else
- {
- test_finished = true;
- }
- }
- }
+ tstop = dds_time() + 4 * DDS_MSECS(ldur) / 3;
+ stopped = 0;
+ do
+ {
+ dds_assert_liveliness(g_pub_participant);
+ CU_ASSERT_EQUAL_FATAL(dds_get_liveliness_changed_status(reader, &lstatus), DDS_RETCODE_OK);
+ stopped += (uint32_t)lstatus.not_alive_count_change;
+ dds_sleepfor(DDS_MSECS(50));
+ } while (dds_time() < tstop);
+ dds_get_liveliness_changed_status(reader, &lstatus);
+ printf("writers alive with dds_assert_liveliness on participant: %d, writers stopped: %d\n", lstatus.alive_count, stopped);
+ if (lstatus.alive_count != wr_cnt_auto + wr_cnt_man_pp || stopped != wr_cnt_man_tp)
+ {
+ ldur *= 10 / (run + 1);
+ printf("incorrect number of writers alive or stopped writers\n");
+ }
+ else
+ {
+ test_finished = true;
+ }
+ }
+ }
- /* cleanup */
- CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
- for (size_t n = 0; n < wr_cnt; n++)
- CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
- CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
+ /* cleanup */
+ CU_ASSERT_EQUAL_FATAL(dds_delete(reader), DDS_RETCODE_OK);
+ for (size_t n = 0; n < wr_cnt; n++)
+ CU_ASSERT_EQUAL_FATAL(dds_delete(writers[n]), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(sub_topic), DDS_RETCODE_OK);
+ CU_ASSERT_EQUAL_FATAL(dds_delete(pub_topic), DDS_RETCODE_OK);
- if (!test_finished)
- {
- if (++run > 3)
- {
- CU_FAIL_FATAL("Run limit reached");
- test_finished = true;
- continue;
- }
- else
- {
- printf("restarting test with ldur %d\n", ldur);
- }
- }
- } while (!test_finished);
+ if (!test_finished)
+ {
+ if (++run > 3)
+ {
+ CU_FAIL_FATAL("Run limit reached");
+ test_finished = true;
+ continue;
+ }
+ else
+ {
+ printf("restarting test with ldur %d\n", ldur);
+ }
+ }
+ } while (!test_finished);
}
#undef MAX_WRITERS
diff --git a/src/core/ddsi/include/dds/ddsi/q_lease.h b/src/core/ddsi/include/dds/ddsi/q_lease.h
index d8f2964..51a00cb 100644
--- a/src/core/ddsi/include/dds/ddsi/q_lease.h
+++ b/src/core/ddsi/include/dds/ddsi/q_lease.h
@@ -42,6 +42,7 @@ void lease_management_term (struct q_globals *gv);
struct lease *lease_new (nn_etime_t texpire, int64_t tdur, struct entity_common *e);
struct lease *lease_clone (const struct lease *l);
void lease_register (struct lease *l);
+void lease_unregister (struct lease *l);
void lease_free (struct lease *l);
void lease_renew (struct lease *l, nn_etime_t tnow);
void lease_set_expiry (struct lease *l, nn_etime_t when);
diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c
index f9f13c2..0e72f6c 100644
--- a/src/core/ddsi/src/q_ddsi_discovery.c
+++ b/src/core/ddsi/src/q_ddsi_discovery.c
@@ -610,13 +610,15 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
else if (existing_entity->kind == EK_PROXY_PARTICIPANT)
{
struct proxy_participant *proxypp = (struct proxy_participant *) existing_entity;
+ struct lease *lease;
int interesting = 0;
RSTTRACE ("SPDP ST0 "PGUIDFMT" (known)", PGUID (datap->participant_guid));
/* SPDP processing is so different from normal processing that we are
even skipping the automatic lease renewal. Note that proxy writers
that are not alive are not set alive here. This is done only when
data is received from a particular pwr (in handle_regular) */
- lease_renew (ddsrt_atomic_ldvoidp (&proxypp->minl_auto), now_et ());
+ if ((lease = ddsrt_atomic_ldvoidp (&proxypp->minl_auto)) != NULL)
+ lease_renew (lease, now_et ());
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->implicitly_created || seq > proxypp->seq)
{
diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c
index b15b807..bb1430c 100644
--- a/src/core/ddsi/src/q_entity.c
+++ b/src/core/ddsi/src/q_entity.c
@@ -3662,51 +3662,67 @@ static void gc_proxy_participant_lease (struct gcreq *gcreq)
gcreq_free (gcreq);
}
-void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease)
-{
- /* Lease renewal is done by the receive thread without locking the
- proxy participant (and I'd like to keep it that way), but that
- means we must guarantee that the lease pointer remains valid once
- loaded.
-
- By loading/storing the pointer atomically, we ensure we always
- read a valid (or once valid) value, by delaying the freeing
- through the garbage collector, we ensure whatever lease update
- occurs in parallel completes before the memory is released.
-
- The lease_renew(never) call ensures the lease will never expire
- while we are messing with it. */
- ddsrt_mutex_lock (&proxypp->e.lock);
- if (proxypp->owns_lease)
- {
- const nn_etime_t never = { T_NEVER };
- struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
- struct lease *oldlease = proxypp->lease;
- lease_renew (oldlease, never);
- gcreq->arg = oldlease;
- gcreq_enqueue (gcreq);
- proxypp->owns_lease = 0;
- }
- proxypp->lease = newlease;
- /* FIXME: replace proxypp lease in leaseheap_auto? */
- ddsrt_mutex_unlock (&proxypp->e.lock);
-}
-
static void proxy_participant_replace_minl (struct proxy_participant *proxypp, bool manbypp, struct lease *lnew)
{
/* By loading/storing the pointer atomically, we ensure we always
read a valid (or once valid) lease. By delaying freeing the lease
through the garbage collector, we ensure whatever lease update
occurs in parallel completes before the memory is released. */
- const nn_etime_t never = { T_NEVER };
struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
struct lease *lease_old = ddsrt_atomic_ldvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto);
- lease_renew (lease_old, never); /* ensures lease will not expire while it is replaced */
+ lease_unregister (lease_old); /* ensures lease will not expire while it is replaced */
gcreq->arg = lease_old;
gcreq_enqueue (gcreq);
ddsrt_atomic_stvoidp (manbypp ? &proxypp->minl_man : &proxypp->minl_auto, lnew);
}
+void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct lease *newlease)
+{
+ ddsrt_mutex_lock (&proxypp->e.lock);
+ if (proxypp->owns_lease)
+ {
+ struct lease *minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
+ ddsrt_fibheap_delete (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
+ if (minl == proxypp->lease)
+ {
+ if ((minl = ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_auto)) != NULL)
+ {
+ dds_duration_t trem = minl->tdur - proxypp->lease->tdur;
+ assert (trem >= 0);
+ nn_etime_t texp = add_duration_to_etime (now_et(), trem);
+ struct lease *lnew = lease_new (texp, minl->tdur, minl->entity);
+ proxy_participant_replace_minl (proxypp, false, lnew);
+ lease_register (lnew);
+ }
+ else
+ {
+ proxy_participant_replace_minl (proxypp, false, NULL);
+ }
+ }
+
+ /* Lease renewal is done by the receive thread without locking the
+ proxy participant (and I'd like to keep it that way), but that
+ means we must guarantee that the lease pointer remains valid once
+ loaded.
+
+ By loading/storing the pointer atomically, we ensure we always
+ read a valid (or once valid) value, by delaying the freeing
+ through the garbage collector, we ensure whatever lease update
+ occurs in parallel completes before the memory is released.
+
+ The lease_unregister call ensures the lease will never expire
+ while we are messing with it. */
+ struct gcreq *gcreq = gcreq_new (proxypp->e.gv->gcreq_queue, gc_proxy_participant_lease);
+ lease_unregister (proxypp->lease);
+ gcreq->arg = proxypp->lease;
+ gcreq_enqueue (gcreq);
+ proxypp->owns_lease = 0;
+ }
+ proxypp->lease = newlease;
+
+ ddsrt_mutex_unlock (&proxypp->e.lock);
+}
+
static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * proxypp, const struct proxy_writer * pwr)
{
struct lease *minl_prev;
@@ -3764,7 +3780,6 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant
}
else
{
- assert (manbypp);
proxy_participant_replace_minl (proxypp, manbypp, NULL);
}
}
@@ -3829,10 +3844,16 @@ void new_proxy_participant
{
struct proxy_participant *privpp;
privpp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &proxypp->privileged_pp_guid);
+
+ ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
+ ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_man);
+ ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL);
+
if (privpp != NULL && privpp->is_ddsi2_pp)
{
proxypp->lease = privpp->lease;
proxypp->owns_lease = 0;
+ ddsrt_atomic_stvoidp (&proxypp->minl_auto, NULL);
}
else
{
@@ -3849,10 +3870,6 @@ void new_proxy_participant
proxypp->lease = lease_new (texp, dur, &proxypp->e);
proxypp->owns_lease = 1;
- /* Init heap for leases */
- ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_auto);
- ddsrt_fibheap_init (&lease_fhdef_proxypp, &proxypp->leaseheap_man);
-
/* Add the proxypp lease to heap so that monitoring liveliness will include this lease
and uses the shortest duration for proxypp and all its pwr's (with automatic liveliness) */
ddsrt_fibheap_insert (&lease_fhdef_proxypp, &proxypp->leaseheap_auto, proxypp->lease);
@@ -3863,7 +3880,6 @@ void new_proxy_participant
by the lease from the proxy writer in proxy_participant_add_pwr_lease_locked. This old shortest
lease is freed, so that's why we need a clone and not the proxypp's lease in the heap. */
ddsrt_atomic_stvoidp (&proxypp->minl_auto, (void *) lease_clone (proxypp->lease));
- ddsrt_atomic_stvoidp (&proxypp->minl_man, NULL);
}
}
@@ -4071,6 +4087,7 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
assert (ddsrt_fibheap_min (&lease_fhdef_proxypp, &proxypp->leaseheap_man) == NULL);
assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL);
assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid));
+ lease_unregister (minl_auto);
lease_free (minl_auto);
lease_free (proxypp->lease);
}
@@ -4556,6 +4573,7 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
GVLOGDISC ("- unknown\n");
return DDS_RETCODE_BAD_PARAMETER;
}
+
/* Set "deleting" flag in particular for Lite, to signal to the receive path it can't
trust rdary[] anymore, which is because removing the proxy writer from the hash
table will prevent the readers from looking up the proxy writer, and consequently
@@ -4565,6 +4583,9 @@ int delete_proxy_writer (struct q_globals *gv, const struct ddsi_guid *guid, nn_
builtintopic_write (gv->builtin_topic_interface, &pwr->e, timestamp, false);
ephash_remove_proxy_writer_guid (gv->guid_hash, pwr);
ddsrt_mutex_unlock (&gv->lock);
+ if (pwr->c.xqos->liveliness.lease_duration != T_NEVER &&
+ pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
+ lease_unregister (pwr->lease);
if (proxy_writer_set_notalive (pwr, false) != DDS_RETCODE_OK)
GVLOGDISC ("proxy_writer_set_notalive failed for "PGUIDFMT"\n", PGUID(*guid));
gcreq_proxy_writer (pwr);
diff --git a/src/core/ddsi/src/q_lease.c b/src/core/ddsi/src/q_lease.c
index ccd0306..12f36e8 100644
--- a/src/core/ddsi/src/q_lease.c
+++ b/src/core/ddsi/src/q_lease.c
@@ -121,10 +121,10 @@ void lease_register (struct lease *l) /* FIXME: make lease admin struct */
force_lease_check (gv->gcreq_queue);
}
-void lease_free (struct lease *l)
+void lease_unregister (struct lease *l)
{
struct q_globals * const gv = l->entity->gv;
- GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
+ GVTRACE ("lease_unregister(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
ddsrt_mutex_lock (&gv->leaseheap_lock);
if (l->tsched.v != TSCHED_NOT_ON_HEAP)
{
@@ -132,12 +132,18 @@ void lease_free (struct lease *l)
l->tsched.v = TSCHED_NOT_ON_HEAP;
}
ddsrt_mutex_unlock (&gv->leaseheap_lock);
- ddsrt_free (l);
/* see lease_register() */
force_lease_check (gv->gcreq_queue);
}
+void lease_free (struct lease *l)
+{
+ struct q_globals * const gv = l->entity->gv;
+ GVTRACE ("lease_free(l %p guid "PGUIDFMT")\n", (void *) l, PGUID (l->entity->guid));
+ ddsrt_free (l);
+}
+
void lease_renew (struct lease *l, nn_etime_t tnowE)
{
nn_etime_t tend_new = add_duration_to_etime (tnowE, l->tdur);
diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c
index b20dd06..58bb2de 100644
--- a/src/core/ddsi/src/q_receive.c
+++ b/src/core/ddsi/src/q_receive.c
@@ -617,6 +617,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
struct proxy_reader *prd;
struct wr_prd_match *rn;
struct writer *wr;
+ struct lease *lease;
ddsi_guid_t src, dst;
seqno_t seqbase;
seqno_t seq_xmit;
@@ -668,7 +669,8 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
return 1;
}
- lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer!)", PGUID (src), PGUID (dst));
@@ -1111,6 +1113,7 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
const seqno_t lastseq = fromSN (msg->lastSN);
struct handle_Heartbeat_helper_arg arg;
struct proxy_writer *pwr;
+ struct lease *lease;
ddsi_guid_t src, dst;
src.prefix = rst->src_guid_prefix;
@@ -1131,15 +1134,15 @@ static int handle_Heartbeat (struct receiver_state *rst, nn_etime_t tnow, struct
RSTTRACE (PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst));
return 1;
}
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
if (msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS &&
pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC &&
pwr->c.xqos->liveliness.lease_duration != T_NEVER)
{
- struct lease *lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man);
- if (lease != NULL)
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL)
lease_renew (lease, tnow);
lease_renew (pwr->lease, tnow);
}
@@ -1253,6 +1256,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
const nn_fragment_number_t fragnum = msg->lastFragmentNum - 1; /* we do 0-based */
ddsi_guid_t src, dst;
struct proxy_writer *pwr;
+ struct lease *lease;
src.prefix = rst->src_guid_prefix;
src.entityid = msg->writerId;
@@ -1272,7 +1276,8 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
return 1;
}
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst));
ddsrt_mutex_lock (&pwr->e.lock);
@@ -1361,6 +1366,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
struct proxy_reader *prd;
struct wr_prd_match *rn;
struct writer *wr;
+ struct lease *lease;
struct whc_borrowed_sample sample;
ddsi_guid_t src, dst;
nn_count_t *countp;
@@ -1397,7 +1403,8 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
return 1;
}
- lease_renew (ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
if (!wr->reliable) /* note: reliability can't be changed */
{
RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer)", PGUID (src), PGUID (dst));
@@ -1609,6 +1616,7 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
struct proxy_writer *pwr;
struct pwr_rd_match *wn;
+ struct lease *lease;
ddsi_guid_t src, dst;
seqno_t gapstart, listbase;
int32_t last_included_rel;
@@ -1642,7 +1650,8 @@ static int handle_Gap (struct receiver_state *rst, nn_etime_t tnow, struct nn_rm
return 1;
}
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
ddsrt_mutex_lock (&pwr->e.lock);
if ((wn = ddsrt_avl_lookup (&pwr_readers_treedef, &pwr->readers, &dst)) == NULL)
{
@@ -2119,7 +2128,8 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
so check whether it is actually in manual-by-topic mode before renewing it. As pwr->lease is
set once (during entity creation) we can read it outside the lock, keeping all the lease
renewals together. */
- lease_renew (ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto), tnow);
+ if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL)
+ lease_renew (lease, tnow);
if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_man)) != NULL && renew_manbypp_lease)
lease_renew (lease, tnow);
if (pwr->lease && pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC)
From 2724f94002b07956429a3e965d0c3b130208fda0 Mon Sep 17 00:00:00 2001
From: Wilco Bonestroo
Date: Mon, 9 Dec 2019 22:18:33 +0100
Subject: [PATCH 54/55] Refer to roundtrip example
Text refers to roundtrip example and code to helloworld.
Signed-off-by: Wilco Bonestroo
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2c80530..c0c5def 100644
--- a/README.md
+++ b/README.md
@@ -126,7 +126,7 @@ to run the program, it is merely to illustrate the process.
$ mkdir roundtrip
$ cd roundtrip
- $ cmake /share/CycloneDDS/examples/helloworld
+ $ cmake /share/CycloneDDS/examples/roundtrip
$ cmake --build .
On one terminal start the application that will be responding to pings:
From fc8d84451921a8cf74b16378ad09cc20e6e9bf6b Mon Sep 17 00:00:00 2001
From: TheFixer
Date: Thu, 12 Dec 2019 14:11:05 +0100
Subject: [PATCH 55/55] Add missing documentation for dds_takecdr() (#357)
* Add missing documentation for dds_takecdr()
Signed-off-by: TheFixer
* Updated documentation for dds_takecdr() and added documentation for dds_writecdr()
Signed-off-by: TheFixer
---
src/core/ddsc/include/dds/dds.h | 58 +++++++++++++++++++++++++++++++--
1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h
index 23b81b2..85d015f 100644
--- a/src/core/ddsc/include/dds/dds.h
+++ b/src/core/ddsc/include/dds/dds.h
@@ -1712,12 +1712,28 @@ DDS_EXPORT void
dds_write_flush(dds_entity_t writer);
/**
- * @brief Write a CDR serialized value of a data instance
+ * @brief Write a serialized value of a data instance
+ *
+ * This call causes the writer to write the serialized value that is provided
+ * in the serdata argument.
*
* @param[in] writer The writer entity.
- * @param[in] serdata CDR serialized value to be written.
+ * @param[in] serdata Serialized value to be written.
*
* @returns A dds_return_t indicating success or failure.
+ *
+ * @retval DDS_RETCODE_OK
+ * The writer successfully wrote the serialized value.
+ * @retval DDS_RETCODE_ERROR
+ * An internal error has occurred.
+ * @retval DDS_RETCODE_BAD_PARAMETER
+ * One of the given arguments is not valid.
+ * @retval DDS_RETCODE_ILLEGAL_OPERATION
+ * The operation is invoked on an inappropriate object.
+ * @retval DDS_RETCODE_ALREADY_DELETED
+ * The entity has already been deleted.
+ * @retval DDS_RETCODE_TIMEOUT
+ * The writer failed to write the serialized value reliably within the specified max_blocking_time.
*/
DDS_EXPORT dds_return_t
dds_writecdr(dds_entity_t writer, struct ddsi_serdata *serdata);
@@ -2668,6 +2684,44 @@ dds_take_mask_wl(
uint32_t maxs,
uint32_t mask);
+/**
+ * @brief Access the collection of serialized data values (of same type) and
+ * sample info from the data reader, readcondition or querycondition.
+ *
+ * This call accesses the serialized data from the data reader, readcondition or
+ * querycondition and makes it available to the application. The serialized data
+ * is made available through \ref ddsi_serdata structures. Once read the data is
+ * removed from the reader and cannot be 'read' or 'taken' again.
+ *
+ * Return value provides information about the number of samples read, which will
+ * be <= maxs. Based on the count, the buffer will contain serialized data to be
+ * read only when valid_data bit in sample info structure is set.
+ * The buffer required for data values, could be allocated explicitly or can
+ * use the memory from data reader to prevent copy. In the latter case, buffer and
+ * sample_info should be returned back, once it is no longer using the data.
+ *
+ * @param[in] reader_or_condition Reader, readcondition or querycondition entity.
+ * @param[out] buf An array of pointers to \ref ddsi_serdata structures that contain
+ * the serialized data. The pointers can be NULL.
+ * @param[in] maxs Maximum number of samples to read.
+ * @param[out] si Pointer to an array of \ref dds_sample_info_t returned for each data value.
+ * @param[in] mask Filter the data based on dds_sample_state_t|dds_view_state_t|dds_instance_state_t.
+ *
+ * @returns A dds_return_t with the number of samples read or an error code.
+ *
+ * @retval >=0
+ * Number of samples read.
+ * @retval DDS_RETCODE_ERROR
+ * An internal error has occurred.
+ * @retval DDS_RETCODE_BAD_PARAMETER
+ * One of the given arguments is not valid.
+ * @retval DDS_RETCODE_ILLEGAL_OPERATION
+ * The operation is invoked on an inappropriate object.
+ * @retval DDS_RETCODE_ALREADY_DELETED
+ * The entity has already been deleted.
+ * @retval DDS_RETCODE_PRECONDITION_NOT_MET
+ * The precondition for this operation is not met.
+ */
DDS_EXPORT dds_return_t
dds_takecdr(
dds_entity_t reader_or_condition,