Merge pull request #261 from martinbremmer/merge

Merge master into security
This commit is contained in:
eboasson 2019-09-27 15:16:50 +02:00 committed by GitHub
commit 992d2b6e55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
128 changed files with 6936 additions and 2075 deletions

View file

@ -68,9 +68,9 @@ linux_clang: &linux_clang
install:
- pip install conan --upgrade --user
osx_xcode10_2: &osx_xcode10_2
osx_xcode10_3: &osx_xcode10_3
os: osx
osx_image: xcode10.2
osx_image: xcode10.3
compiler: clang
addons:
homebrew:
@ -147,9 +147,9 @@ jobs:
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *linux_clang
env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode10_2
- <<: *osx_xcode10_3
env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, GENERATOR="Unix Makefiles" ]
- <<: *osx_xcode10_2
- <<: *osx_xcode10_3
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" ]
@ -162,6 +162,22 @@ before_script:
- conan profile new default --detect
- conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan
# Notes on test settings:
# - CYCLONEDDS_URI:
# - EnableExpensiveChecks: for the few horrendously expensive (but pretty thorough)
# integrity checks, in particular on the WHC and the RHC, but there may be more
# - config to stderr: gives the configuration used when running the test in conjunction
# with "--output-on-failure" (sadly that still doesn't output the failed
# assertions ...)
# - -j 4: run 4 tests in parallel, this saves quite a bit of time because the VMs are
# all dual-core
# - --output-on-failed: print whatever output the test generated when it failed, which
# can obviously be quite helpful for debugging
# - -E ...: regex of tests to exclude:
# CUnit_ddsrt_random_default_random: performs a Chi-square test on the output of
# the random generator, but this does produce the odd failure (it should!). The
# 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:
- mkdir build
- cd build
@ -184,7 +200,7 @@ script:
${SCAN_BUILD} cmake --build . --config ${BUILD_TYPE} --target install
;;
esac
- CYCLONEDDS_URI='<CycloneDDS><Domain><Internal><EnableExpensiveChecks>all</EnableExpensiveChecks></Internal><Tracing><Verbosity>config</Verbosity><OutputFile>stderr</OutputFile></Tracing></Domain></CycloneDDS>' ctest -j 4 --output-on-failure -T test -C ${BUILD_TYPE}
- CYCLONEDDS_URI='<CycloneDDS><Domain><Internal><EnableExpensiveChecks>all</EnableExpensiveChecks></Internal><Tracing><Verbosity>config</Verbosity><OutputFile>stderr</OutputFile></Tracing></Domain></CycloneDDS>' ctest -j 4 --output-on-failure -T test -E '^CUnit_ddsrt_random_default_random$' -C ${BUILD_TYPE}
- if [ "${ASAN}" != "none" ]; then
CMAKE_LINKER_FLAGS="-DCMAKE_LINKER_FLAGS=-fsanitize=${USE_SANITIZER}";
CMAKE_C_FLAGS="-DCMAKE_C_FLAGS=-fsanitize=${USE_SANITIZER}";

View file

@ -32,7 +32,7 @@ The Java-based components are the preprocessor and a configurator tool. The run
pure C code, so there is no need to have Java available on "target" machines. If desired, it is
possible to do a build without Java or Maven installed by defining ``BUILD_IDLC=NO`` and
``BUILD_CONFTOOL=NO``, but that effectively only gets you the core library. For the
current [ROS2 RMW layer](https://github.com/atolab/rmw_cyclonedds), that is sufficient.
current [ROS2 RMW layer](https://github.com/ros2/rmw_cyclonedds), that is sufficient.
To obtain Eclipse Cyclone DDS, do

View file

@ -47,4 +47,4 @@ build_script:
test_script:
- set "CYCLONEDDS_URI=<CycloneDDS><Domain><Internal><EnableExpensiveChecks>all</EnableExpensiveChecks></Internal><Tracing><Verbosity>config</Verbosity><OutputFile>stderr</OutputFile></Tracing></Domain></CycloneDDS>"
- ctest --output-on-failure --parallel 4 --test-action test --build-config %CONFIGURATION%
- ctest --output-on-failure --parallel 4 --exclude-regex "^CUnit_ddsrt_random_default_random$" --test-action test --build-config %CONFIGURATION%

View file

@ -1,3 +0,0 @@
{
"name": "cyclonedds"
}

View file

@ -1,6 +1,6 @@
[requires]
cunit/2.1-3@bincrafters/stable
OpenSSL/1.1.1a@conan/stable
OpenSSL/1.1.1c@conan/stable
[generators]
cmake

25
package.xml Normal file
View file

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>cyclonedds</name>
<version>0.1.0</version>
<description>Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation. Cyclone DDS is developed completely in the open as an Eclipse IoT project.</description>
<maintainer email="cyclonedds-dev@eclipse.org">Eclipse Foundation, Inc.</maintainer>
<license>Eclipse Public License 2.0</license>
<url type="website">https://projects.eclipse.org/projects/iot.cyclonedds</url>
<url type="bugtracker">https://github.com/eclipse-cyclonedds/cyclonedds/issues</url>
<url type="repository">https://github.com/eclipse-cyclonedds/cyclonedds</url>
<buildtool_depend>cmake</buildtool_depend>
<buildtool_depend>java</buildtool_depend>
<buildtool_depend>maven</buildtool_depend>
<depend>openssl</depend>
<test_depend>libcunit-dev</test_depend>
<doc_depend>python3-sphinx</doc_depend>
<export>
<build_type>cmake</build_type>
</export>
</package>

View file

@ -50,6 +50,7 @@ PREPEND(hdrs_public_ddsc "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/dd
ddsc/dds_public_qos.h
ddsc/dds_public_qosdefs.h
ddsc/dds_public_status.h
ddsc/dds_rhc.h
)
PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
@ -67,7 +68,6 @@ PREPEND(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src"
dds__readcond.h
dds__guardcond.h
dds__reader.h
dds__rhc.h
dds__rhc_default.h
dds__stream.h
dds__subscriber.h

View file

@ -49,19 +49,9 @@ typedef int32_t dds_entity_t;
extern "C" {
#endif
struct dds_rhc;
struct ddsi_serdata;
/**
* @brief Returns the default domain identifier.
*
* The default domain identifier can be configured in the configuration file
* or be set through an evironment variable ({DDSC_PROJECT_NAME_NOSPACE_CAPS}_DOMAIN).
*
* @returns Default domain identifier
*/
DDS_EXPORT dds_domainid_t dds_domain_default (void);
#define DDS_MIN_PSEUDO_HANDLE ((dds_entity_t) 0x7fff0000)
/* @defgroup builtintopic_constants Convenience constants for referring to builtin topics
@ -77,6 +67,9 @@ DDS_EXPORT dds_domainid_t dds_domain_default (void);
#define DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 4))
/** @}*/
/** Special handle representing the entity corresponding to the CycloneDDS library itself */
#define DDS_CYCLONEDDS_HANDLE ((dds_entity_t) (DDS_MIN_PSEUDO_HANDLE + 256))
/** @name Communication Status definitions
@{**/
typedef enum dds_status_id {
@ -733,7 +726,7 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener);
* If no configuration file exists, the default domain is configured as 0.
*
*
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). Valid values for domain id are between 0 and 230. DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
* @param[in] qos The QoS to set on the new participant (can be NULL).
* @param[in] listener Any listener functions associated with the new participant (can be NULL).
@ -750,6 +743,33 @@ dds_create_participant(
const dds_qos_t *qos,
const dds_listener_t *listener);
/**
* @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.
*
*
* @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
*
* @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
* The domain already existed and cannot be created again.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
*/
DDS_EXPORT dds_return_t
dds_create_domain(const dds_domainid_t domain, const char *config);
/**
* @brief Get entity parent.
*
@ -871,7 +891,8 @@ dds_get_children(dds_entity_t entity, dds_entity_t *children, size_t size);
* DataReaders), etc are also attached to that domain.
*
* This function will return the original domain ID when called on
* any of the entities within that hierarchy.
* any of the entities within that hierarchy. For entities not associated
* with a domain, the id is set to DDS_DOMAIN_DEFAULT.
*
* @param[in] entity Entity from which to get its children.
* @param[out] id Pointer to put the domain ID in.
@ -1202,6 +1223,34 @@ dds_create_reader(
const dds_qos_t *qos,
const dds_listener_t *listener);
/**
* @brief Creates a new instance of a DDS reader with a custom history cache.
*
* This implicit subscriber will be deleted automatically when the created reader
* is deleted.
*
* @param[in] participant_or_subscriber The participant or subscriber on which the reader is being created.
* @param[in] topic The topic to read.
* @param[in] qos The QoS to set on the new reader (can be NULL).
* @param[in] listener Any listener functions associated with the new reader (can be NULL).
* @param[in] rhc Reader history cache to use, reader becomes the owner
*
* @returns A valid reader handle or an error code.
*
* @retval >0
* A valid reader handle.
* @retval DDS_RETCODE_ERROR
* An internal error occurred.
*/
/* TODO: Complete list of error codes */
DDS_EXPORT dds_entity_t
dds_create_reader_rhc(
dds_entity_t participant_or_subscriber,
dds_entity_t topic,
const dds_qos_t *qos,
const dds_listener_t *listener,
struct dds_rhc *rhc);
/**
* @brief Wait until reader receives all historic data
*

View file

@ -108,7 +108,9 @@ typedef enum dds_entity_kind
DDS_KIND_COND_READ,
DDS_KIND_COND_QUERY,
DDS_KIND_COND_GUARD,
DDS_KIND_WAITSET
DDS_KIND_WAITSET,
DDS_KIND_DOMAIN,
DDS_KIND_CYCLONEDDS
} dds_entity_kind_t;
/* Handles are opaque pointers to implementation types */

View file

@ -13,8 +13,7 @@
#define _DDS_RHC_H_
#include "dds/ddsrt/static_assert.h"
#include "dds/ddsi/q_rhc.h"
#include "dds__types.h" /* for dds_readcond */
#include "dds/ddsi/ddsi_rhc.h"
#define NO_STATE_MASK_SET (DDS_ANY_STATE + 1)
@ -23,42 +22,50 @@ extern "C" {
#endif
struct dds_rhc;
struct dds_readcond;
struct dds_reader;
struct ddsi_tkmap;
typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_readcond *cond);
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_readcond *cond);
typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond);
typedef uint32_t (*dds_rhc_lock_samples_t) (struct dds_rhc *rhc);
struct dds_rhc_ops {
/* A copy of DDSI rhc ops comes first so we can use either interface without
additional indirections */
struct rhc_ops rhc_ops;
struct ddsi_rhc_ops rhc_ops;
dds_rhc_read_t read;
dds_rhc_take_t take;
dds_rhc_takecdr_t takecdr;
dds_rhc_add_readcondition_t add_readcondition;
dds_rhc_remove_readcondition_t remove_readcondition;
dds_rhc_lock_samples_t lock_samples;
dds_rhc_associate_t associate;
};
struct dds_rhc {
union {
const struct dds_rhc_ops *ops;
struct rhc rhc;
struct ddsi_rhc rhc;
} common;
};
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct rhc, ops));
DDSRT_STATIC_ASSERT (offsetof (struct dds_rhc, common.ops) == offsetof (struct ddsi_rhc, ops));
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, pwr_info, sample, tk);
DDS_EXPORT inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap) {
return rhc->common.ops->associate (rhc, reader, topic, tkmap);
}
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, pwr_info);
DDS_EXPORT inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return rhc->common.ops->rhc_ops.store (&rhc->common.rhc, wrinfo, sample, tk);
}
DDS_EXPORT inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
rhc->common.ops->rhc_ops.unregister_wr (&rhc->common.rhc, wrinfo);
}
DDS_EXPORT inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid) {
rhc->common.ops->rhc_ops.relinquish_ownership (&rhc->common.rhc, wr_iid);
@ -78,16 +85,18 @@ DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **value
DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
}
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_readcond *cond) {
return cond->m_rhc->common.ops->add_readcondition (cond);
DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
return rhc->common.ops->add_readcondition (rhc, cond);
}
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_readcond *cond) {
cond->m_rhc->common.ops->remove_readcondition (cond);
DDS_EXPORT inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) {
rhc->common.ops->remove_readcondition (rhc, cond);
}
DDS_EXPORT inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc) {
return rhc->common.ops->lock_samples (rhc);
}
DDS_EXPORT void dds_reader_data_available_cb (struct dds_reader *rd);
#if defined (__cplusplus)
}
#endif

View file

@ -18,8 +18,7 @@
extern "C" {
#endif
DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id);
DDS_EXPORT void dds_domain_free (dds_domain *domain);
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_domain *dds_domain_find_locked (dds_domainid_t id);
#if defined (__cplusplus)

View file

@ -28,6 +28,8 @@ dds_entity_init(
const dds_listener_t *listener,
status_mask_t mask);
DDS_EXPORT void dds_entity_init_complete (dds_entity *entity);
DDS_EXPORT void
dds_entity_register_child (
dds_entity *parent,
@ -46,7 +48,6 @@ dds_entity_add_ref_locked(dds_entity *e);
*x = (type_ *) e; \
return DDS_RETCODE_OK; \
} \
\
qualifier_ void type_##_unlock (type_ *x) \
{ \
dds_entity_unlock (&x->m_entity); \
@ -78,6 +79,18 @@ DDS_EXPORT void dds_entity_status_signal (dds_entity *e, uint32_t status);
DDS_EXPORT void dds_entity_invoke_listener (const dds_entity *entity, enum dds_status_id which, const void *vst);
DDS_EXPORT dds_participant *dds_entity_participant (dds_entity *e);
DDS_EXPORT void dds_entity_final_deinit_before_free (dds_entity *e);
DDS_EXPORT bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root);
enum delete_impl_state {
DIS_EXPLICIT, /* explicit delete on this entity */
DIS_FROM_PARENT, /* called because the parent is being deleted */
DIS_IMPLICIT /* called from child; delete if implicit w/o children */
};
DDS_EXPORT dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate);
DDS_EXPORT dds_return_t
dds_entity_pin (
dds_entity_t hdl,
@ -98,23 +111,16 @@ dds_entity_unlock(dds_entity *e);
DDS_EXPORT dds_return_t
dds_entity_observer_register(
dds_entity *observed,
dds_entity *observer,
dds_entity_callback cb,
dds_entity_delete_callback delete_cb);
dds_waitset *observer,
dds_entity_callback_t cb,
dds_entity_attach_callback_t attach_cb, void *attach_arg,
dds_entity_delete_callback_t delete_cb);
DDS_EXPORT dds_return_t
dds_entity_observer_unregister(
dds_entity *observed,
dds_entity *observer);
DDS_EXPORT dds_return_t
dds_delete_impl(
dds_entity_t entity,
bool keep_if_explicit);
DDS_EXPORT dds_domain *
dds__entity_domain(
dds_entity* e);
dds_waitset *observer,
bool invoke_delete_cb);
DDS_EXPORT dds_return_t
dds_generic_unimplemented_operation_manykinds(

View file

@ -69,6 +69,13 @@ typedef int32_t dds_handle_t;
* This handlelink is invalid after the related handle is deleted and should
* never be used afterwards.
*/
/* 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)
struct dds_handle_link {
dds_handle_t hdl;
ddsrt_atomic_uint32_t cnt_flags;
@ -112,6 +119,15 @@ dds_handle_create(
struct dds_handle_link *link);
/*
* Register a specific handle.
*/
DDS_EXPORT dds_return_t
dds_handle_register_special (
struct dds_handle_link *link, dds_handle_t handle);
DDS_EXPORT void dds_handle_unpend (struct dds_handle_link *link);
/*
* This will close the handle. All information remains, only new claims will
* fail.
@ -119,10 +135,9 @@ dds_handle_create(
* This is a noop on an already closed handle.
*/
DDS_EXPORT void
dds_handle_close(
dds_handle_close_wait (
struct dds_handle_link *link);
/*
* This will remove the handle related information from the server administration
* to free up space.
@ -134,8 +149,7 @@ dds_handle_close(
*/
DDS_EXPORT int32_t
dds_handle_delete(
struct dds_handle_link *link,
dds_time_t timeout);
struct dds_handle_link *link);
/*
@ -149,6 +163,11 @@ dds_handle_pin(
dds_handle_t hdl,
struct dds_handle_link **entity);
DDS_EXPORT int32_t
dds_handle_pin_and_ref(
dds_handle_t hdl,
struct dds_handle_link **entity);
DDS_EXPORT void
dds_handle_repin(
@ -172,14 +191,15 @@ dds_handle_unpin(
* break of your process and release the handle, making the deletion
* possible.
*/
DDS_EXPORT bool
dds_handle_is_closed(
struct dds_handle_link *link);
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 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;
}
#if defined (__cplusplus)
}
#endif

View file

@ -19,27 +19,15 @@ extern "C" {
#endif
/**
*Description : Initialization function, called from main. This operation
*initializes all the required DDS resources,
*handles configuration of domainid based on the input passed, parses and
*configures middleware from a xml file and initializes required resources.
*Description : Initializes the library and constructs the global
*pseudo-entity identified by DDS_CYCLONEDDS_HANDLE with one reference
*that must (eventually) be released by calling dds_delete on that handle.
*
*Arguments :
*-# Returns 0 on success or a non-zero error status
**/
dds_return_t dds_init (void);
/* Finalization function, called from main */
/**
*Description : Finalization function, called from main. This operation
*releases all the resources used by DDS.
*
*Arguments :
*-# None
**/
void dds_fini (void);
#if defined (__cplusplus)
}
#endif

View file

@ -23,8 +23,6 @@ struct status_cb_data;
void dds_reader_status_cb (void *entity, const struct status_cb_data * data);
void dds_reader_data_available_cb (struct dds_reader *entity);
/*
dds_reader_lock_samples: Returns number of samples in read cache and locks the
reader cache to make sure that the samples content doesn't change.

View file

@ -22,7 +22,7 @@ extern "C" {
struct ddsi_serdata_builtintopic {
struct ddsi_serdata c;
nn_guid_t key;
ddsi_guid_t key;
dds_instance_handle_t pphandle;
dds_qos_t xqos;
};

View file

@ -60,6 +60,10 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
void dds_stream_read_key (dds_istream_t * __restrict is, char * __restrict sample, const struct ddsi_sertopic_default * __restrict topic);
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
size_t dds_stream_print_sample (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t size);
/* For marshalling op code handling */
#define DDS_OP_MASK 0xff000000

View file

@ -39,7 +39,7 @@ struct dds_guardcond;
struct dds_statuscond;
struct ddsi_sertopic;
struct rhc;
struct ddsi_rhc;
typedef uint16_t status_mask_t;
typedef ddsrt_atomic_uint32_t status_and_enabled_t;
@ -90,47 +90,32 @@ struct dds_listener {
/* Entity flag values */
#define DDS_ENTITY_ENABLED 0x0001u
#define DDS_ENTITY_IMPLICIT 0x0002u
typedef struct dds_domain {
/* FIXME: protected by dds_global.lock -- for now */
ddsrt_avl_node_t m_node;
dds_domainid_t m_id;
ddsrt_avl_tree_t m_topics;
ddsrt_avl_tree_t m_ppants;
uint32_t m_refc;
struct cfgst *cfgst;
struct ddsi_sertopic *builtin_participant_topic;
struct ddsi_sertopic *builtin_reader_topic;
struct ddsi_sertopic *builtin_writer_topic;
struct local_orphan_writer *builtintopic_writer_participant;
struct local_orphan_writer *builtintopic_writer_publications;
struct local_orphan_writer *builtintopic_writer_subscriptions;
struct ddsi_builtin_topic_interface btif;
struct q_globals gv;
} dds_domain;
#define DDS_ENTITY_ENABLED ((uint32_t) 0x1) /* DDS "enabled" state */
#define DDS_ENTITY_IMPLICIT ((uint32_t) 0x2) /* implicit ones get deleted when the last child is deleted */
struct dds_domain;
struct dds_entity;
typedef struct dds_entity_deriver {
/* Close can be used to terminate (blocking) actions on a entity before actually deleting it. */
dds_return_t (*close)(struct dds_entity *e) ddsrt_nonnull_all;
/* Pending close can be used to terminate (blocking) actions on a entity before actually deleting it. */
void (*interrupt) (struct dds_entity *e) ddsrt_nonnull_all;
/* Close can be used to do ... */
void (*close) (struct dds_entity *e) ddsrt_nonnull_all;
/* Delete is used to actually free the entity. */
dds_return_t (*delete) (struct dds_entity *e) ddsrt_nonnull_all;
dds_return_t (*set_qos) (struct dds_entity *e, const dds_qos_t *qos, bool enabled) ddsrt_nonnull_all;
dds_return_t (*validate_status) (uint32_t mask);
} dds_entity_deriver;
typedef void (*dds_entity_callback)(struct dds_entity *observer, dds_entity_t observed, uint32_t status);
typedef void (*dds_entity_delete_callback)(struct dds_entity *observer, dds_entity_t observed);
struct dds_waitset;
typedef void (*dds_entity_callback_t) (struct dds_waitset *observer, dds_entity_t observed, uint32_t status);
typedef bool (*dds_entity_attach_callback_t) (struct dds_waitset *observer, struct dds_entity *observed, void *attach_arg);
typedef void (*dds_entity_delete_callback_t) (struct dds_waitset *observer, dds_entity_t observed);
typedef struct dds_entity_observer {
dds_entity_callback m_cb;
dds_entity_delete_callback m_delete_cb;
struct dds_entity *m_observer;
dds_entity_callback_t m_cb;
dds_entity_delete_callback_t m_delete_cb;
struct dds_waitset *m_observer;
struct dds_entity_observer *m_next;
} dds_entity_observer;
@ -141,10 +126,9 @@ typedef struct dds_entity {
struct dds_entity *m_parent; /* constant */
ddsrt_avl_node_t m_avlnode_child; /* [m_mutex of m_parent] */
ddsrt_avl_tree_t m_children; /* [m_mutex] tree on m_iid using m_avlnode_child */
struct dds_entity *m_participant; /* constant */
struct dds_domain *m_domain; /* constant */
dds_qos_t *m_qos; /* [m_mutex] */
nn_guid_t m_guid; /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
ddsi_guid_t m_guid; /* unique (if not 0) and constant; FIXME: set during creation, but possibly after becoming visible */
dds_instance_handle_t m_iid; /* unique for all time, constant; FIXME: like GUID */
uint32_t m_flags; /* [m_mutex] */
@ -154,6 +138,7 @@ typedef struct dds_entity {
(no hierarchical relationship there)
- locking topic::m_mutex while holding {reader,writer}::m_mutex
- locking observers_lock while holding m_mutex
- locking waitset::wait_lock
*/
ddsrt_mutex_t m_mutex;
ddsrt_cond_t m_cond;
@ -167,6 +152,7 @@ typedef struct dds_entity {
ddsrt_cond_t m_observers_cond;
dds_listener_t m_listener; /* [m_observers_lock] */
uint32_t m_cb_count; /* [m_observers_lock] */
uint32_t m_cb_pending_count; /* [m_observers_lock] */
dds_entity_observer *m_observers; /* [m_observers_lock] */
} dds_entity;
@ -182,16 +168,21 @@ extern const struct dds_entity_deriver dds_entity_deriver_publisher;
extern const struct dds_entity_deriver dds_entity_deriver_readcondition;
extern const struct dds_entity_deriver dds_entity_deriver_guardcondition;
extern const struct dds_entity_deriver dds_entity_deriver_waitset;
extern const struct dds_entity_deriver dds_entity_deriver_domain;
extern const struct dds_entity_deriver dds_entity_deriver_cyclonedds;
extern const struct dds_entity_deriver *dds_entity_deriver_table[];
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e);
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e);
void dds_entity_deriver_dummy_close (struct dds_entity *e);
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e);
dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask);
inline dds_return_t dds_entity_deriver_close (struct dds_entity *e) {
return (dds_entity_deriver_table[e->m_kind]->close) (e);
inline void dds_entity_deriver_interrupt (struct dds_entity *e) {
(dds_entity_deriver_table[e->m_kind]->interrupt) (e);
}
inline void dds_entity_deriver_close (struct dds_entity *e) {
(dds_entity_deriver_table[e->m_kind]->close) (e);
}
inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e) {
return dds_entity_deriver_table[e->m_kind]->delete (e);
@ -209,6 +200,36 @@ inline bool dds_entity_supports_validate_status (struct dds_entity *e) {
return dds_entity_deriver_table[e->m_kind]->validate_status != dds_entity_deriver_dummy_validate_status;
}
typedef struct dds_cyclonedds_entity {
struct dds_entity m_entity;
ddsrt_mutex_t m_mutex;
ddsrt_cond_t m_cond;
ddsrt_avl_tree_t m_domains;
uint32_t threadmon_count;
struct ddsi_threadmon *threadmon;
} dds_cyclonedds_entity;
typedef struct dds_domain {
struct dds_entity m_entity;
ddsrt_avl_node_t m_node; /* for dds_global.m_domains */
dds_domainid_t m_id;
ddsrt_avl_tree_t m_topics;
struct cfgst *cfgst;
struct ddsi_sertopic *builtin_participant_topic;
struct ddsi_sertopic *builtin_reader_topic;
struct ddsi_sertopic *builtin_writer_topic;
struct local_orphan_writer *builtintopic_writer_participant;
struct local_orphan_writer *builtintopic_writer_publications;
struct local_orphan_writer *builtintopic_writer_subscriptions;
struct ddsi_builtin_topic_interface btif;
struct q_globals gv;
} dds_domain;
typedef struct dds_subscriber {
struct dds_entity m_entity;
} dds_subscriber;
@ -279,12 +300,10 @@ typedef uint32_t dds_querycond_mask_t;
typedef struct dds_readcond {
dds_entity m_entity;
struct dds_rhc *m_rhc;
uint32_t m_qminv;
uint32_t m_sample_states;
uint32_t m_view_states;
uint32_t m_instance_states;
nn_guid_t m_rd_guid;
struct dds_readcond *m_next;
struct {
dds_querycondition_filter_fn m_filter;
@ -304,22 +323,18 @@ typedef struct dds_attachment {
typedef struct dds_waitset {
dds_entity m_entity;
size_t nentities; /* [m_entity.m_mutex] */
size_t ntriggered; /* [m_entity.m_mutex] */
dds_attachment *entities; /* [m_entity.m_mutex] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
/* Need a lock other than m_entity.m_mutex because the locking order an entity lock may not be
acquired while holding an ancestor's lock, but a waitset must be capable of triggering on
events on its parent */
ddsrt_mutex_t wait_lock;
ddsrt_cond_t wait_cond;
size_t nentities; /* [wait_lock] */
size_t ntriggered; /* [wait_lock] */
dds_attachment *entities; /* [wait_lock] 0 .. ntriggered are triggred, ntriggred .. nentities are not */
} dds_waitset;
/* Globals */
typedef struct dds_globals {
int32_t m_init_count;
ddsrt_avl_tree_t m_domains;
ddsrt_mutex_t m_mutex;
uint32_t threadmon_count;
struct ddsi_threadmon *threadmon;
} dds_globals;
DDS_EXPORT extern dds_globals dds_global;
DDS_EXPORT extern dds_cyclonedds_entity dds_global;
#if defined (__cplusplus)
}

View file

@ -22,6 +22,7 @@
#include "dds__participant.h"
#include "dds__types.h"
#include "dds__builtin.h"
#include "dds__entity.h"
#include "dds__subscriber.h"
#include "dds__write.h"
#include "dds__writer.h"
@ -46,9 +47,15 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
dds_entity_t tp;
dds_return_t rc;
dds_entity *e;
dds_participant *par;
if ((rc = dds_entity_pin (entity, &e)) < 0)
return rc;
if ((par = dds_entity_participant (e)) == NULL)
{
dds_entity_unpin (e);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
struct ddsi_sertopic *sertopic;
switch (topic)
@ -69,7 +76,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic)
}
dds_qos_t *qos = dds__create_builtin_qos ();
tp = dds_create_topic_arbitrary (e->m_participant->m_hdllink.hdl, sertopic, qos, NULL, NULL);
tp = dds_create_topic_arbitrary (par->m_entity.m_hdllink.hdl, sertopic, qos, NULL, NULL);
dds_delete_qos (qos);
dds_entity_unpin (e);
return tp;
@ -155,7 +162,7 @@ static bool dds__builtin_is_builtintopic (const struct ddsi_sertopic *tp, void *
return tp->ops == &ddsi_sertopic_ops_builtintopic;
}
static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
static bool dds__builtin_is_visible (const ddsi_guid_t *guid, nn_vendorid_t vendorid, void *vdomain)
{
(void) vdomain;
if (is_builtin_endpoint (guid->entityid, vendorid))
@ -163,7 +170,7 @@ static bool dds__builtin_is_visible (const nn_guid_t *guid, nn_vendorid_t vendor
return true;
}
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct nn_guid *guid, void *vdomain)
static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct ddsi_guid *guid, void *vdomain)
{
struct dds_domain *domain = vdomain;
struct ddsi_tkmap_instance *tk;

View file

@ -11,14 +11,14 @@
*/
#include <string.h>
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__domain.h"
#include "dds__builtin.h"
#include "dds__whc_builtintopic.h"
#include "dds__entity.h"
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_serdata.h"
@ -27,7 +27,16 @@
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_gc.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
static dds_return_t dds_domain_free (dds_entity *vdomain);
const struct dds_entity_deriver dds_entity_deriver_domain = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_domain_free,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
static int dds_domain_compare (const void *va, const void *vb)
{
@ -39,14 +48,20 @@ 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)
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
{
dds_return_t ret = DDS_RETCODE_OK;
char * uri = NULL;
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;
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 ();
domain->m_refc = 1;
ddsrt_avl_init (&dds_topictree_def, &domain->m_topics);
/* | domain_id | domain id in config | result
@ -72,8 +87,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
a value (if nothing has been set previously, it a warning is good
enough) */
(void) ddsrt_getenv ("CYCLONEDDS_URI", &uri);
domain->cfgst = config_init (uri, &domain->gv.config, domain_id);
domain->cfgst = config_init (config, &domain->gv.config, domain_id);
if (domain->cfgst == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri);
@ -152,9 +166,9 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
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;
rtps_stop (&domain->gv);
fail_rtps_start:
if (domain->gv.config.liveliness_monitoring && dds_global.threadmon_count == 1)
ddsi_threadmon_stop (dds_global.threadmon);
@ -170,43 +184,23 @@ fail_rtps_init:
fail_rtps_config:
config_fini (domain->cfgst);
fail_config:
dds_handle_delete (&domain->m_entity.m_hdllink);
return ret;
}
static void dds_domain_fini (struct dds_domain *domain)
{
rtps_stop (&domain->gv);
dds__builtin_fini (domain);
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
rtps_fini (&domain->gv);
ddsrt_mutex_lock (&dds_global.m_mutex);
if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
{
ddsi_threadmon_stop (dds_global.threadmon);
ddsi_threadmon_free (dds_global.threadmon);
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
config_fini (domain->cfgst);
}
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 (dds_domain **domain_out, dds_domainid_t id)
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
{
struct dds_domain *dom = NULL;
struct dds_domain *dom;
dds_return_t ret;
/* FIXME: should perhaps lock parent object just like everywhere */
ddsrt_mutex_lock (&dds_global.m_mutex);
/* FIXME: hack around default domain ids, not yet being able to handle multiple domains simultaneously */
retry:
if (id != DDS_DOMAIN_DEFAULT)
{
if ((dom = dds_domain_find_locked (id)) == NULL)
@ -225,41 +219,94 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
switch (ret)
{
case DDS_RETCODE_OK:
dom->m_refc++;
*domain_out = dom;
if (!use_existing)
{
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
break;
case DDS_RETCODE_NOT_FOUND:
dom = dds_alloc (sizeof (*dom));
if ((ret = dds_domain_init (dom, id)) < 0)
dds_free (dom);
}
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_add_ref_locked (&dom->m_entity);
ddsrt_mutex_unlock (&dom->m_entity.m_mutex);
*domain_out = dom;
}
break;
case DDS_RETCODE_PRECONDITION_NOT_MET:
DDS_ILOG (DDS_LC_ERROR, id, "Inconsistent domain configuration detected: domain on configuration: %"PRIu32", domain %"PRIu32"\n", dom->m_id, id);
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_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;
}
break;
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
return ret;
}
void dds_domain_free (dds_domain *domain)
dds_return_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)
return DDS_RETCODE_BAD_PARAMETER;
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
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:
return ret;
}
static dds_return_t dds_domain_free (dds_entity *vdomain)
{
struct dds_domain *domain = (struct dds_domain *) vdomain;
rtps_stop (&domain->gv);
dds__builtin_fini (domain);
if (domain->gv.config.liveliness_monitoring)
ddsi_threadmon_unregister_domain (dds_global.threadmon, &domain->gv);
rtps_fini (&domain->gv);
/* tearing down the top-level object has more consequences, so it waits until signalled that all
domains have been removed */
ddsrt_mutex_lock (&dds_global.m_mutex);
if (--domain->m_refc != 0)
if (domain->gv.config.liveliness_monitoring && --dds_global.threadmon_count == 0)
{
ddsrt_mutex_unlock (&dds_global.m_mutex);
ddsi_threadmon_stop (dds_global.threadmon);
ddsi_threadmon_free (dds_global.threadmon);
}
else
{
ddsrt_avl_delete (&dds_domaintree_def, &dds_global.m_domains, domain);
dds_entity_final_deinit_before_free (vdomain);
config_fini (domain->cfgst);
dds_free (vdomain);
ddsrt_cond_broadcast (&dds_global.m_cond);
ddsrt_mutex_unlock (&dds_global.m_mutex);
dds_domain_fini (domain);
dds_free (domain);
}
return DDS_RETCODE_NO_DATA;
}
#include "dds__entity.h"
@ -295,7 +342,8 @@ void dds_write_set_batch (bool enable)
/* FIXME: get channels + latency budget working and get rid of this; in the mean time, any ugly hack will do. */
struct dds_domain *dom;
dds_domainid_t next_id = 0;
dds_init ();
if (dds_init () < 0)
return;
ddsrt_mutex_lock (&dds_global.m_mutex);
while ((dom = ddsrt_avl_lookup_succ_eq (&dds_domaintree_def, &dds_global.m_domains, &next_id)) != NULL)
{
@ -306,7 +354,7 @@ void dds_write_set_batch (bool enable)
dds_instance_handle_t last_iid = 0;
struct dds_entity *e;
while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_ppants, &last_iid)) != NULL)
while (dom && (e = ddsrt_avl_lookup_succ (&dds_entity_children_td, &dom->m_entity.m_children, &last_iid)) != NULL)
{
struct dds_entity *x;
last_iid = e->m_iid;
@ -321,5 +369,5 @@ void dds_write_set_batch (bool enable)
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
dds_fini ();
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
}

View file

@ -40,10 +40,15 @@ const struct dds_entity_deriver *dds_entity_deriver_table[] = {
[DDS_KIND_COND_QUERY] = &dds_entity_deriver_readcondition,
[DDS_KIND_COND_GUARD] = &dds_entity_deriver_guardcondition,
[DDS_KIND_WAITSET] = &dds_entity_deriver_waitset,
[DDS_KIND_DOMAIN] = &dds_entity_deriver_domain,
[DDS_KIND_CYCLONEDDS] = &dds_entity_deriver_cyclonedds
};
dds_return_t dds_entity_deriver_dummy_close (struct dds_entity *e) {
(void) e; return DDS_RETCODE_OK;
void dds_entity_deriver_dummy_interrupt (struct dds_entity *e) {
(void) e;
}
void dds_entity_deriver_dummy_close (struct dds_entity *e) {
(void) e;
}
dds_return_t dds_entity_deriver_dummy_delete (struct dds_entity *e) {
(void) e; return DDS_RETCODE_OK;
@ -55,7 +60,8 @@ dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask) {
(void) mask; return DDS_RETCODE_ILLEGAL_OPERATION;
}
extern inline dds_return_t dds_entity_deriver_close (struct dds_entity *e);
extern inline void dds_entity_deriver_interrupt (struct dds_entity *e);
extern inline void dds_entity_deriver_close (struct dds_entity *e);
extern inline dds_return_t dds_entity_deriver_delete (struct dds_entity *e);
extern inline dds_return_t dds_entity_deriver_set_qos (struct dds_entity *e, const dds_qos_t *qos, bool enabled);
extern inline dds_return_t dds_entity_deriver_validate_status (struct dds_entity *e, uint32_t mask);
@ -73,23 +79,12 @@ 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 void dds_entity_observers_delete (dds_entity *observed);
void dds_entity_add_ref_locked (dds_entity *e)
{
dds_handle_add_ref (&e->m_hdllink);
}
dds_domain *dds__entity_domain (dds_entity *e)
{
return e->m_domain;
}
static dds_entity *dds__nonself_parent (dds_entity *e)
{
return e->m_parent == e ? NULL : e->m_parent;
}
static bool entity_has_status (const dds_entity *e)
{
switch (e->m_kind)
@ -105,6 +100,8 @@ static bool entity_has_status (const dds_entity *e)
case DDS_KIND_COND_QUERY:
case DDS_KIND_COND_GUARD:
case DDS_KIND_WAITSET:
case DDS_KIND_DOMAIN:
case DDS_KIND_CYCLONEDDS:
break;
case DDS_KIND_DONTCARE:
abort ();
@ -117,12 +114,13 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
{
dds_handle_t handle;
assert ((kind == DDS_KIND_PARTICIPANT) == (parent == NULL));
assert ((kind == DDS_KIND_CYCLONEDDS) == (parent == NULL));
assert (e);
e->m_kind = kind;
e->m_qos = qos;
e->m_cb_count = 0;
e->m_cb_pending_count = 0;
e->m_observers = NULL;
/* TODO: CHAM-96: Implement dynamic enabling of entity. */
@ -143,14 +141,14 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
{
e->m_parent = parent;
e->m_domain = parent->m_domain;
e->m_participant = parent->m_participant;
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
}
else
{
e->m_participant = e;
e->m_parent = e;
assert (kind == DDS_KIND_CYCLONEDDS);
e->m_parent = NULL;
e->m_domain = NULL;
}
ddsrt_avl_init (&dds_entity_children_td, &e->m_children);
dds_reset_listener (&e->m_listener);
if (listener)
@ -162,13 +160,26 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind
ddsrt_mutex_unlock (&parent->m_observers_lock);
}
if (kind == DDS_KIND_CYCLONEDDS)
{
if ((handle = dds_handle_register_special (&e->m_hdllink, DDS_CYCLONEDDS_HANDLE)) <= 0)
return (dds_entity_t) handle;
}
else
{
if ((handle = dds_handle_create (&e->m_hdllink)) <= 0)
return (dds_entity_t) handle;
}
/* An dds_handle_t is directly used as dds_entity_t. */
return (dds_entity_t) handle;
}
void dds_entity_init_complete (dds_entity *entity)
{
dds_handle_unpend (&entity->m_hdllink);
}
void dds_entity_register_child (dds_entity *parent, dds_entity *child)
{
assert (child->m_iid != 0);
@ -176,11 +187,6 @@ void dds_entity_register_child (dds_entity *parent, dds_entity *child)
ddsrt_avl_insert (&dds_entity_children_td, &parent->m_children, child);
}
dds_return_t dds_delete (dds_entity_t entity)
{
return dds_delete_impl (entity, false);
}
static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
{
ddsrt_avl_iter_t it;
@ -192,45 +198,145 @@ static dds_entity *next_non_topic_child (ddsrt_avl_tree_t *remaining_children)
return NULL;
}
dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
#define TRACE_DELETE 0 /* FIXME: use DDS_LOG for this */
#if TRACE_DELETE
static const char *entity_kindstr (dds_entity_kind_t kind)
{
switch (kind)
{
case DDS_KIND_TOPIC: return "topic";
case DDS_KIND_READER: return "reader";
case DDS_KIND_WRITER: return "writer";
case DDS_KIND_PUBLISHER: return "publisher";
case DDS_KIND_SUBSCRIBER: return "subscriber";
case DDS_KIND_PARTICIPANT: return "participant";
case DDS_KIND_COND_READ: return "readcond";
case DDS_KIND_COND_QUERY: return "querycond";
case DDS_KIND_COND_GUARD: return "guardcond";
case DDS_KIND_WAITSET: return "waitset";
case DDS_KIND_DOMAIN: return "domain";
case DDS_KIND_CYCLONEDDS: return "cyclonedds";
case DDS_KIND_DONTCARE: break;
}
return "UNDEF";
}
static void print_delete (const dds_entity *e, enum delete_impl_state delstate , dds_instance_handle_t iid)
{
unsigned cm = ddsrt_atomic_ld32 (&e->m_hdllink.cnt_flags);
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",
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);
}
void dds_entity_final_deinit_before_free (dds_entity *e)
{
dds_delete_qos (e->m_qos);
ddsrt_cond_destroy (&e->m_cond);
ddsrt_cond_destroy (&e->m_observers_cond);
ddsrt_mutex_destroy (&e->m_mutex);
ddsrt_mutex_destroy (&e->m_observers_lock);
}
static dds_return_t dds_delete_impl (dds_entity_t entity, enum delete_impl_state delstate)
{
dds_time_t timeout = DDS_SECS(10);
dds_entity *e;
dds_return_t ret;
if ((ret = dds_entity_pin (entity, &e)) < 0)
return ret;
else
return dds_delete_impl_pinned (e, delstate);
}
dds_return_t dds_delete_impl_pinned (dds_entity *e, enum delete_impl_state delstate)
{
dds_entity *child;
dds_return_t ret;
dds_return_t rc;
if ((rc = dds_entity_pin (entity, &e)) < 0)
return rc;
/* 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 (keep_if_explicit == true && (e->m_flags & DDS_ENTITY_IMPLICIT) == 0)
#if TRACE_DELETE
print_delete (e, delstate, 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))
{
ddsrt_mutex_unlock (&e->m_mutex);
dds_entity_unpin (e);
dds_entity_unlock (e);
return DDS_RETCODE_OK;
}
/* 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))
{
ddsrt_mutex_unlock (&e->m_mutex);
dds_entity_unpin (e);
dds_entity_unlock (e);
return DDS_RETCODE_OK;
}
/* 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
trying to acquire m_mutex to do their thing (including creating children,
attaching to waitsets, &c.) */
assert (dds_handle_is_closed (&e->m_hdllink));
/* Trigger blocked threads (and, still, delete DDSI reader/writer to trigger
continued cleanup -- while that's quite safe given that GUIDs don't get
reused quickly, it needs an update) */
dds_entity_deriver_interrupt (e);
/* Prevent further listener invocations; dds_set_status_mask locks m_mutex and
checks for a pending delete to guarantee that once we clear the mask here,
no new listener invocations will occur beyond those already in progress.
(FIXME: or committed to? I think in-progress only, better check.) */
ddsrt_mutex_lock (&e->m_observers_lock);
if (entity_has_status (e))
ddsrt_atomic_and32 (&e->m_status.m_status_and_mask, SAM_STATUS_MASK);
dds_reset_listener (&e->m_listener);
/* Signal observers that this entity will be deleted and wait for
all listeners to complete. */
ddsrt_mutex_unlock (&e->m_mutex);
dds_entity_observers_signal_delete (e);
while (e->m_cb_count > 0)
/* wait for all listeners to complete - FIXME: rely on pincount instead?
that would require all listeners to pin the entity instead, but it
would prevent them from doing much. */
while (e->m_cb_pending_count > 0)
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
ddsrt_mutex_unlock (&e->m_observers_lock);
/* Wait for all other threads to unpin the entity */
dds_handle_close_wait (&e->m_hdllink);
/* Pin count dropped to one with CLOSING flag set: no other threads still
in operations involving this entity */
dds_entity_observers_signal_delete (e);
dds_entity_deriver_close (e);
/*
* Recursively delete children.
*
@ -248,106 +354,123 @@ dds_return_t dds_delete_impl (dds_entity_t entity, bool keep_if_explicit)
*
* To circumvent the problem. We ignore topics in the first loop.
*/
ret = DDS_RETCODE_OK;
ddsrt_mutex_lock (&e->m_mutex);
while ((child = next_non_topic_child (&e->m_children)) && ret == DDS_RETCODE_OK)
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 (child_handle);
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
ddsrt_mutex_lock (&e->m_mutex);
}
while ((child = ddsrt_avl_find_min (&dds_entity_children_td, &e->m_children)) != NULL && ret == DDS_RETCODE_OK)
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 (child_handle);
(void) dds_delete_impl (child_handle, DIS_FROM_PARENT);
ddsrt_mutex_lock (&e->m_mutex);
}
ddsrt_mutex_unlock (&e->m_mutex);
if (ret == DDS_RETCODE_OK)
ret = dds_entity_deriver_close (e);
dds_entity_unpin (e);
if (ret == DDS_RETCODE_OK)
/* 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
kicked during the close(). */
ret = dds_handle_delete (&e->m_hdllink);
assert (ret == DDS_RETCODE_OK);
(void) ret;
/* Remove from parent; schedule deletion of parent if it was created implicitly, no
longer has any remaining children, and we didn't arrive here as a consequence of
deleting the parent. */
dds_entity *parent_to_delete = NULL;
if (e->m_parent != NULL)
{
/* 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 kicked during the close(). */
if ((ret = dds_handle_delete (&e->m_hdllink, timeout)) != DDS_RETCODE_OK)
struct dds_entity * const p = e->m_parent;
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);
/* 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);
}
/* Do some specific deletion when needed */
ret = dds_entity_deriver_delete (e);
if (ret == DDS_RETCODE_NO_DATA)
{
/* Bootstrapping and its inverse are always a tricky business, and here it is no different:
deleting the pseudo-top-level object tears down all kinds of stuff that is supposed to
remain in existence (like the entire platform abstraction) and so it must be the final
call. Thus, we rely on it to call "dds_entity_final_deinit_before_free" and return a
special error code that we don't pass on to the caller. */
ret = DDS_RETCODE_OK;
}
else if (ret != DDS_RETCODE_OK)
{
if (parent_to_delete)
dds_entity_unpin (parent_to_delete);
return ret;
}
if (ret == DDS_RETCODE_OK)
else
{
/* Remove all possible observers. */
dds_entity_observers_delete (e);
/* Remove from parent */
dds_entity *parent;
if ((parent = dds__nonself_parent(e)) != NULL)
{
ddsrt_mutex_lock (&parent->m_mutex);
assert (ddsrt_avl_lookup (&dds_entity_children_td, &parent->m_children, &e->m_iid) != NULL);
ddsrt_avl_delete (&dds_entity_children_td, &parent->m_children, e);
ddsrt_mutex_unlock (&parent->m_mutex);
}
/* Do some specific deletion when needed. */
ret = dds_entity_deriver_delete (e);
}
if (ret == DDS_RETCODE_OK)
{
dds_delete_qos (e->m_qos);
ddsrt_cond_destroy (&e->m_cond);
ddsrt_cond_destroy (&e->m_observers_cond);
ddsrt_mutex_destroy (&e->m_mutex);
ddsrt_mutex_destroy (&e->m_observers_lock);
dds_entity_final_deinit_before_free (e);
dds_free (e);
}
return ret;
assert (ret == DDS_RETCODE_OK);
(void) ret;
return (parent_to_delete != NULL) ? dds_delete_impl_pinned (parent_to_delete, DIS_IMPLICIT) : DDS_RETCODE_OK;
}
bool dds_entity_in_scope (const dds_entity *e, const dds_entity *root)
{
/* An entity is not an ancestor of itself */
while (e != NULL && e != root)
e = e->m_parent;
return (e != NULL);
}
dds_entity_t dds_get_parent (dds_entity_t entity)
{
dds_entity *e;
dds_return_t rc;
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;
else
{
dds_entity *parent;
dds_entity_t hdl;
if ((parent = dds__nonself_parent(e)) == NULL)
hdl = DDS_ENTITY_NIL;
else
{
dds_entity *x;
hdl = parent->m_hdllink.hdl;
if (dds_entity_lock (hdl, DDS_KIND_DONTCARE, &x) == DDS_RETCODE_OK)
{
parent->m_flags &= ~DDS_ENTITY_IMPLICIT;
dds_entity_unlock (parent);
}
}
dds_entity_unlock (e);
dds_entity_t hdl = e->m_parent ? e->m_parent->m_hdllink.hdl : 0;
dds_entity_unpin (e);
return hdl;
}
}
dds_participant *dds_entity_participant (dds_entity *e)
{
while (e && dds_entity_kind (e) != DDS_KIND_PARTICIPANT)
e = e->m_parent;
return (dds_participant *) e;
}
dds_entity_t dds_get_participant (dds_entity_t entity)
{
dds_entity *e;
dds_return_t rc;
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;
else
{
dds_entity_t hdl = e->m_participant->m_hdllink.hdl;
dds_entity_unlock (e);
dds_participant *par = dds_entity_participant (e);
dds_entity_t hdl = par ? par->m_entity.m_hdllink.hdl : 0;
dds_entity_unpin (e);
return hdl;
}
}
@ -357,42 +480,28 @@ dds_return_t dds_get_children (dds_entity_t entity, dds_entity_t *children, size
dds_entity *e;
dds_return_t rc;
if (children != NULL && (size <= 0 || size >= INT32_MAX))
return DDS_RETCODE_BAD_PARAMETER;
if (children == NULL && size != 0)
if ((children != NULL && (size == 0 || size > INT32_MAX)) || (children == NULL && size != 0))
return DDS_RETCODE_BAD_PARAMETER;
if ((rc = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
return rc;
else
{
/* FIXME: fix the implicit/explicit stuff so the set_explicit isn't needed; and then this can also be done with a regular iterator & without unlocking */
ddsrt_avl_iter_t it;
size_t n = 0;
dds_instance_handle_t last_iid = 0;
struct dds_entity *c;
ddsrt_mutex_lock (&e->m_mutex);
while ((c = ddsrt_avl_lookup_succ (&dds_entity_children_td, &e->m_children, &last_iid)) != NULL)
for (c = ddsrt_avl_iter_first (&dds_entity_children_td, &e->m_children, &it); c != NULL; c = ddsrt_avl_iter_next (&it))
{
struct dds_entity *tmp;
/* Attempt at pinning the entity will fail if it is still pending */
if (dds_entity_pin (c->m_hdllink.hdl, &tmp) == DDS_RETCODE_OK)
{
last_iid = c->m_iid;
if (n < size)
{
dds_entity *x;
/* Claim child handle to guarantee the child entity remains valid; as we unlock "e" only when we manage to claim the child, and the child has to remain in existence until we release it, "c" remains a valid pointer despite the unlocking. */
if (dds_entity_pin (c->m_hdllink.hdl, &x) == DDS_RETCODE_OK)
{
assert (x == c);
children[n] = c->m_hdllink.hdl;
ddsrt_mutex_unlock (&e->m_mutex);
ddsrt_mutex_lock (&c->m_mutex);
c->m_flags &= ~DDS_ENTITY_IMPLICIT;
ddsrt_mutex_unlock (&c->m_mutex);
ddsrt_mutex_lock (&e->m_mutex);
dds_entity_unpin (c);
}
}
n++;
dds_entity_unpin (tmp);
}
}
ddsrt_mutex_unlock (&e->m_mutex);
dds_entity_unpin (e);
@ -423,6 +532,8 @@ static uint64_t entity_kind_qos_mask (dds_entity_kind_t kind)
case DDS_KIND_COND_QUERY:
case DDS_KIND_COND_GUARD:
case DDS_KIND_WAITSET:
case DDS_KIND_DOMAIN:
case DDS_KIND_CYCLONEDDS:
break;
}
return 0;
@ -603,7 +714,8 @@ dds_return_t dds_set_qos (dds_entity_t entity, const dds_qos_t *qos)
{
case DDS_KIND_TOPIC: {
dds_entity *pp;
if (dds_entity_pin (e->m_participant->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
assert (dds_entity_kind (e->m_parent) == DDS_KIND_PARTICIPANT);
if (dds_entity_pin (e->m_parent->m_hdllink.hdl, &pp) == DDS_RETCODE_OK)
{
pushdown_topic_qos (pp, e);
dds_entity_unpin (pp);
@ -763,7 +875,7 @@ static void pushdown_listener (dds_entity *e)
ddsrt_mutex_unlock (&e->m_mutex);
ddsrt_mutex_lock (&c->m_observers_lock);
while (c->m_cb_count > 0)
while (c->m_cb_pending_count > 0)
ddsrt_cond_wait (&c->m_observers_cond, &c->m_observers_lock);
ddsrt_mutex_lock (&e->m_observers_lock);
@ -791,7 +903,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
return rc;
ddsrt_mutex_lock (&e->m_observers_lock);
while (e->m_cb_count > 0)
while (e->m_cb_pending_count > 0)
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
/* new listener is constructed by combining "listener" with the ancestral listeners;
@ -801,7 +913,7 @@ dds_return_t dds_set_listener (dds_entity_t entity, const dds_listener_t *listen
if (listener)
dds_merge_listener (&e->m_listener, listener);
x = e;
while (dds_entity_kind (x) != DDS_KIND_PARTICIPANT)
while (dds_entity_kind (x) != DDS_KIND_CYCLONEDDS)
{
x = x->m_parent;
ddsrt_mutex_lock (&x->m_observers_lock);
@ -892,17 +1004,26 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
if ((mask & ~SAM_STATUS_MASK) != 0)
return DDS_RETCODE_BAD_PARAMETER;
if ((ret = dds_entity_pin (entity, &e)) != DDS_RETCODE_OK)
if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
return ret;
if (dds_handle_is_closed (&e->m_hdllink))
{
/* The sole reason for locking the mutex was so we can do this atomically with
respect to dds_delete (which in turn requires checking whether the handle
is still open), because delete relies on the mask to shut down all listener
invocations. */
dds_entity_unlock (e);
return DDS_RETCODE_PRECONDITION_NOT_MET;
}
if ((ret = dds_entity_deriver_validate_status (e, mask)) == DDS_RETCODE_OK)
{
assert (entity_has_status (e));
ddsrt_mutex_lock (&e->m_observers_lock);
while (e->m_cb_count > 0)
while (e->m_cb_pending_count > 0)
ddsrt_cond_wait (&e->m_observers_cond, &e->m_observers_lock);
/* Don't block internal status triggers. */
uint32_t old, new;
do {
old = ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask);
@ -910,7 +1031,7 @@ dds_return_t dds_set_status_mask (dds_entity_t entity, uint32_t mask)
} while (!ddsrt_atomic_cas32 (&e->m_status.m_status_and_mask, old, new));
ddsrt_mutex_unlock (&e->m_observers_lock);
}
dds_entity_unpin (e);
dds_entity_unlock (e);
return ret;
}
@ -946,7 +1067,6 @@ static dds_return_t dds_readtake_status (dds_entity_t entity, uint32_t *status,
return ret;
}
dds_return_t dds_read_status (dds_entity_t entity, uint32_t *status, uint32_t mask)
{
return dds_readtake_status (entity, status, mask, false);
@ -965,11 +1085,11 @@ dds_return_t dds_get_domainid (dds_entity_t entity, dds_domainid_t *id)
if (id == NULL)
return DDS_RETCODE_BAD_PARAMETER;
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;
*id = e->m_domain->m_id;
dds_entity_unlock(e);
*id = e->m_domain ? e->m_domain->m_id : DDS_DOMAIN_DEFAULT;
dds_entity_unpin (e);
return DDS_RETCODE_OK;
}
@ -1029,7 +1149,7 @@ dds_return_t dds_entity_lock (dds_entity_t hdl, dds_entity_kind_t kind, dds_enti
void dds_entity_unlock (dds_entity *e)
{
ddsrt_mutex_unlock (&e->m_mutex);
dds_handle_unpin (&e->m_hdllink);
dds_entity_unpin (e);
}
dds_return_t dds_triggered (dds_entity_t entity)
@ -1047,7 +1167,7 @@ dds_return_t dds_triggered (dds_entity_t entity)
return ret;
}
static bool in_observer_list_p (const struct dds_entity *observed, const dds_entity *observer)
static bool in_observer_list_p (const struct dds_entity *observed, const dds_waitset *observer)
{
dds_entity_observer *cur;
for (cur = observed->m_observers; cur != NULL; cur = cur->m_next)
@ -1056,13 +1176,15 @@ static bool in_observer_list_p (const struct dds_entity *observed, const dds_ent
return false;
}
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *observer, dds_entity_callback cb, dds_entity_delete_callback delete_cb)
dds_return_t dds_entity_observer_register (dds_entity *observed, dds_waitset *observer, dds_entity_callback_t cb, dds_entity_attach_callback_t attach_cb, void *attach_arg, dds_entity_delete_callback_t delete_cb)
{
dds_return_t rc;
assert (observed);
ddsrt_mutex_lock (&observed->m_observers_lock);
if (in_observer_list_p (observed, observer))
rc = DDS_RETCODE_PRECONDITION_NOT_MET;
else if (!attach_cb (observer, observed, attach_arg))
rc = DDS_RETCODE_BAD_PARAMETER;
else
{
dds_entity_observer *o = ddsrt_malloc (sizeof (dds_entity_observer));
@ -1077,7 +1199,7 @@ dds_return_t dds_entity_observer_register (dds_entity *observed, dds_entity *obs
return rc;
}
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *observer)
dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_waitset *observer, bool invoke_delete_cb)
{
dds_return_t rc;
dds_entity_observer *prev, *idx;
@ -1098,6 +1220,8 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
observed->m_observers = idx->m_next;
else
prev->m_next = idx->m_next;
if (invoke_delete_cb)
idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
ddsrt_free (idx);
rc = DDS_RETCODE_OK;
}
@ -1105,21 +1229,6 @@ dds_return_t dds_entity_observer_unregister (dds_entity *observed, dds_entity *o
return rc;
}
static void dds_entity_observers_delete (dds_entity *observed)
{
dds_entity_observer *idx;
ddsrt_mutex_lock (&observed->m_observers_lock);
idx = observed->m_observers;
while (idx != NULL)
{
dds_entity_observer *next = idx->m_next;
ddsrt_free (idx);
idx = next;
}
observed->m_observers = NULL;
ddsrt_mutex_unlock (&observed->m_observers_lock);
}
static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
{
for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
@ -1128,8 +1237,16 @@ static void dds_entity_observers_signal (dds_entity *observed, uint32_t status)
static void dds_entity_observers_signal_delete (dds_entity *observed)
{
for (dds_entity_observer *idx = observed->m_observers; idx; idx = idx->m_next)
dds_entity_observer *idx;
idx = observed->m_observers;
while (idx != NULL)
{
dds_entity_observer *next = idx->m_next;
idx->m_delete_cb (idx->m_observer, observed->m_hdllink.hdl);
ddsrt_free (idx);
idx = next;
}
observed->m_observers = NULL;
}
void dds_entity_status_signal (dds_entity *e, uint32_t status)
@ -1158,11 +1275,13 @@ void dds_entity_trigger_set (dds_entity *e, uint32_t t)
{
assert (! entity_has_status (e));
uint32_t oldst;
ddsrt_mutex_lock (&e->m_observers_lock);
do {
oldst = ddsrt_atomic_ld32 (&e->m_status.m_trigger);
} while (!ddsrt_atomic_cas32 (&e->m_status.m_trigger, oldst, t));
if (oldst == 0 && t != 0)
dds_entity_observers_signal (e, t);
ddsrt_mutex_unlock (&e->m_observers_lock);
}
dds_entity_t dds_get_topic (dds_entity_t entity)

View file

@ -11,6 +11,7 @@
*/
#include <assert.h>
#include <string.h>
#include "dds__init.h"
#include "dds__reader.h"
#include "dds__guardcond.h"
#include "dds__participant.h"
@ -22,28 +23,53 @@
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_guardcond)
const struct dds_entity_deriver dds_entity_deriver_guardcondition = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_entity_deriver_dummy_delete,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_entity_t dds_create_guardcondition (dds_entity_t participant)
dds_entity_t dds_create_guardcondition (dds_entity_t owner)
{
dds_participant *pp;
dds_entity *e;
dds_return_t rc;
if ((rc = dds_participant_lock (participant, &pp)) != DDS_RETCODE_OK)
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
have to call it. If it is some bogus value and the library is not initialised yet ... so be
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
if ((rc = dds_init ()) < 0)
return rc;
else
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
goto err_entity_lock;
switch (dds_entity_kind (e))
{
dds_guardcond *gcond = dds_alloc (sizeof (*gcond));
dds_entity_t hdl = dds_entity_init (&gcond->m_entity, &pp->m_entity, DDS_KIND_COND_GUARD, NULL, NULL, 0);
gcond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&pp->m_entity, &gcond->m_entity);
dds_participant_unlock (pp);
return hdl;
case DDS_KIND_CYCLONEDDS:
case DDS_KIND_DOMAIN:
case DDS_KIND_PARTICIPANT:
break;
default:
rc = DDS_RETCODE_ILLEGAL_OPERATION;
goto err_entity_kind;
}
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);
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);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return rc;
}
dds_return_t dds_set_guardcondition (dds_entity_t condition, bool triggered)

View file

@ -20,27 +20,10 @@
#include "dds__handles.h"
#include "dds__types.h"
/* FIXME: this code isn't really correct when USE_CHH is set:
- the DDS entity code doesn't really play by the awake/asleep mechanism
- there is no provision in the code for a handle being deleted concurrent to a lookup,
that is, deleting handle links should also go through the GC
entity framework needs a fair bit of rewriting anyway ... */
#define USE_CHH 0
#define HDL_FLAG_CLOSED (0x80000000u)
/* ref count: # outstanding references to this handle/object (not so sure it is
ideal to have a one-to-one mapping between the two, but that is what the rest
of the code assumes at the moment); so this limits one to having, e.g., no
more than 64k endpoints referencing the same topic */
#define HDL_REFCOUNT_MASK (0x0ffff000u)
#define HDL_REFCOUNT_UNIT (0x00001000u)
#define HDL_REFCOUNT_SHIFT 12
/* pin count: # concurrent operations, so allowing up to 4096 threads had better
be enough ... */
#define HDL_PINCOUNT_MASK (0x00000fffu)
#define HDL_PINCOUNT_UNIT (0x00000001u)
/* 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
@ -50,11 +33,7 @@
#define MAX_HANDLES (INT32_MAX / 128)
struct dds_handle_server {
#if USE_CHH
struct ddsrt_chh *ht;
#else
struct ddsrt_hh *ht;
#endif
size_t count;
ddsrt_mutex_t lock;
ddsrt_cond_t cond;
@ -78,45 +57,46 @@ static int handle_equal (const void *va, const void *vb)
dds_return_t dds_handle_server_init (void)
{
#if USE_CHH
handles.ht = ddsrt_chh_new (128, handle_hash, handle_equal, free_via_gc);
#else
/* called with ddsrt's singleton mutex held (see dds_init/fini) */
if (handles.ht == NULL)
{
handles.ht = ddsrt_hh_new (128, handle_hash, handle_equal);
#endif
handles.count = 0;
ddsrt_mutex_init (&handles.lock);
ddsrt_cond_init (&handles.cond);
}
return DDS_RETCODE_OK;
}
void dds_handle_server_fini (void)
{
#if USE_CHH
#ifndef NDEBUG
struct ddsrt_chh_iter it;
assert (ddsrt_chh_iter_first (handles.ht, &it) == NULL);
#endif
ddsrt_chh_free (handles.ht);
#else /* USE_CHH */
/* called with ddsrt's singleton mutex held (see dds_init/fini) */
if (handles.ht != NULL)
{
#ifndef NDEBUG
struct ddsrt_hh_iter it;
for (struct dds_handle_link *link = ddsrt_hh_iter_first (handles.ht, &it); link != NULL; link = ddsrt_hh_iter_next (&it))
{
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
DDS_ERROR ("handle %"PRId32" pin %"PRIu32" refc %"PRIu32"%s%s%s\n", link->hdl,
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" : "");
}
assert (ddsrt_hh_iter_first (handles.ht, &it) == NULL);
#endif
ddsrt_hh_free (handles.ht);
#endif /* USE_CHH */
ddsrt_cond_destroy (&handles.cond);
ddsrt_mutex_destroy (&handles.lock);
handles.ht = NULL;
}
}
#if USE_CHH
static bool hhadd (struct ddsrt_chh *ht, void *elem) { return ddsrt_chh_add (ht, elem); }
#else
static bool hhadd (struct ddsrt_hh *ht, void *elem) { return ddsrt_hh_add (ht, elem); }
#endif
static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
{
ddsrt_atomic_st32 (&link->cnt_flags, HDL_REFCOUNT_UNIT);
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
do {
do {
link->hdl = (int32_t) (ddsrt_random () & INT32_MAX);
@ -127,13 +107,7 @@ static dds_handle_t dds_handle_create_int (struct dds_handle_link *link)
dds_handle_t dds_handle_create (struct dds_handle_link *link)
{
#if USE_CHH
struct thread_state1 * const ts1 = lookup_thread_state ();
#endif
dds_handle_t ret;
#if USE_CHH
thread_state_awake (ts1);
#endif
ddsrt_mutex_lock (&handles.lock);
if (handles.count == MAX_HANDLES)
{
@ -143,55 +117,67 @@ dds_handle_t dds_handle_create (struct dds_handle_link *link)
else
{
handles.count++;
#if USE_CHH
ddsrt_mutex_unlock (&handles.lock);
ret = dds_handle_create_int (link);
#else
ret = dds_handle_create_int (link);
ddsrt_mutex_unlock (&handles.lock);
#endif
assert (ret > 0);
}
#if USE_CHH
thread_state_asleep (ts1);
#endif
return ret;
}
void dds_handle_close (struct dds_handle_link *link)
dds_return_t dds_handle_register_special (struct dds_handle_link *link, dds_handle_t handle)
{
ddsrt_atomic_or32 (&link->cnt_flags, HDL_FLAG_CLOSED);
}
int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
{
#if USE_CHH
struct thread_state1 * const ts1 = lookup_thread_state ();
#endif
assert (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED);
dds_return_t ret;
if (handle <= 0)
return DDS_RETCODE_BAD_PARAMETER;
ddsrt_mutex_lock (&handles.lock);
if ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
{
/* FIXME: there is no sensible solution when this times out, so it must
never do that ... */
const dds_time_t abstimeout = dds_time () + timeout;
while ((ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_PINCOUNT_MASK) != 0)
{
if (!ddsrt_cond_waituntil (&handles.cond, &handles.lock, abstimeout))
if (handles.count == MAX_HANDLES)
{
ddsrt_mutex_unlock (&handles.lock);
fprintf (stderr, "** timeout in handle_delete **\n");
return DDS_RETCODE_TIMEOUT;
ret = DDS_RETCODE_OUT_OF_RESOURCES;
}
else
{
handles.count++;
ddsrt_atomic_st32 (&link->cnt_flags, HDL_FLAG_PENDING | HDL_REFCOUNT_UNIT | 1u);
link->hdl = handle;
if (hhadd (handles.ht, link))
ret = handle;
else
ret = DDS_RETCODE_BAD_PARAMETER;
ddsrt_mutex_unlock (&handles.lock);
assert (ret > 0);
}
return ret;
}
#if USE_CHH
thread_state_awake (ts1);
int x = ddsrt_chh_remove (handles.ht, link);
thread_state_asleep (ts1);
#else
int x = ddsrt_hh_remove (handles.ht, link);
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_CLOSING));
assert ((cf & HDL_REFCOUNT_MASK) >= HDL_REFCOUNT_UNIT);
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_atomic_and32 (&link->cnt_flags, ~HDL_FLAG_PENDING);
dds_handle_unpin (link);
}
int32_t dds_handle_delete (struct dds_handle_link *link)
{
#ifndef NDEBUG
uint32_t cf = ddsrt_atomic_ld32 (&link->cnt_flags);
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);
#endif
ddsrt_mutex_lock (&handles.lock);
int x = ddsrt_hh_remove (handles.ht, link);
assert(x);
(void)x;
assert (handles.count > 0);
@ -200,11 +186,8 @@ int32_t dds_handle_delete (struct dds_handle_link *link, dds_duration_t timeout)
return DDS_RETCODE_OK;
}
int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
static int32_t dds_handle_pin_int (dds_handle_t hdl, uint32_t delta, struct dds_handle_link **link)
{
#if USE_CHH
struct thread_state1 * const ts1 = lookup_thread_state ();
#endif
struct dds_handle_link dummy = { .hdl = hdl };
int32_t rc;
/* it makes sense to check here for initialization: the first thing any operation
@ -218,41 +201,41 @@ int32_t dds_handle_pin (dds_handle_t hdl, struct dds_handle_link **link)
if (handles.ht == NULL)
return DDS_RETCODE_PRECONDITION_NOT_MET;
#if USE_CHH
thread_state_awake (ts1);
*link = ddsrt_chh_lookup (handles.ht, &dummy);
#else
ddsrt_mutex_lock (&handles.lock);
*link = ddsrt_hh_lookup (handles.ht, &dummy);
#endif
if (*link == NULL)
rc = DDS_RETCODE_BAD_PARAMETER;
else
{
uint32_t cnt_flags;
uint32_t cf;
/* Assume success; bail out if the object turns out to be in the process of
being deleted */
rc = DDS_RETCODE_OK;
do {
cnt_flags = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
if (cnt_flags & HDL_FLAG_CLOSED)
cf = ddsrt_atomic_ld32 (&(*link)->cnt_flags);
if (cf & (HDL_FLAG_CLOSED | HDL_FLAG_CLOSING | HDL_FLAG_PENDING))
{
rc = DDS_RETCODE_BAD_PARAMETER;
break;
}
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cnt_flags, cnt_flags + HDL_PINCOUNT_UNIT));
} while (!ddsrt_atomic_cas32 (&(*link)->cnt_flags, cf, cf + delta));
}
#if USE_CHH
thread_state_asleep (ts1);
#else
ddsrt_mutex_unlock (&handles.lock);
#endif
return rc;
}
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_and_ref (dds_handle_t hdl, struct dds_handle_link **link)
{
return dds_handle_pin_int (hdl, HDL_REFCOUNT_UNIT + 1u, link);
}
void dds_handle_repin (struct dds_handle_link *link)
{
DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
uint32_t x = ddsrt_atomic_inc32_nv (&link->cnt_flags);
assert (!(x & HDL_FLAG_CLOSED));
(void) x;
@ -260,13 +243,20 @@ void dds_handle_repin (struct dds_handle_link *link)
void dds_handle_unpin (struct dds_handle_link *link)
{
DDSRT_STATIC_ASSERT (HDL_PINCOUNT_UNIT == 1);
if ((ddsrt_atomic_dec32_ov (&link->cnt_flags) & (HDL_FLAG_CLOSED | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSED | HDL_PINCOUNT_UNIT))
{
#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
assert ((cf & HDL_PINCOUNT_MASK) >= 1u);
#endif
ddsrt_mutex_lock (&handles.lock);
if ((ddsrt_atomic_dec32_nv (&link->cnt_flags) & (HDL_FLAG_CLOSING | HDL_PINCOUNT_MASK)) == (HDL_FLAG_CLOSING | 1u))
{
ddsrt_cond_broadcast (&handles.cond);
ddsrt_mutex_unlock (&handles.lock);
}
ddsrt_mutex_unlock (&handles.lock);
}
void dds_handle_add_ref (struct dds_handle_link *link)
@ -283,12 +273,27 @@ bool dds_handle_drop_ref (struct dds_handle_link *link)
if ((old & HDL_REFCOUNT_MASK) != HDL_REFCOUNT_UNIT)
new = old - HDL_REFCOUNT_UNIT;
else
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSED;
new = (old - HDL_REFCOUNT_UNIT) | HDL_FLAG_CLOSING;
} while (!ddsrt_atomic_cas32 (&link->cnt_flags, old, new));
return (new & HDL_REFCOUNT_MASK) == 0;
}
bool dds_handle_is_closed (struct dds_handle_link *link)
void dds_handle_close_wait (struct dds_handle_link *link)
{
return (ddsrt_atomic_ld32 (&link->cnt_flags) & HDL_FLAG_CLOSED) != 0;
#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);
}
extern inline bool dds_handle_is_closed (struct dds_handle_link *link);

View file

@ -18,10 +18,11 @@
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__domain.h"
#include "dds__builtin.h"
#include "dds__whc_builtintopic.h"
#include "dds__entity.h"
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_serdata.h"
@ -32,10 +33,49 @@
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
#define DOMAIN_ID_MIN 0
#define DOMAIN_ID_MAX 230
static void dds_close (struct dds_entity *e);
static dds_return_t dds_fini (struct dds_entity *e);
dds_globals dds_global;
const struct dds_entity_deriver dds_entity_deriver_cyclonedds = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_close,
.delete = dds_fini,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_cyclonedds_entity dds_global;
#define CDDS_STATE_ZERO 0u
#define CDDS_STATE_STARTING 1u
#define CDDS_STATE_READY 2u
#define CDDS_STATE_STOPPING 3u
static ddsrt_atomic_uint32_t dds_state = DDSRT_ATOMIC_UINT32_INIT (CDDS_STATE_ZERO);
static void common_cleanup (void)
{
if (thread_states_fini ())
dds_handle_server_fini ();
ddsi_iid_fini ();
ddsrt_cond_destroy (&dds_global.m_cond);
ddsrt_mutex_destroy (&dds_global.m_mutex);
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_ZERO);
ddsrt_cond_broadcast (ddsrt_get_singleton_cond ());
}
static bool cyclonedds_entity_ready (uint32_t s)
{
assert (s != CDDS_STATE_ZERO);
if (s == CDDS_STATE_STARTING || s == CDDS_STATE_STOPPING)
return false;
else
{
struct dds_handle_link *x;
return dds_handle_pin_and_ref (DDS_CYCLONEDDS_HANDLE, &x) == DDS_RETCODE_OK;
}
}
dds_return_t dds_init (void)
{
@ -43,18 +83,34 @@ dds_return_t dds_init (void)
ddsrt_init ();
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
ddsrt_cond_t * const init_cond = ddsrt_get_singleton_cond ();
ddsrt_mutex_lock (init_mutex);
if (dds_global.m_init_count++ != 0)
uint32_t s = ddsrt_atomic_ld32 (&dds_state);
while (s != CDDS_STATE_ZERO && !cyclonedds_entity_ready (s))
{
ddsrt_cond_wait (init_cond, init_mutex);
s = ddsrt_atomic_ld32 (&dds_state);
}
switch (s)
{
case CDDS_STATE_READY:
assert (dds_global.m_entity.m_hdllink.hdl == DDS_CYCLONEDDS_HANDLE);
ddsrt_mutex_unlock (init_mutex);
return DDS_RETCODE_OK;
case CDDS_STATE_ZERO:
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STARTING);
break;
default:
ddsrt_mutex_unlock (init_mutex);
ddsrt_fini ();
return DDS_RETCODE_ERROR;
}
ddsrt_mutex_init (&dds_global.m_mutex);
ddsrt_cond_init (&dds_global.m_cond);
ddsi_iid_init ();
thread_states_init_static ();
thread_states_init (64);
upgrade_main_thread ();
if (dds_handle_server_init () != DDS_RETCODE_OK)
{
@ -63,30 +119,48 @@ dds_return_t dds_init (void)
goto fail_handleserver;
}
dds_entity_init (&dds_global.m_entity, NULL, DDS_KIND_CYCLONEDDS, 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);
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_READY);
ddsrt_mutex_unlock (init_mutex);
return DDS_RETCODE_OK;
fail_handleserver:
ddsrt_mutex_destroy (&dds_global.m_mutex);
dds_global.m_init_count--;
common_cleanup ();
ddsrt_mutex_unlock (init_mutex);
ddsrt_fini ();
return ret;
}
extern void dds_fini (void)
static void dds_close (struct dds_entity *e)
{
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
ddsrt_mutex_lock (init_mutex);
assert (dds_global.m_init_count > 0);
if (--dds_global.m_init_count == 0)
{
dds_handle_server_fini ();
downgrade_main_thread ();
thread_states_fini ();
ddsi_iid_fini ();
ddsrt_mutex_destroy (&dds_global.m_mutex);
(void) e;
assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_READY);
ddsrt_atomic_st32 (&dds_state, CDDS_STATE_STOPPING);
}
static dds_return_t dds_fini (struct dds_entity *e)
{
(void) e;
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
/* If there are multiple domains shutting down simultaneously, the one "deleting" the top-level
entity (and thus arriving here) may have overtaken another thread that is still in the process
of deleting its domain object. For most entities such races are not an issue, but here we tear
down the run-time, so here we must wait until everyone else is out. */
ddsrt_mutex_lock (&dds_global.m_mutex);
while (!ddsrt_avl_is_empty (&dds_global.m_domains))
ddsrt_cond_wait (&dds_global.m_cond, &dds_global.m_mutex);
ddsrt_mutex_unlock (&dds_global.m_mutex);
ddsrt_mutex_lock (init_mutex);
assert (ddsrt_atomic_ld32 (&dds_state) == CDDS_STATE_STOPPING);
dds_entity_final_deinit_before_free (e);
common_cleanup ();
ddsrt_mutex_unlock (init_mutex);
ddsrt_fini ();
return DDS_RETCODE_NO_DATA;
}

View file

@ -16,7 +16,7 @@
#include "dds__entity.h"
#include "dds__write.h"
#include "dds__writer.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds/ddsi/q_entity.h"

View file

@ -27,15 +27,14 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
{
dds_writer *wr;
dds_return_t rc;
if (rds == NULL && nrds > 0)
if ((rds != NULL && (nrds == 0 || nrds > INT32_MAX)) || (rds == NULL && nrds != 0))
return DDS_RETCODE_BAD_PARAMETER;
if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK)
return rc;
else
{
const struct ephash *gh = wr->m_entity.m_domain->gv.guid_hash;
const int32_t nrds_max = (nrds > INT32_MAX) ? INT32_MAX : (int32_t) nrds;
int32_t nrds_act = 0;
size_t nrds_act = 0;
ddsrt_avl_iter_t it;
/* FIXME: this ought not be so tightly coupled to the lower layer */
thread_state_awake (lookup_thread_state (), &wr->m_entity.m_domain->gv);
@ -47,7 +46,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
struct proxy_reader *prd;
if ((prd = ephash_lookup_proxy_reader_guid (gh, &m->prd_guid)) != NULL)
{
if (nrds_act < nrds_max)
if (nrds_act < nrds)
rds[nrds_act] = prd->e.iid;
nrds_act++;
}
@ -59,7 +58,7 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (gh, &m->rd_guid)) != NULL)
{
if (nrds_act < nrds_max)
if (nrds_act < nrds)
rds[nrds_act] = rd->e.iid;
nrds_act++;
}
@ -67,7 +66,10 @@ dds_return_t dds_get_matched_subscriptions (dds_entity_t writer, dds_instance_ha
ddsrt_mutex_unlock (&wr->m_wr->e.lock);
thread_state_asleep (lookup_thread_state ());
dds_writer_unlock (wr);
return nrds_act;
/* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
(in practice it'll come to a halt long before that) */
assert (nrds_act <= INT32_MAX);
return (dds_return_t) nrds_act;
}
}
@ -75,15 +77,14 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
{
dds_reader *rd;
dds_return_t rc;
if (wrs == NULL && nwrs > 0)
if ((wrs != NULL && (nwrs == 0 || nwrs > INT32_MAX)) || (wrs == NULL && nwrs != 0))
return DDS_RETCODE_BAD_PARAMETER;
if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK)
return rc;
else
{
const struct ephash *gh = rd->m_entity.m_domain->gv.guid_hash;
const int32_t nwrs_max = (nwrs > INT32_MAX) ? INT32_MAX : (int32_t) nwrs;
int32_t nwrs_act = 0;
size_t nwrs_act = 0;
ddsrt_avl_iter_t it;
/* FIXME: this ought not be so tightly coupled to the lower layer */
thread_state_awake (lookup_thread_state (), &rd->m_entity.m_domain->gv);
@ -95,7 +96,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
struct proxy_writer *pwr;
if ((pwr = ephash_lookup_proxy_writer_guid (gh, &m->pwr_guid)) != NULL)
{
if (nwrs_act < nwrs_max)
if (nwrs_act < nwrs)
wrs[nwrs_act] = pwr->e.iid;
nwrs_act++;
}
@ -107,7 +108,7 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
struct writer *wr;
if ((wr = ephash_lookup_writer_guid (gh, &m->wr_guid)) != NULL)
{
if (nwrs_act < nwrs_max)
if (nwrs_act < nwrs)
wrs[nwrs_act] = wr->e.iid;
nwrs_act++;
}
@ -115,14 +116,17 @@ dds_return_t dds_get_matched_publications (dds_entity_t reader, dds_instance_han
ddsrt_mutex_unlock (&rd->m_rd->e.lock);
thread_state_asleep (lookup_thread_state ());
dds_reader_unlock (rd);
return nwrs_act;
/* FIXME: is it really true that there can not be more than INT32_MAX matching readers?
(in practice it'll come to a halt long before that) */
assert (nwrs_act <= INT32_MAX);
return (dds_return_t) nwrs_act;
}
}
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const nn_guid_t *guid, const nn_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_t *guid, const ddsi_guid_t *ppguid, dds_instance_handle_t ppiid, const dds_qos_t *qos)
{
dds_builtintopic_endpoint_t *ep;
nn_guid_t tmp;
ddsi_guid_t tmp;
ep = dds_alloc (sizeof (*ep));
tmp = nn_hton_guid (*guid);
memcpy (&ep->key, &tmp, sizeof (ep->key));

View file

@ -12,11 +12,13 @@
#include <assert.h>
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
#include "dds__init.h"
#include "dds__domain.h"
#include "dds__participant.h"
@ -42,14 +44,7 @@ static dds_return_t dds_participant_delete (dds_entity *e)
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
if ((ret = delete_participant (&e->m_domain->gv, &e->m_guid)) < 0)
DDS_CERROR (&e->m_domain->gv.logconfig, "dds_participant_delete: internal error %"PRId32"\n", ret);
ddsrt_mutex_lock (&dds_global.m_mutex);
ddsrt_avl_delete (&dds_entity_children_td, &e->m_domain->m_ppants, e);
ddsrt_mutex_unlock (&dds_global.m_mutex);
thread_state_asleep (lookup_thread_state ());
/* Every dds_init needs a dds_fini. */
dds_domain_free (e->m_domain);
dds_fini ();
return DDS_RETCODE_OK;
}
@ -74,6 +69,7 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos
}
const struct dds_entity_deriver dds_entity_deriver_participant = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_participant_delete,
.set_qos = dds_participant_qos_set,
@ -84,16 +80,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
{
dds_domain *dom;
dds_entity_t ret;
nn_guid_t guid;
ddsi_guid_t guid;
dds_participant * pp;
nn_plist_t plist;
dds_qos_t *new_qos = NULL;
char *config = "";
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
if ((ret = dds_domain_create (&dom, domain)) < 0)
(void) ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &config);
if ((ret = dds_domain_create_internal (&dom, domain, true, config)) < 0)
goto err_domain_create;
new_qos = dds_create_qos ();
@ -118,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, NULL, 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, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0)
goto err_entity_init;
pp->m_entity.m_guid = guid;
@ -127,9 +126,14 @@ 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_mutex);
ddsrt_avl_insert (&dds_entity_children_td, &dom->m_ppants, &pp->m_entity);
ddsrt_mutex_unlock (&dds_global.m_mutex);
ddsrt_mutex_lock (&dds_global.m_entity.m_mutex);
dds_entity_register_child (&dom->m_entity, &pp->m_entity);
ddsrt_mutex_unlock (&dds_global.m_entity.m_mutex);
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);
return ret;
err_entity_init:
@ -137,34 +141,33 @@ err_entity_init:
err_new_participant:
err_qos_validation:
dds_delete_qos (new_qos);
dds_domain_free (dom);
dds_delete (dom->m_entity.m_hdllink.hdl);
err_domain_create:
dds_fini ();
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
err_dds_init:
return ret;
}
dds_entity_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
dds_return_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *participants, size_t size)
{
if ((participants != NULL && (size <= 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
return DDS_RETCODE_BAD_PARAMETER;
dds_return_t ret;
ddsrt_init ();
ddsrt_mutex_t * const init_mutex = ddsrt_get_singleton_mutex ();
if ((participants != NULL && (size == 0 || size >= INT32_MAX)) || (participants == NULL && size != 0))
return DDS_RETCODE_BAD_PARAMETER;
if (participants)
participants[0] = 0;
dds_return_t ret = 0;
ddsrt_mutex_lock (init_mutex);
if (dds_global.m_init_count > 0)
{
if ((ret = dds_init ()) < 0)
return ret;
ret = 0;
struct dds_domain *dom;
ddsrt_mutex_lock (&dds_global.m_mutex);
if ((dom = dds_domain_find_locked (domain_id)) != NULL)
{
ddsrt_avl_iter_t it;
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_ppants, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
for (dds_entity *e = ddsrt_avl_iter_first (&dds_entity_children_td, &dom->m_entity.m_children, &it); e != NULL; e = ddsrt_avl_iter_next (&it))
{
if ((size_t) ret < size)
participants[ret] = e->m_hdllink.hdl;
@ -172,8 +175,6 @@ dds_entity_t dds_lookup_participant (dds_domainid_t domain_id, dds_entity_t *par
}
}
ddsrt_mutex_unlock (&dds_global.m_mutex);
}
ddsrt_mutex_unlock (init_mutex);
ddsrt_fini ();
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return ret;
}

View file

@ -38,6 +38,7 @@ static dds_return_t dds_publisher_status_validate (uint32_t mask)
}
const struct dds_entity_deriver dds_entity_deriver_publisher = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_entity_deriver_dummy_delete,
.set_qos = dds_publisher_qos_set,
@ -69,6 +70,7 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo
hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, 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);
dds_participant_unlock (par);
return hdl;
}

View file

@ -33,8 +33,9 @@ dds_entity_t dds_create_querycondition (dds_entity_t reader, uint32_t mask, dds_
dds_entity_t hdl;
dds_readcond *cond = dds_create_readcond (r, DDS_KIND_COND_QUERY, mask, filter);
assert (cond);
dds_reader_unlock (r);
hdl = cond->m_entity.m_hdllink.hdl;
dds_entity_init_complete (&cond->m_entity);
dds_reader_unlock (r);
return hdl;
}
}

View file

@ -14,7 +14,7 @@
#include "dds__entity.h"
#include "dds__reader.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_ephash.h"
#include "dds/ddsi/q_entity.h"
@ -130,7 +130,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition,
if (nodata_cleanups & NC_CLEAR_LOAN_OUT)
rd->m_loan_out = false;
if (nodata_cleanups & NC_FREE_BUF)
ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf[0], maxs, DDS_FREE_ALL);
ddsi_sertopic_free_samples (rd->m_topic->m_stopic, buf, maxs, DDS_FREE_ALL);
if (nodata_cleanups & NC_RESET_BUF)
buf[0] = NULL;
ddsrt_mutex_unlock (&rd->m_entity.m_mutex);

View file

@ -12,7 +12,7 @@
#include <assert.h>
#include "dds__reader.h"
#include "dds__readcond.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__entity.h"
#include "dds/ddsi/ddsi_iid.h"
#include "dds/ddsi/q_ephash.h"
@ -23,11 +23,14 @@ static dds_return_t dds_readcond_delete (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_readcond_delete (dds_entity *e)
{
dds_rhc_remove_readcondition ((dds_readcond *) e);
struct dds_reader * const rd = (struct dds_reader *) e->m_parent;
assert (dds_entity_kind (&rd->m_entity) == DDS_KIND_READER);
dds_rhc_remove_readcondition (rd->m_rhc, (dds_readcond *) e);
return DDS_RETCODE_OK;
}
const struct dds_entity_deriver dds_entity_deriver_readcondition = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_readcond_delete,
.set_qos = dds_entity_deriver_dummy_set_qos,
@ -41,17 +44,15 @@ dds_readcond *dds_create_readcond (dds_reader *rd, dds_entity_kind_t kind, uint3
(void) dds_entity_init (&cond->m_entity, &rd->m_entity, kind, NULL, NULL, 0);
cond->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&rd->m_entity, &cond->m_entity);
cond->m_rhc = rd->m_rhc;
cond->m_sample_states = mask & DDS_ANY_SAMPLE_STATE;
cond->m_view_states = mask & DDS_ANY_VIEW_STATE;
cond->m_instance_states = mask & DDS_ANY_INSTANCE_STATE;
cond->m_rd_guid = rd->m_entity.m_guid;
if (kind == DDS_KIND_COND_QUERY)
{
cond->m_query.m_filter = filter;
cond->m_query.m_qcmask = 0;
}
if (!dds_rhc_add_readcondition (cond))
if (!dds_rhc_add_readcondition (rd->m_rhc, cond))
{
/* FIXME: current entity management code can't deal with an error late in the creation of the
entity because it doesn't allow deleting it again ... */
@ -72,6 +73,7 @@ dds_entity_t dds_create_readcondition (dds_entity_t reader, uint32_t mask)
dds_readcond *cond = dds_create_readcond(rd, DDS_KIND_COND_READ, mask, 0);
assert (cond);
hdl = cond->m_entity.m_hdllink.hdl;
dds_entity_init_complete (&cond->m_entity);
dds_reader_unlock (rd);
return hdl;
}

View file

@ -18,7 +18,7 @@
#include "dds__reader.h"
#include "dds__listener.h"
#include "dds__init.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__rhc_default.h"
#include "dds__topic.h"
#include "dds__get_status.h"
@ -40,16 +40,21 @@ DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
DDS_SAMPLE_LOST_STATUS |\
DDS_SUBSCRIPTION_MATCHED_STATUS)
static dds_return_t dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_reader_close (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_reader_close (dds_entity *e)
static void dds_reader_close (dds_entity *e)
{
dds_return_t ret = DDS_RETCODE_OK;
struct dds_reader * const rd = (struct dds_reader *) e;
assert (rd->m_rd != NULL);
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
if (delete_reader (&e->m_domain->gv, &e->m_guid) != 0)
ret = DDS_RETCODE_ERROR;
(void) delete_reader (&e->m_domain->gv, &e->m_guid);
thread_state_asleep (lookup_thread_state ());
return ret;
ddsrt_mutex_lock (&e->m_mutex);
while (rd->m_rd != NULL)
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
ddsrt_mutex_unlock (&e->m_mutex);
}
static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all;
@ -57,17 +62,12 @@ 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;
dds_return_t ret;
if ((ret = dds_delete (rd->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
{
/* Delete an implicitly created parent; for normal ones, this is expected
to fail with BAD_PARAMETER - FIXME: there must be a cleaner way */
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
if (ret == DDS_RETCODE_BAD_PARAMETER)
ret = DDS_RETCODE_OK;
}
(void) dds_delete (rd->m_topic->m_entity.m_hdllink.hdl);
dds_free (rd->m_loan);
return ret;
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
dds_rhc_free (rd->m_rhc);
thread_state_asleep (lookup_thread_state ());
return DDS_RETCODE_OK;
}
static dds_return_t dds_reader_qos_set (dds_entity *e, const dds_qos_t *qos, bool enabled)
@ -97,11 +97,14 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
overhead really matters. Otherwise, it is pretty much like
dds_reader_status_cb. */
const bool data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
if (!data_av_enabled)
const uint32_t data_av_enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & (DDS_DATA_AVAILABLE_STATUS << SAM_ENABLED_SHIFT));
if (data_av_enabled == 0)
return;
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
rd->m_entity.m_cb_pending_count++;
/* FIXME: why wait if no listener is set? */
while (rd->m_entity.m_cb_count > 0)
ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
rd->m_entity.m_cb_count++;
@ -111,8 +114,11 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
if (lst->on_data_on_readers)
{
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
ddsrt_mutex_lock (&sub->m_observers_lock);
const uint32_t data_on_rds_enabled = (ddsrt_atomic_ld32 (&sub->m_status.m_status_and_mask) & (DDS_DATA_ON_READERS_STATUS << SAM_ENABLED_SHIFT));
if (data_on_rds_enabled)
{
sub->m_cb_pending_count++;
while (sub->m_cb_count > 0)
ddsrt_cond_wait (&sub->m_observers_cond, &sub->m_observers_lock);
sub->m_cb_count++;
@ -120,11 +126,13 @@ void dds_reader_data_available_cb (struct dds_reader *rd)
lst->on_data_on_readers (sub->m_hdllink.hdl, lst->on_data_on_readers_arg);
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
ddsrt_mutex_lock (&sub->m_observers_lock);
sub->m_cb_count--;
sub->m_cb_pending_count--;
ddsrt_cond_broadcast (&sub->m_observers_cond);
}
ddsrt_mutex_unlock (&sub->m_observers_lock);
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
}
else if (rd->m_entity.m_listener.on_data_available)
{
@ -141,24 +149,28 @@ 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);
}
void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
{
struct dds_entity * const entity = ventity;
dds_reader * const rd = ventity;
/* When data is NULL, it means that the DDSI reader is deleted. */
if (data == NULL)
{
/* Release the initial claim that was done during the create. This
* will indicate that further API deletion is now possible. */
dds_handle_unpin (&entity->m_hdllink);
ddsrt_mutex_lock (&rd->m_entity.m_mutex);
rd->m_rd = NULL;
ddsrt_cond_broadcast (&rd->m_entity.m_cond);
ddsrt_mutex_unlock (&rd->m_entity.m_mutex);
return;
}
struct dds_listener const * const lst = &entity->m_listener;
struct dds_listener const * const lst = &rd->m_entity.m_listener;
enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
bool invoke = false;
void *vst = NULL;
@ -175,13 +187,12 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
m_observers_lock for the duration of the listener call itself,
and that similarly the listener function and argument pointers
are stable */
ddsrt_mutex_lock (&entity->m_observers_lock);
while (entity->m_cb_count > 0)
ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
entity->m_cb_count++;
/* FIXME: why do this if no listener is set? */
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
while (rd->m_entity.m_cb_count > 0)
ddsrt_cond_wait (&rd->m_entity.m_observers_cond, &rd->m_entity.m_observers_lock);
/* Update status metrics. */
dds_reader * const rd = (dds_reader *) entity;
switch (status_id) {
case DDS_REQUESTED_DEADLINE_MISSED_STATUS_ID: {
struct dds_requested_deadline_missed_status * const st = vst = &rd->m_requested_deadline_missed_status;
@ -265,36 +276,46 @@ void dds_reader_status_cb (void *ventity, const status_cb_data_t *data)
assert (0);
}
if (invoke)
const uint32_t enabled = (ddsrt_atomic_ld32 (&rd->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
if (!enabled)
{
ddsrt_mutex_unlock (&entity->m_observers_lock);
dds_entity_invoke_listener (entity, status_id, vst);
ddsrt_mutex_lock (&entity->m_observers_lock);
/* Don't invoke listeners or set status flag if masked */
}
else if (invoke)
{
rd->m_entity.m_cb_pending_count++;
rd->m_entity.m_cb_count++;
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
dds_entity_invoke_listener (&rd->m_entity, status_id, vst);
ddsrt_mutex_lock (&rd->m_entity.m_observers_lock);
rd->m_entity.m_cb_count--;
rd->m_entity.m_cb_pending_count--;
*reset[0] = 0;
if (reset[1])
*reset[1] = 0;
}
else
{
dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
dds_entity_status_set (&rd->m_entity, (status_mask_t) (1u << status_id));
}
entity->m_cb_count--;
ddsrt_cond_broadcast (&entity->m_observers_cond);
ddsrt_mutex_unlock (&entity->m_observers_lock);
ddsrt_cond_broadcast (&rd->m_entity.m_observers_cond);
ddsrt_mutex_unlock (&rd->m_entity.m_observers_lock);
}
const struct dds_entity_deriver dds_entity_deriver_reader = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_reader_close,
.delete = dds_reader_delete,
.set_qos = dds_reader_qos_set,
.validate_status = dds_reader_status_validate
};
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
{
dds_qos_t *rqos;
dds_subscriber *sub = NULL;
dds_participant *pp;
dds_entity_t subscriber;
dds_reader *rd;
dds_topic *tp;
@ -347,8 +368,12 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
goto err_tp_lock;
}
assert (tp->m_stopic);
/* FIXME: domain check */
assert (sub->m_entity.m_domain == tp->m_entity.m_domain);
pp = dds_entity_participant (&sub->m_entity);
if (pp != dds_entity_participant (&tp->m_entity))
{
reader = DDS_RETCODE_BAD_PARAMETER;
goto err_pp_mismatch;
}
/* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null
argument, but that isn't the case here */
@ -378,25 +403,26 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
goto err_bad_qos;
}
/* Create reader and associated read cache */
/* 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);
rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED;
rd->m_topic = tp;
rd->m_rhc = dds_rhc_default_new (rd, tp->m_stopic);
rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stopic);
if (dds_rhc_associate (rd->m_rhc, rd, tp->m_stopic, rd->m_entity.m_domain->gv.m_tkmap) < 0)
{
/* FIXME: see also create_querycond, need to be able to undo entity_init */
abort ();
}
dds_entity_add_ref_locked (&tp->m_entity);
/* Extra claim of this reader to make sure that the delete waits until DDSI
has deleted its reader as well. This can be known through the callback. */
dds_handle_repin (&rd->m_entity.m_hdllink);
ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
ddsrt_mutex_unlock (&sub->m_entity.m_mutex);
/* FIXME: listeners can come too soon ... should set mask based on listeners
then atomically set the listeners, save the mask to a pending set and clear
it; and then invoke those listeners that are in the pending set */
dds_entity_init_complete (&rd->m_entity);
thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv);
ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &sub->m_entity.m_participant->m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
ddsrt_mutex_lock (&sub->m_entity.m_mutex);
ddsrt_mutex_lock (&tp->m_entity.m_mutex);
ret = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
assert (ret == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */
thread_state_asleep (lookup_thread_state ());
@ -414,6 +440,7 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti
return reader;
err_bad_qos:
err_pp_mismatch:
dds_topic_unlock (tp);
err_tp_lock:
dds_subscriber_unlock (sub);
@ -438,7 +465,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
dds_reader *dds_rd = (dds_reader *) dds_entity;
struct reader *rd = dds_rd->m_rd;
nn_guid_t pwrguid;
ddsi_guid_t pwrguid;
struct proxy_writer *pwr;
struct rd_pwr_match *m;
memset (&pwrguid, 0, sizeof (pwrguid));
@ -451,7 +478,7 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
/* have to be careful walking the tree -- pretty is different, but
I want to check this before I write a lookup_succ function. */
struct rd_pwr_match *m_next;
nn_guid_t pwrguid_next;
ddsi_guid_t pwrguid_next;
pwrguid = m->pwr_guid;
if ((m_next = ddsrt_avl_find_succ (&rd_writers_treedef, &rd->writers, m)) != NULL)
pwrguid_next = m_next->pwr_guid;
@ -475,6 +502,18 @@ void dds_reader_ddsi2direct (dds_entity_t entity, ddsi2direct_directread_cb_t cb
dds_entity_unpin (dds_entity);
}
dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener)
{
return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, NULL);
}
dds_entity_t dds_create_reader_rhc (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc)
{
if (rhc == NULL)
return DDS_RETCODE_BAD_PARAMETER;
return dds_create_reader_int (participant_or_subscriber, topic, qos, listener, rhc);
}
uint32_t dds_reader_lock_samples (dds_entity_t reader)
{
dds_reader *rd;

View file

@ -11,17 +11,18 @@
*/
#include "dds/dds.h"
#include "dds/ddsi/q_rhc.h"
#include "dds__rhc.h"
#include "dds/ddsi/ddsi_rhc.h"
#include "dds/ddsc/dds_rhc.h"
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
extern inline dds_return_t dds_rhc_associate (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap);
extern inline bool dds_rhc_store (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
extern inline void dds_rhc_unregister_wr (struct dds_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict pwr_info);
extern inline void dds_rhc_relinquish_ownership (struct dds_rhc * __restrict rhc, const uint64_t wr_iid);
extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *qos);
extern inline void dds_rhc_free (struct dds_rhc *rhc);
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond);
extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
extern inline bool dds_rhc_add_readcondition (struct dds_readcond *cond);
extern inline void dds_rhc_remove_readcondition (struct dds_readcond *cond);
extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond);
extern inline uint32_t dds_rhc_lock_samples (struct dds_rhc *rhc);

View file

@ -25,12 +25,12 @@
#include "dds__entity.h"
#include "dds__reader.h"
#include "dds__rhc.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds__rhc_default.h"
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsrt/hopscotch.h"
#include "dds/ddsrt/avl.h"
#include "dds/ddsi/q_rhc.h"
#include "dds/ddsi/ddsi_rhc.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/q_unused.h"
#include "dds/ddsi/q_config.h"
@ -263,7 +263,7 @@ struct rhc_instance {
uint32_t disposed_gen; /* bloody generation counters - worst invention of mankind */
uint32_t no_writers_gen; /* __/ */
int32_t strength; /* "current" ownership strength */
nn_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
ddsi_guid_t wr_guid; /* guid of last writer (if wr_iid != 0 then wr_guid is the corresponding guid, else undef) */
nn_wctime_t tstamp; /* source time stamp of last update */
struct rhc_instance *next; /* next non-empty instance in arbitrary ordering */
struct rhc_instance *prev;
@ -346,30 +346,30 @@ struct trigger_info_post {
};
static void dds_rhc_default_free (struct dds_rhc_default *rhc);
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid);
static void dds_rhc_default_set_qos (struct dds_rhc_default *rhc, const struct dds_qos *qos);
static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond);
static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle);
static bool dds_rhc_default_add_readcondition (dds_readcond *cond);
static void dds_rhc_default_remove_readcondition (dds_readcond *cond);
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond);
static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc);
static void dds_rhc_default_free_wrap (struct rhc *rhc) {
static void dds_rhc_default_free_wrap (struct ddsi_rhc *rhc) {
dds_rhc_default_free ((struct dds_rhc_default *) rhc);
}
static bool dds_rhc_default_store_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return dds_rhc_default_store ((struct dds_rhc_default *) rhc, pwr_info, sample, tk);
static bool dds_rhc_default_store_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return dds_rhc_default_store ((struct dds_rhc_default *) rhc, wrinfo, sample, tk);
}
static void dds_rhc_default_unregister_wr_wrap (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, pwr_info);
static void dds_rhc_default_unregister_wr_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, wrinfo);
}
static void dds_rhc_default_relinquish_ownership_wrap (struct rhc * __restrict rhc, const uint64_t wr_iid) {
static void dds_rhc_default_relinquish_ownership_wrap (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) {
dds_rhc_default_relinquish_ownership ((struct dds_rhc_default *) rhc, wr_iid);
}
static void dds_rhc_default_set_qos_wrap (struct rhc *rhc, const struct dds_qos *qos) {
static void dds_rhc_default_set_qos_wrap (struct ddsi_rhc *rhc, const struct dds_qos *qos) {
dds_rhc_default_set_qos ((struct dds_rhc_default *) rhc, qos);
}
static int dds_rhc_default_read_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) {
@ -381,15 +381,21 @@ static int dds_rhc_default_take_wrap (struct dds_rhc *rhc, bool lock, void **val
static int dds_rhc_default_takecdr_wrap (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) {
return dds_rhc_default_takecdr ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle);
}
static bool dds_rhc_default_add_readcondition_wrap (dds_readcond *cond) {
return dds_rhc_default_add_readcondition (cond);
static bool dds_rhc_default_add_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
return dds_rhc_default_add_readcondition ((struct dds_rhc_default *) rhc, cond);
}
static void dds_rhc_default_remove_readcondition_wrap (dds_readcond *cond) {
dds_rhc_default_remove_readcondition (cond);
static void dds_rhc_default_remove_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) {
dds_rhc_default_remove_readcondition ((struct dds_rhc_default *) rhc, cond);
}
static uint32_t dds_rhc_default_lock_samples_wrap (struct dds_rhc *rhc) {
return dds_rhc_default_lock_samples ((struct dds_rhc_default *) rhc);
}
static dds_return_t dds_rhc_default_associate (struct dds_rhc *rhc, dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap)
{
/* ignored out of laziness */
(void) rhc; (void) reader; (void) topic; (void) tkmap;
return DDS_RETCODE_OK;
}
static const struct dds_rhc_ops dds_rhc_default_ops = {
.rhc_ops = {
@ -404,7 +410,8 @@ static const struct dds_rhc_ops dds_rhc_default_ops = {
.takecdr = dds_rhc_default_takecdr_wrap,
.add_readcondition = dds_rhc_default_add_readcondition_wrap,
.remove_readcondition = dds_rhc_default_remove_readcondition_wrap,
.lock_samples = dds_rhc_default_lock_samples_wrap
.lock_samples = dds_rhc_default_lock_samples_wrap,
.associate = dds_rhc_default_associate
};
static unsigned qmask_of_sample (const struct rhc_sample *s)
@ -758,7 +765,7 @@ static bool trigger_info_differs (const struct dds_rhc_default *rhc, const struc
trig_qc->dec_sample_read != trig_qc->inc_sample_read);
}
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc)
{
struct rhc_sample *s;
@ -832,7 +839,7 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst,
}
s->sample = ddsi_serdata_ref (sample); /* drops const (tho refcount does change) */
s->wr_iid = pwr_info->iid;
s->wr_iid = wrinfo->iid;
s->isread = false;
s->disposed_gen = inst->disposed_gen;
s->no_writers_gen = inst->no_writers_gen;
@ -867,12 +874,12 @@ static bool content_filter_accepts (const dds_reader *reader, const struct ddsi_
return ret;
}
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info)
static int inst_accepts_sample_by_writer_guid (const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo)
{
return (inst->wr_iid_islive && inst->wr_iid == pwr_info->iid) || memcmp (&pwr_info->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
return (inst->wr_iid_islive && inst->wr_iid == wrinfo->iid) || memcmp (&wrinfo->guid, &inst->wr_guid, sizeof (inst->wr_guid)) < 0;
}
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct proxy_writer_info *pwr_info, const struct ddsi_serdata *sample, const bool has_data)
static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, const bool has_data)
{
if (rhc->by_source_ordering)
{
@ -884,7 +891,7 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
{
return 0;
}
else if (inst_accepts_sample_by_writer_guid (inst, pwr_info))
else if (inst_accepts_sample_by_writer_guid (inst, wrinfo))
{
/* ok */
}
@ -893,14 +900,14 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
return 0;
}
}
if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != pwr_info->iid)
if (rhc->exclusive_ownership && inst->wr_iid_islive && inst->wr_iid != wrinfo->iid)
{
int32_t strength = pwr_info->ownership_strength;
int32_t strength = wrinfo->ownership_strength;
if (strength > inst->strength) {
/* ok */
} else if (strength < inst->strength) {
return 0;
} else if (inst_accepts_sample_by_writer_guid (inst, pwr_info)) {
} else if (inst_accepts_sample_by_writer_guid (inst, wrinfo)) {
/* ok */
} else {
return 0;
@ -913,17 +920,17 @@ static int inst_accepts_sample (const struct dds_rhc_default *rhc, const struct
return 1;
}
static void update_inst (struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, bool wr_iid_valid, nn_wctime_t tstamp)
static void update_inst (struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, bool wr_iid_valid, nn_wctime_t tstamp)
{
inst->tstamp = tstamp;
inst->wr_iid_islive = wr_iid_valid;
if (wr_iid_valid)
{
inst->wr_iid = pwr_info->iid;
if (inst->wr_iid != pwr_info->iid)
inst->wr_guid = pwr_info->guid;
inst->wr_iid = wrinfo->iid;
if (inst->wr_iid != wrinfo->iid)
inst->wr_guid = wrinfo->guid;
}
inst->strength = pwr_info->ownership_strength;
inst->strength = wrinfo->ownership_strength;
}
static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst)
@ -1109,13 +1116,13 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons
}
}
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda)
{
assert (inst->wrcount > 0);
if (--inst->wrcount > 0)
{
if (inst->wr_iid_islive && pwr_info->iid == inst->wr_iid)
if (inst->wr_iid_islive && wrinfo->iid == inst->wr_iid)
{
/* Next register will have to do real work before we have a cached
wr_iid again */
@ -1142,7 +1149,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
if (inst->latest == NULL || inst->latest->isread)
{
inst_set_invsample (rhc, inst, trig_qc, nda);
update_inst (inst, pwr_info, false, tstamp);
update_inst (inst, wrinfo, false, tstamp);
}
if (!inst->isdisposed)
{
@ -1164,7 +1171,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
TRACE (",#0,empty,nowriters");
assert (inst_is_empty (inst));
inst_set_invsample (rhc, inst, trig_qc, nda);
update_inst (inst, pwr_info, false, tstamp);
update_inst (inst, wrinfo, false, tstamp);
account_for_empty_to_nonempty_transition (rhc, inst);
inst->wr_iid_islive = 0;
return 0;
@ -1172,18 +1179,18 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in
}
}
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct proxy_writer_info * __restrict pwr_info, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, nn_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
{
bool notify_data_available = false;
/* 'post' always gets set; instance may have been freed upon return. */
TRACE (" unregister:");
if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, pwr_info->iid))
if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, wrinfo->iid))
{
/* other registrations remain */
get_trigger_info_cmn (&post->c, inst);
}
else if (rhc_unregister_updateinst (rhc, inst, pwr_info, tstamp, trig_qc, &notify_data_available))
else if (rhc_unregister_updateinst (rhc, inst, wrinfo, tstamp, trig_qc, &notify_data_available))
{
/* instance dropped */
init_trigger_info_cmn_nonmatch (&post->c);
@ -1196,7 +1203,7 @@ static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance
return notify_data_available;
}
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk)
{
struct rhc_instance *inst;
@ -1210,11 +1217,11 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
inst->isnew = 1;
inst->a_sample_free = 1;
inst->conds = 0;
inst->wr_iid = pwr_info->iid;
inst->wr_iid = wrinfo->iid;
inst->wr_iid_islive = (inst->wrcount != 0);
inst->wr_guid = pwr_info->guid;
inst->wr_guid = wrinfo->guid;
inst->tstamp = serdata->timestamp;
inst->strength = pwr_info->ownership_strength;
inst->strength = wrinfo->ownership_strength;
if (rhc->nqconds != 0)
{
@ -1230,7 +1237,7 @@ static struct rhc_instance *alloc_new_instance (const struct dds_rhc_default *rh
return inst;
}
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc)
{
struct rhc_instance *inst;
int ret;
@ -1265,10 +1272,10 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
return RHC_REJECTED;
}
inst = alloc_new_instance (rhc, pwr_info, sample, tk);
inst = alloc_new_instance (rhc, wrinfo, sample, tk);
if (has_data)
{
if (!add_sample (rhc, inst, pwr_info, sample, cb_data, trig_qc))
if (!add_sample (rhc, inst, wrinfo, sample, cb_data, trig_qc))
{
free_empty_instance (inst, rhc);
return RHC_REJECTED;
@ -1298,9 +1305,9 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst
delivered (true unless a reliable sample rejected).
*/
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk)
{
const uint64_t wr_iid = pwr_info->iid;
const uint64_t wr_iid = wrinfo->iid;
const unsigned statusinfo = sample->statusinfo;
const bool has_data = (sample->kind == SDK_DATA);
const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0;
@ -1347,7 +1354,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
else
{
TRACE (" new instance");
stored = rhc_store_new_instance (&inst, rhc, pwr_info, sample, tk, has_data, &cb_data, &post, &trig_qc);
stored = rhc_store_new_instance (&inst, rhc, wrinfo, sample, tk, has_data, &cb_data, &post, &trig_qc);
if (stored != RHC_STORED)
{
goto error_or_nochange;
@ -1356,7 +1363,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
notify_data_available = true;
}
}
else if (!inst_accepts_sample (rhc, inst, pwr_info, sample, has_data))
else if (!inst_accepts_sample (rhc, inst, wrinfo, sample, has_data))
{
/* Rejected samples (and disposes) should still register the writer;
unregister *must* be processed, or we have a memory leak. (We
@ -1372,7 +1379,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
}
if (statusinfo & NN_STATUSINFO_UNREGISTER)
{
if (dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc))
if (dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc))
notify_data_available = true;
}
else
@ -1450,7 +1457,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
if (has_data)
{
TRACE (" add_sample");
if (!add_sample (rhc, inst, pwr_info, sample, &cb_data, &trig_qc))
if (!add_sample (rhc, inst, wrinfo, sample, &cb_data, &trig_qc))
{
TRACE ("(reject)");
stored = RHC_REJECTED;
@ -1469,7 +1476,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
if (inst_became_disposed && inst->latest == NULL)
inst_set_invsample (rhc, inst, &trig_qc, &notify_data_available);
update_inst (inst, pwr_info, true, sample->timestamp);
update_inst (inst, wrinfo, true, sample->timestamp);
/* Can only add samples => only need to give special treatment
to instances that were empty before. It is, however, not
@ -1513,7 +1520,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons
mean an application reading "x" after the write and reading it
again after the unregister will see a change in the
no_writers_generation field? */
dds_rhc_unregister (rhc, inst, pwr_info, sample->timestamp, &post, &trig_qc);
dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc);
}
else
{
@ -1559,7 +1566,7 @@ error_or_nochange:
return delivered;
}
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info)
static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo)
{
/* Only to be called when writer with ID WR_IID has died.
@ -1579,8 +1586,8 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
bool notify_data_available = false;
struct rhc_instance *inst;
struct ddsrt_hh_iter iter;
const uint64_t wr_iid = pwr_info->iid;
const int auto_dispose = pwr_info->auto_dispose;
const uint64_t wr_iid = wrinfo->iid;
const int auto_dispose = wrinfo->auto_dispose;
size_t ntriggers = SIZE_MAX;
@ -1620,7 +1627,7 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r
}
}
dds_rhc_unregister (rhc, inst, pwr_info, inst->tstamp, &post, &trig_qc);
dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc);
TRACE ("\n");
@ -2292,13 +2299,12 @@ static bool cond_is_sample_state_dependent (const struct dds_readcond *cond)
}
}
static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
{
/* On the assumption that a readcondition will be attached to a
waitset for nearly all of its life, we keep track of all
readconditions on a reader in one set, without distinguishing
between those attached to a waitset or not. */
struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
struct ddsrt_hh_iter it;
assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) ||
@ -2397,9 +2403,8 @@ static bool dds_rhc_default_add_readcondition (dds_readcond *cond)
return true;
}
static void dds_rhc_default_remove_readcondition (dds_readcond *cond)
static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond)
{
struct dds_rhc_default *rhc = (struct dds_rhc_default *) cond->m_rhc;
dds_readcond **ptr;
ddsrt_mutex_lock (&rhc->lock);
ptr = &rhc->conds;

View file

@ -32,7 +32,7 @@ static const uint64_t unihashconsts[] = {
UINT64_C (16728792139623414127)
};
static uint32_t hash_guid (const nn_guid_t *g)
static uint32_t hash_guid (const ddsi_guid_t *g)
{
return
(uint32_t) (((((uint32_t) g->prefix.u[0] + unihashconsts[0]) *
@ -131,7 +131,7 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi
/* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */
const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn;
/* keyhash must in host format (which the GUIDs always are internally) */
struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const nn_guid_t *) keyhash->value);
struct entity_common *entity = ephash_lookup_guid_untyped (tp->gv->guid_hash, (const ddsi_guid_t *) keyhash->value);
struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY);
memcpy (&d->key, keyhash->value, sizeof (d->key));
if (entity)
@ -175,9 +175,9 @@ static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serd
return ddsi_serdata_ref (serdata_common);
}
static void convkey (dds_builtintopic_guid_t *key, const nn_guid_t *guid)
static void convkey (dds_builtintopic_guid_t *key, const ddsi_guid_t *guid)
{
nn_guid_t tmp;
ddsi_guid_t tmp;
tmp = nn_hton_guid (*guid);
memcpy (key, &tmp, sizeof (*key));
}
@ -214,7 +214,7 @@ static bool to_sample_pp (const struct ddsi_serdata_builtintopic *d, struct dds_
static bool to_sample_endpoint (const struct ddsi_serdata_builtintopic *d, struct dds_builtintopic_endpoint *sample)
{
nn_guid_t ppguid;
ddsi_guid_t ppguid;
convkey (&sample->key, &d->key);
ppguid = d->key;
ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
@ -276,6 +276,12 @@ static void serdata_builtin_to_ser_unref (struct ddsi_serdata *serdata_common, c
(void)serdata_common; (void)ref;
}
static size_t serdata_builtin_topic_print (const struct ddsi_sertopic *topic, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
{
(void)topic; (void)serdata_common;
return (size_t) snprintf (buf, size, "(blob)");
}
const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
.get_size = serdata_builtin_get_size,
.eqkey = serdata_builtin_eqkey,
@ -288,5 +294,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = {
.to_ser_ref = serdata_builtin_to_ser_ref,
.to_ser_unref = serdata_builtin_to_ser_unref,
.to_topicless = serdata_builtin_to_topicless,
.topicless_to_sample = serdata_builtin_topicless_to_sample
.topicless_to_sample = serdata_builtin_topicless_to_sample,
.print = serdata_builtin_topic_print
};

View file

@ -11,6 +11,7 @@
*/
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include "dds/ddsrt/endian.h"
#include "dds/ddsrt/md5.h"
@ -1608,6 +1609,292 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t *
}
}
/*******************************************************************************************
**
** Pretty-printing
**
*******************************************************************************************/
/* Returns true if buffer not yet exhausted, false otherwise */
static bool prtf (char * __restrict *buf, size_t * __restrict bufsize, const char *fmt, ...)
{
va_list ap;
if (*bufsize == 0)
return false;
va_start (ap, fmt);
int n = vsnprintf (*buf, *bufsize, fmt, ap);
va_end (ap);
if (n < 0)
{
**buf = 0;
return false;
}
else if ((size_t) n <= *bufsize)
{
*buf += (size_t) n;
*bufsize -= (size_t) n;
return (*bufsize > 0);
}
else
{
*buf += *bufsize;
*bufsize = 0;
return false;
}
}
static bool prtf_str (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is)
{
size_t sz = dds_is_get4 (is);
bool ret = prtf (buf, bufsize, "\"%s\"", is->m_buffer + is->m_index);
is->m_index += (uint32_t) sz;
return ret;
}
static size_t isprint_runlen (const unsigned char *s, size_t n)
{
size_t m;
for (m = 0; m < n && s[m] != '"' && isprint (s[m]); m++)
;
return m;
}
static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type)
{
switch (type)
{
case DDS_OP_VAL_1BY: return prtf (buf, bufsize, "%"PRIu8, dds_is_get1 (is));
case DDS_OP_VAL_2BY: return prtf (buf, bufsize, "%"PRIu16, dds_is_get2 (is));
case DDS_OP_VAL_4BY: return prtf (buf, bufsize, "%"PRIu32, dds_is_get4 (is));
case DDS_OP_VAL_8BY: return prtf (buf, bufsize, "%"PRIu64, dds_is_get8 (is));
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is);
case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
abort ();
}
return false;
}
static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type)
{
bool cont = prtf (buf, bufsize, "{");
switch (type)
{
case DDS_OP_VAL_1BY: {
size_t i = 0, j;
while (cont && i < num)
{
size_t m = isprint_runlen ((unsigned char *) (is->m_buffer + is->m_index), num - i);
if (m >= 4)
{
cont = prtf (buf, bufsize, "%s\"", i != 0 ? "," : "");
for (j = 0; cont && j < m; j++)
cont = prtf (buf, bufsize, "%c", is->m_buffer[is->m_index + j]);
cont = prtf (buf, bufsize, "\"");
is->m_index += (uint32_t) m;
i += m;
}
else
{
if (i != 0)
(void) prtf (buf, bufsize, ",");
cont = prtf_simple (buf, bufsize, is, type);
i++;
}
}
break;
}
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:
for (size_t i = 0; cont && i < num; i++)
{
if (i != 0)
(void) prtf (buf, bufsize, ",");
cont = prtf_simple (buf, bufsize, is, type);
}
break;
default:
abort ();
break;
}
return cont;
}
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces);
static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
{
const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
uint32_t num;
num = dds_is_get4 (is);
if (num == 0)
{
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);
return ops + 2;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
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]);
uint32_t const * const jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]);
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
if (i > 0) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 4); /* FIXME: why would jmp be 0? */
}
}
return NULL;
}
static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
{
const enum dds_stream_typecode subtype = DDS_OP_SUBTYPE (insn);
const uint32_t num = ops[2];
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);
return ops + 3;
case DDS_OP_VAL_STR: case DDS_OP_VAL_BST:
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]);
const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]);
bool cont = prtf (buf, bufsize, "{");
for (uint32_t i = 0; cont && i < num; i++)
{
if (i > 0) prtf (buf, bufsize, ",");
cont = dds_stream_print_sample1 (buf, bufsize, is, jsr_ops, subtype == DDS_OP_VAL_STU);
}
prtf (buf, bufsize, "}");
return ops + (jmp ? jmp : 5);
}
}
return NULL;
}
static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, uint32_t insn)
{
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);
ops += DDS_OP_ADR_JMP (ops[3]);
if (jeq_op)
{
const enum dds_stream_typecode valtype = DDS_JEQ_TYPE (jeq_op[0]);
switch (valtype)
{
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);
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);
break;
}
}
return ops;
}
static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, const uint32_t * __restrict ops, bool add_braces)
{
uint32_t insn;
bool cont = true;
bool needs_comma = false;
if (add_braces)
prtf (buf, bufsize, "{");
while (cont && (insn = *ops) != DDS_OP_RTS)
{
if (needs_comma)
prtf (buf, bufsize, ",");
needs_comma = true;
switch (DDS_OP (insn))
{
case DDS_OP_ADR: {
switch (DDS_OP_TYPE (insn))
{
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:
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
ops += 2;
break;
case DDS_OP_VAL_BST:
cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn));
ops += 3;
break;
case DDS_OP_VAL_SEQ:
ops = prtf_seq (buf, bufsize, is, ops, insn);
break;
case DDS_OP_VAL_ARR:
ops = prtf_arr (buf, bufsize, is, ops, insn);
break;
case DDS_OP_VAL_UNI:
ops = prtf_uni (buf, bufsize, is, ops, insn);
break;
case DDS_OP_VAL_STU:
abort ();
break;
}
break;
}
case DDS_OP_JSR: {
cont = dds_stream_print_sample1 (buf, bufsize, is, ops + DDS_OP_JUMP (insn), true);
ops++;
break;
}
case DDS_OP_RTS: case DDS_OP_JEQ: {
abort ();
break;
}
}
}
if (add_braces)
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);
return bufsize;
}
size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_sertopic_default * __restrict topic, char * __restrict buf, size_t bufsize)
{
const dds_topic_descriptor_t *desc = topic->type;
bool cont = prtf (&buf, &bufsize, ":k:{");
for (uint32_t i = 0; cont && i < desc->m_nkeys; i++)
{
const uint32_t *op = desc->m_ops + desc->m_keys[i].m_index;
assert (insn_key_ok_p (*op));
switch (DDS_OP_TYPE (*op))
{
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:
cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op));
break;
case DDS_OP_VAL_ARR:
cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op));
break;
case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU:
abort ();
break;
}
}
prtf (&buf, &bufsize, "}");
return bufsize;
}
/*******************************************************************************************
**
** Stuff to make it possible to treat a ddsi_serdata_default as a stream

View file

@ -38,6 +38,7 @@ static dds_return_t dds_subscriber_status_validate (uint32_t mask)
}
const struct dds_entity_deriver dds_entity_deriver_subscriber = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_entity_deriver_dummy_delete,
.set_qos = dds_subscriber_qos_set,
@ -66,6 +67,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q
subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, 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);
return subscriber;
}

View file

@ -131,7 +131,7 @@ static bool dds_find_topic_check_and_add_ref (dds_entity_t participant, dds_enti
return false;
bool ret;
if (tp->m_entity.m_participant->m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant || strcmp (tp->m_stopic->name, name) != 0)
ret = false;
else
{
@ -243,7 +243,7 @@ static bool sertopic_equivalent (const struct ddsi_sertopic *a, const struct dds
return true;
}
static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
static dds_return_t create_topic_topic_arbitrary_check_sertopic (dds_entity_t participant, dds_entity_t topic, struct ddsi_sertopic *sertopic, const dds_qos_t *qos)
{
dds_topic *tp;
dds_return_t ret;
@ -251,7 +251,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
if (dds_topic_lock (topic, &tp) < 0)
return DDS_RETCODE_NOT_FOUND;
if (tp->m_entity.m_participant->m_hdllink.hdl != participant)
if (dds_entity_participant (&tp->m_entity)->m_entity.m_hdllink.hdl != participant)
ret = DDS_RETCODE_NOT_FOUND;
else if (!sertopic_equivalent (tp->m_stopic, sertopic))
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
@ -272,6 +272,7 @@ static dds_return_t create_topic_topic_arbirary_check_sertopic (dds_entity_t par
}
const struct dds_entity_deriver dds_entity_deriver_topic = {
.interrupt = dds_entity_deriver_dummy_interrupt,
.close = dds_entity_deriver_dummy_close,
.delete = dds_topic_delete,
.set_qos = dds_topic_qos_set,
@ -296,6 +297,14 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
existing topic's compatibility */
if ((rc = dds_entity_pin (participant, &par_ent)) < 0)
return rc;
/* Verify that we've been given a participant, not strictly necessary
because dds_participant_lock below checks it, but this is more
obvious */
if (dds_entity_kind (par_ent) != DDS_KIND_PARTICIPANT)
{
dds_entity_unpin (par_ent);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
new_qos = dds_create_qos ();
if (qos)
@ -351,7 +360,7 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
for the various scary cases. */
dds_participant_unlock (par);
rc = create_topic_topic_arbirary_check_sertopic (participant, topic, sertopic, new_qos);
rc = create_topic_topic_arbitrary_check_sertopic (participant, topic, sertopic, new_qos);
switch (rc)
{
case DDS_RETCODE_OK: /* duplicate definition */
@ -439,6 +448,8 @@ dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_s
nn_plist_fini (&plist);
}
thread_state_asleep (lookup_thread_state ());
dds_entity_init_complete (&top->m_entity);
dds_participant_unlock (par);
dds_entity_unpin (par_ent);
return hdl;

View file

@ -1,5 +1,5 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
* 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
@ -17,11 +17,10 @@
#include "dds__participant.h"
#include "dds__querycond.h"
#include "dds__readcond.h"
#include "dds__rhc.h"
#include "dds__init.h"
#include "dds/ddsc/dds_rhc.h"
#include "dds/ddsi/ddsi_iid.h"
DEFINE_ENTITY_LOCK_UNLOCK (static, dds_waitset, DDS_KIND_WAITSET)
static bool is_triggered (struct dds_entity *e)
{
bool t;
@ -63,7 +62,7 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
}
/* Move any previously but no longer triggering entities back to the observed list */
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
ddsrt_mutex_lock (&ws->wait_lock);
ws->ntriggered = 0;
for (size_t i = 0; i < ws->nentities; i++)
{
@ -76,83 +75,195 @@ static dds_return_t dds_waitset_wait_impl (dds_entity_t waitset, dds_attach_t *x
}
/* Only wait/keep waiting when we have something to observe and there aren't any triggers yet. */
while (ws->nentities > 0 && ws->ntriggered == 0)
if (!ddsrt_cond_waituntil (&ws->m_entity.m_cond, &ws->m_entity.m_mutex, abstimeout))
while (ws->nentities > 0 && ws->ntriggered == 0 && !dds_handle_is_closed (&ws->m_entity.m_hdllink))
if (!ddsrt_cond_waituntil (&ws->wait_cond, &ws->wait_lock, abstimeout))
break;
ret = (int32_t) ws->ntriggered;
for (size_t i = 0; i < ws->ntriggered && i < nxs; i++)
xs[i] = ws->entities[i].arg;
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
ddsrt_mutex_unlock (&ws->wait_lock);
dds_entity_unpin (&ws->m_entity);
return ret;
}
static dds_return_t dds_waitset_close (struct dds_entity *e)
static void dds_waitset_interrupt (struct dds_entity *e)
{
/* deep in the process of deleting the entity, so this is the only thread */
dds_waitset *ws = (dds_waitset *) e;
for (size_t i = 0; i < ws->nentities; i++)
(void) dds_entity_observer_unregister (ws->entities[i].entity, &ws->m_entity);
return DDS_RETCODE_OK;
ddsrt_mutex_lock (&ws->wait_lock);
assert (dds_handle_is_closed (&ws->m_entity.m_hdllink));
ddsrt_cond_broadcast (&ws->wait_cond);
ddsrt_mutex_unlock (&ws->wait_lock);
}
static void dds_waitset_close (struct dds_entity *e)
{
dds_waitset *ws = (dds_waitset *) e;
ddsrt_mutex_lock (&ws->wait_lock);
while (ws->nentities > 0)
{
dds_entity *observed;
if (dds_entity_pin (ws->entities[0].handle, &observed) < 0)
{
/* can't be pinned => being deleted => will be removed from wait set soon enough
and go through delete_observer (which will trigger the condition variable) */
ddsrt_cond_wait (&ws->wait_cond, &ws->wait_lock);
}
else
{
/* entity will remain in existence */
ddsrt_mutex_unlock (&ws->wait_lock);
(void) dds_entity_observer_unregister (observed, ws, true);
ddsrt_mutex_lock (&ws->wait_lock);
assert (ws->nentities == 0 || ws->entities[0].entity != observed);
dds_entity_unpin (observed);
}
}
ddsrt_mutex_unlock (&ws->wait_lock);
}
static dds_return_t dds_waitset_delete (struct dds_entity *e)
{
/* deep in the process of deleting the entity, so this is the only thread */
dds_waitset *ws = (dds_waitset *) e;
ddsrt_mutex_destroy (&ws->wait_lock);
ddsrt_cond_destroy (&ws->wait_cond);
ddsrt_free (ws->entities);
return DDS_RETCODE_OK;
}
const struct dds_entity_deriver dds_entity_deriver_waitset = {
.interrupt = dds_waitset_interrupt,
.close = dds_waitset_close,
.delete = dds_waitset_delete,
.set_qos = dds_entity_deriver_dummy_set_qos,
.validate_status = dds_entity_deriver_dummy_validate_status
};
dds_entity_t dds_create_waitset (dds_entity_t participant)
dds_entity_t dds_create_waitset (dds_entity_t owner)
{
dds_entity_t hdl;
dds_participant *par;
dds_entity *e;
dds_return_t rc;
if ((rc = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK)
/* If the owner is any ordinary (allowed) entity, the library is already initialised and calling
init here is cheap. If it is DDS_CYCLONEDDS_HANDLE, we may have to initialise the library, so
have to call it. If it is some bogus value and the library is not initialised yet ... so be
it. Naturally, this requires us to call delete on DDS_CYCLONEDDS_HANDLE afterward. */
if ((rc = dds_init ()) < 0)
return rc;
if ((rc = dds_entity_lock (owner, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK)
goto err_entity_lock;
switch (dds_entity_kind (e))
{
case DDS_KIND_CYCLONEDDS:
case DDS_KIND_DOMAIN:
case DDS_KIND_PARTICIPANT:
break;
default:
rc = DDS_RETCODE_ILLEGAL_OPERATION;
goto err_entity_kind;
}
dds_waitset *waitset = dds_alloc (sizeof (*waitset));
hdl = dds_entity_init (&waitset->m_entity, &par->m_entity, DDS_KIND_WAITSET, NULL, NULL, 0);
dds_entity_t hdl = dds_entity_init (&waitset->m_entity, e, DDS_KIND_WAITSET, NULL, NULL, 0);
ddsrt_mutex_init (&waitset->wait_lock);
ddsrt_cond_init (&waitset->wait_cond);
waitset->m_entity.m_iid = ddsi_iid_gen ();
dds_entity_register_child (&par->m_entity, &waitset->m_entity);
dds_entity_register_child (e, &waitset->m_entity);
waitset->nentities = 0;
waitset->ntriggered = 0;
waitset->entities = NULL;
dds_participant_unlock (par);
dds_entity_init_complete (&waitset->m_entity);
dds_entity_unlock (e);
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return hdl;
err_entity_kind:
dds_entity_unlock (e);
err_entity_lock:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
return rc;
}
dds_return_t dds_waitset_get_entities (dds_entity_t waitset, dds_entity_t *entities, size_t size)
{
dds_return_t ret;
dds_waitset *ws;
if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
dds_entity *wsent;
if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
return ret;
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
{
dds_entity_unpin (wsent);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
else
{
dds_waitset *ws = (dds_waitset *) wsent;
ddsrt_mutex_lock (&ws->wait_lock);
if (entities != NULL)
{
for (size_t i = 0; i < ws->nentities && i < size; i++)
entities[i] = ws->entities[i].handle;
}
ret = (int32_t) ws->nentities;
dds_waitset_unlock (ws);
ddsrt_mutex_unlock (&ws->wait_lock);
dds_entity_unpin (&ws->m_entity);
return ret;
}
}
static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
/* This is called when the observed entity signals a status change. */
static void dds_waitset_observer (struct dds_waitset *ws, dds_entity_t observed, uint32_t status)
{
(void) status;
ddsrt_mutex_lock (&ws->wait_lock);
/* Move observed entity to triggered list. */
size_t i;
for (i = 0; i < ws->nentities; i++)
if (ws->entities[i].handle == observed)
break;
if (i < ws->nentities && i >= ws->ntriggered)
{
dds_attachment tmp = ws->entities[i];
ws->entities[i] = ws->entities[ws->ntriggered];
ws->entities[ws->ntriggered++] = tmp;
}
/* Trigger waitset to wake up. */
ddsrt_cond_broadcast (&ws->wait_cond);
ddsrt_mutex_unlock (&ws->wait_lock);
}
struct dds_waitset_attach_observer_arg {
dds_attach_t x;
};
static bool dds_waitset_attach_observer (struct dds_waitset *ws, struct dds_entity *observed, void *varg)
{
struct dds_waitset_attach_observer_arg *arg = varg;
ddsrt_mutex_lock (&ws->wait_lock);
ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
ws->entities[ws->nentities].arg = arg->x;
ws->entities[ws->nentities].entity = observed;
ws->entities[ws->nentities].handle = observed->m_hdllink.hdl;
ws->nentities++;
if (is_triggered (observed))
{
const size_t i = ws->nentities - 1;
dds_attachment tmp = ws->entities[i];
ws->entities[i] = ws->entities[ws->ntriggered];
ws->entities[ws->ntriggered++] = tmp;
}
ddsrt_cond_broadcast (&ws->wait_cond);
ddsrt_mutex_unlock (&ws->wait_lock);
return true;
}
static void dds_waitset_delete_observer (struct dds_waitset *ws, dds_entity_t observed)
{
size_t i;
ddsrt_mutex_lock (&ws->wait_lock);
for (i = 0; i < ws->nentities; i++)
if (ws->entities[i].handle == observed)
break;
@ -167,119 +278,86 @@ static void dds_waitset_remove (dds_waitset *ws, dds_entity_t observed)
{
ws->entities[i] = ws->entities[--ws->nentities];
}
return;
}
}
/* This is called when the observed entity signals a status change. */
static void dds_waitset_observer (dds_entity *ent, dds_entity_t observed, uint32_t status)
{
assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
dds_waitset *ws = (dds_waitset *) ent;
(void) status;
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
/* Move observed entity to triggered list. */
size_t i;
for (i = 0; i < ws->nentities; i++)
if (ws->entities[i].handle == observed)
break;
if (i < ws->nentities && i >= ws->ntriggered)
{
dds_attachment tmp = ws->entities[i];
ws->entities[i] = ws->entities[ws->ntriggered];
ws->entities[ws->ntriggered++] = tmp;
}
/* Trigger waitset to wake up. */
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
}
static void dds_waitset_delete_observer (dds_entity *ent, dds_entity_t observed)
{
assert (dds_entity_kind (ent) == DDS_KIND_WAITSET);
dds_waitset *ws = (dds_waitset *) ent;
ddsrt_mutex_lock (&ws->m_entity.m_mutex);
/* Remove this observed entity, which is being deleted, from the waitset. */
dds_waitset_remove (ws, observed);
/* Our registration to this observed entity will be removed automatically. */
/* Trigger waitset to wake up. */
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
ddsrt_mutex_unlock (&ws->m_entity.m_mutex);
ddsrt_cond_broadcast (&ws->wait_cond);
ddsrt_mutex_unlock (&ws->wait_lock);
}
dds_return_t dds_waitset_attach (dds_entity_t waitset, dds_entity_t entity, dds_attach_t x)
{
dds_entity *wsent;
dds_entity *e;
dds_waitset *ws;
dds_return_t ret;
if ((ret = dds_waitset_lock (waitset, &ws)) < 0)
if ((ret = dds_entity_pin (waitset, &wsent)) < 0)
return ret;
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
{
dds_entity_unpin (wsent);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
else
{
dds_waitset *ws = (dds_waitset *) wsent;
if (waitset == entity)
e = &ws->m_entity;
else if ((ret = dds_entity_pin (entity, &e)) < 0)
goto err_waitset;
/* This will fail if given entity is already attached (or deleted). */
if ((ret = dds_entity_observer_register (e, &ws->m_entity, dds_waitset_observer, dds_waitset_delete_observer)) != DDS_RETCODE_OK)
if ((ret = dds_entity_pin (entity, &e)) < 0)
goto err_entity;
ws->entities = ddsrt_realloc (ws->entities, (ws->nentities + 1) * sizeof (*ws->entities));
ws->entities[ws->nentities].arg = x;
ws->entities[ws->nentities].entity = e;
ws->entities[ws->nentities].handle = e->m_hdllink.hdl;
ws->nentities++;
if (is_triggered (e))
/* Entity must be "in scope": within the participant, domain or (self-evidently true) Cyclone DDS,
depending on the parent of the waitset, so that one can't use a waitset created in participant
A to wait for entities in participant B, &c. While there is no technical obstacle (though
there might be one for cross-domain use one day), it seems rather unhygienic practice. */
if (!dds_entity_in_scope (e, ws->m_entity.m_parent))
{
const size_t i = ws->nentities - 1;
dds_attachment tmp = ws->entities[i];
ws->entities[i] = ws->entities[ws->ntriggered];
ws->entities[ws->ntriggered++] = tmp;
ret = DDS_RETCODE_BAD_PARAMETER;
goto err_scope;
}
ddsrt_cond_broadcast (&ws->m_entity.m_cond);
err_entity:
if (e != &ws->m_entity)
/* This will fail if given entity is already attached (or deleted). */
struct dds_waitset_attach_observer_arg attach_arg = { .x = x };
ret = dds_entity_observer_register (e, ws, dds_waitset_observer, dds_waitset_attach_observer, &attach_arg, dds_waitset_delete_observer);
err_scope:
dds_entity_unpin (e);
err_waitset:
dds_waitset_unlock (ws);
err_entity:
dds_entity_unpin (&ws->m_entity);
return ret;
}
}
dds_return_t dds_waitset_detach (dds_entity_t waitset, dds_entity_t entity)
{
dds_waitset *ws;
dds_entity *e;
dds_entity *wsent;
dds_return_t ret;
if ((ret = dds_waitset_lock (waitset, &ws)) != DDS_RETCODE_OK)
if ((ret = dds_entity_pin (waitset, &wsent)) != DDS_RETCODE_OK)
return ret;
else if (dds_entity_kind (wsent) != DDS_KIND_WAITSET)
{
dds_entity_unpin (wsent);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
else
{
dds_waitset *ws = (dds_waitset *) wsent;
dds_entity *e;
/* Possibly fails when entity was not attached. */
if (waitset == entity)
ret = dds_entity_observer_unregister (&ws->m_entity, &ws->m_entity);
ret = dds_entity_observer_unregister (&ws->m_entity, ws, true);
else if ((ret = dds_entity_pin (entity, &e)) < 0)
; /* entity invalid */
else
{
ret = dds_entity_observer_unregister (e, &ws->m_entity);
ret = dds_entity_observer_unregister (e, ws, true);
dds_entity_unpin (e);
}
if (ret == DDS_RETCODE_OK)
{
dds_waitset_remove (ws, entity);
}
else
{
if (ret != DDS_RETCODE_PRECONDITION_NOT_MET)
dds_entity_unpin (&ws->m_entity);
if (ret != DDS_RETCODE_OK && ret != DDS_RETCODE_PRECONDITION_NOT_MET)
ret = DDS_RETCODE_BAD_PARAMETER;
}
dds_waitset_unlock (ws);
return ret;
}
}
dds_return_t dds_waitset_wait_until (dds_entity_t waitset, dds_attach_t *xs, size_t nxs, dds_time_t abstimeout)
{
@ -299,7 +377,6 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
{
dds_entity *ent;
dds_return_t rc;
if ((rc = dds_entity_pin (waitset, &ent)) != DDS_RETCODE_OK)
return rc;
else if (dds_entity_kind (ent) != DDS_KIND_WAITSET)
@ -307,11 +384,10 @@ dds_return_t dds_waitset_set_trigger (dds_entity_t waitset, bool trigger)
dds_entity_unpin (ent);
return DDS_RETCODE_ILLEGAL_OPERATION;
}
ddsrt_mutex_lock (&ent->m_observers_lock);
else
{
dds_entity_trigger_set (ent, trigger);
ddsrt_mutex_unlock (&ent->m_observers_lock);
dds_entity_unpin (ent);
return DDS_RETCODE_OK;
}
}

View file

@ -981,21 +981,14 @@ static uint32_t whc_default_remove_acked_messages_full (struct whc_impl *whc, se
/* Delete it - but this may not result in deleting the index node as
there must still be a more recent one available */
#ifndef NDEBUG
struct whc_node whcn_template;
union {
struct whc_idxnode idxn;
char pad[sizeof (struct whc_idxnode) + sizeof (struct whc_node *)];
} template;
template.idxn.headidx = 0;
template.idxn.hist[0] = &whcn_template;
whcn_template.serdata = ddsi_serdata_ref (oldn->serdata);
struct whc_idxnode template;
template.iid = idxn->iid;
assert (oldn->seq < whcn->seq);
#endif
TRACE (" del %p %"PRId64, (void *) oldn, oldn->seq);
whc_delete_one (whc, oldn);
#ifndef NDEBUG
assert (ddsrt_hh_lookup (whc->idx_hash, &template) == idxn);
ddsi_serdata_unref (whcn_template.serdata);
#endif
}
}

View file

@ -16,7 +16,7 @@
#include "dds/ddsi/ddsi_tkmap.h"
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/q_rhc.h"
#include "dds/ddsi/ddsi_rhc.h"
#include "dds/ddsi/ddsi_serdata.h"
#include "dds__stream.h"
#include "dds/ddsi/q_transmit.h"
@ -71,9 +71,9 @@ dds_return_t dds_write_ts (dds_entity_t writer, const void *data, dds_time_t tim
return ret;
}
static dds_return_t try_store (struct rhc *rhc, const struct proxy_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
static dds_return_t try_store (struct ddsi_rhc *rhc, const struct ddsi_writer_info *pwr_info, struct ddsi_serdata *payload, struct ddsi_tkmap_instance *tk, dds_duration_t *max_block_ms)
{
while (! rhc_store (rhc, pwr_info, payload, tk))
while (! ddsi_rhc_store (rhc, pwr_info, payload, tk))
{
if (*max_block_ms > 0)
{
@ -98,8 +98,8 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
if (rdary[0])
{
dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
struct proxy_writer_info pwr_info;
make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
struct ddsi_writer_info pwr_info;
ddsi_make_writer_info (&pwr_info, &wr->e, wr->xqos);
for (uint32_t i = 0; rdary[i]; i++) {
DDS_CTRACE (&wr->e.gv->logconfig, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid));
if ((ret = try_store (rdary[i]->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
@ -120,11 +120,11 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
reliable samples that are rejected are simply discarded. */
ddsrt_avl_iter_t it;
struct pwr_rd_match *m;
struct proxy_writer_info pwr_info;
struct ddsi_writer_info wrinfo;
const struct ephash *gh = wr->e.gv->guid_hash;
dds_duration_t max_block_ms = wr->xqos->reliability.max_blocking_time;
ddsrt_mutex_unlock (&wr->rdary.rdary_lock);
make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
ddsrt_mutex_lock (&wr->e.lock);
for (m = ddsrt_avl_iter_first (&wr_local_readers_treedef, &wr->local_readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
{
@ -133,7 +133,7 @@ static dds_return_t deliver_locally (struct writer *wr, struct ddsi_serdata *pay
{
DDS_CTRACE (&wr->e.gv->logconfig, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid));
/* Copied the return value ignore from DDSI deliver_user_data () function. */
if ((ret = try_store (rd->rhc, &pwr_info, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
if ((ret = try_store (rd->rhc, &wrinfo, payload, tk, &max_block_ms)) != DDS_RETCODE_OK)
break;
}
}

View file

@ -51,34 +51,36 @@ static dds_return_t dds_writer_status_validate (uint32_t mask)
static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
{
struct dds_entity * const entity = ventity;
dds_writer * const wr = ventity;
/* When data is NULL, it means that the writer is deleted. */
/* When data is NULL, it means that the DDSI reader is deleted. */
if (data == NULL)
{
/* Release the initial claim that was done during the create. This
* will indicate that further API deletion is now possible. */
dds_handle_unpin (&entity->m_hdllink);
ddsrt_mutex_lock (&wr->m_entity.m_mutex);
wr->m_wr = NULL;
ddsrt_cond_broadcast (&wr->m_entity.m_cond);
ddsrt_mutex_unlock (&wr->m_entity.m_mutex);
return;
}
struct dds_listener const * const lst = &entity->m_listener;
struct dds_listener const * const lst = &wr->m_entity.m_listener;
enum dds_status_id status_id = (enum dds_status_id) data->raw_status_id;
bool invoke = false;
void *vst = NULL;
int32_t *reset[2] = { NULL, NULL };
ddsrt_mutex_lock (&entity->m_observers_lock);
while (entity->m_cb_count > 0)
ddsrt_cond_wait (&entity->m_observers_cond, &entity->m_observers_lock);
entity->m_cb_count++;
/* FIXME: why wait if no listener is set? */
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
while (wr->m_entity.m_cb_count > 0)
ddsrt_cond_wait (&wr->m_entity.m_observers_cond, &wr->m_entity.m_observers_lock);
/* Reset the status for possible Listener call.
* When a listener is not called, the status will be set (again). */
dds_entity_status_reset (entity, (status_mask_t) (1u << status_id));
dds_entity_status_reset (&wr->m_entity, (status_mask_t) (1u << status_id));
/* Update status metrics. */
dds_writer * const wr = (dds_writer *) entity;
switch (status_id)
{
case DDS_OFFERED_DEADLINE_MISSED_STATUS_ID: {
@ -136,23 +138,31 @@ static void dds_writer_status_cb (void *ventity, const status_cb_data_t *data)
assert (0);
}
if (invoke)
const uint32_t enabled = (ddsrt_atomic_ld32 (&wr->m_entity.m_status.m_status_and_mask) & ((1u << status_id) << SAM_ENABLED_SHIFT));
if (enabled == 0)
{
ddsrt_mutex_unlock (&entity->m_observers_lock);
dds_entity_invoke_listener(entity, status_id, vst);
ddsrt_mutex_lock (&entity->m_observers_lock);
/* Don't invoke listeners or set status flag if masked */
}
else if (invoke)
{
wr->m_entity.m_cb_pending_count++;
wr->m_entity.m_cb_count++;
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
dds_entity_invoke_listener (&wr->m_entity, status_id, vst);
ddsrt_mutex_lock (&wr->m_entity.m_observers_lock);
wr->m_entity.m_cb_count--;
wr->m_entity.m_cb_pending_count--;
*reset[0] = 0;
if (reset[1])
*reset[1] = 0;
}
else
{
dds_entity_status_set (entity, (status_mask_t) (1u << status_id));
dds_entity_status_set (&wr->m_entity, (status_mask_t) (1u << status_id));
}
entity->m_cb_count--;
ddsrt_cond_broadcast (&entity->m_observers_cond);
ddsrt_mutex_unlock (&entity->m_observers_lock);
ddsrt_cond_broadcast (&wr->m_entity.m_observers_cond);
ddsrt_mutex_unlock (&wr->m_entity.m_observers_lock);
}
static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transport_priority)
@ -166,18 +176,32 @@ static uint32_t get_bandwidth_limit (dds_transport_priority_qospolicy_t transpor
#endif
}
static dds_return_t dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all;
static dds_return_t dds_writer_close (dds_entity *e)
static void dds_writer_interrupt (dds_entity *e)
{
dds_writer * const wr = (dds_writer *) e;
dds_return_t ret;
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_send (wr->m_xp, false);
if ((ret = delete_writer (&e->m_domain->gv, &e->m_guid)) < 0)
ret = DDS_RETCODE_ERROR;
struct q_globals * const gv = &e->m_domain->gv;
thread_state_awake (lookup_thread_state (), gv);
unblock_throttled_writer (gv, &e->m_guid);
thread_state_asleep (lookup_thread_state ());
return ret;
}
static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all;
static void dds_writer_close (dds_entity *e)
{
struct dds_writer * const wr = (struct dds_writer *) e;
struct q_globals * const gv = &e->m_domain->gv;
struct thread_state1 * const ts1 = lookup_thread_state ();
thread_state_awake (ts1, gv);
nn_xpack_send (wr->m_xp, false);
(void) delete_writer (gv, &e->m_guid);
thread_state_asleep (ts1);
ddsrt_mutex_lock (&e->m_mutex);
while (wr->m_wr != NULL)
ddsrt_cond_wait (&e->m_cond, &e->m_mutex);
ddsrt_mutex_unlock (&e->m_mutex);
}
static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all;
@ -190,12 +214,7 @@ static dds_return_t dds_writer_delete (dds_entity *e)
thread_state_awake (lookup_thread_state (), &e->m_domain->gv);
nn_xpack_free (wr->m_xp);
thread_state_asleep (lookup_thread_state ());
if ((ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl)) == DDS_RETCODE_OK)
{
ret = dds_delete_impl (e->m_parent->m_hdllink.hdl, true);
if (ret == DDS_RETCODE_BAD_PARAMETER)
ret = DDS_RETCODE_OK;
}
ret = dds_delete (wr->m_topic->m_entity.m_hdllink.hdl);
return ret;
}
@ -238,6 +257,7 @@ static struct whc *make_whc (struct dds_domain *dom, const dds_qos_t *qos)
}
const struct dds_entity_deriver dds_entity_deriver_writer = {
.interrupt = dds_writer_interrupt,
.close = dds_writer_close,
.delete = dds_writer_delete,
.set_qos = dds_writer_qos_set,
@ -251,6 +271,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_writer *wr;
dds_entity_t writer;
dds_publisher *pub = NULL;
dds_participant *pp;
dds_topic *tp;
dds_entity_t publisher;
@ -274,9 +295,14 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
if ((rc = dds_topic_lock (topic, &tp)) != DDS_RETCODE_OK)
goto err_tp_lock;
assert (tp->m_stopic);
assert (pub->m_entity.m_domain == tp->m_entity.m_domain);
pp = dds_entity_participant (&pub->m_entity);
if (pp != dds_entity_participant (&tp->m_entity))
{
rc = DDS_RETCODE_BAD_PARAMETER;
goto err_pp_mismatch;
}
/* Merge Topic & Publisher qos */
wqos = dds_create_qos ();
@ -304,34 +330,26 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
wr->m_whc = make_whc (pub->m_entity.m_domain, wqos);
wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch;
/* Extra claim of this writer to make sure that the delete waits until DDSI
* has deleted its writer as well. This can be known through the callback. */
dds_handle_repin (&wr->m_entity.m_hdllink);
ddsrt_mutex_unlock (&tp->m_entity.m_mutex);
ddsrt_mutex_unlock (&pub->m_entity.m_mutex);
thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv);
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pub->m_entity.m_participant->m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
ddsrt_mutex_lock (&pub->m_entity.m_mutex);
ddsrt_mutex_lock (&tp->m_entity.m_mutex);
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, &pp->m_entity.m_guid, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
assert(rc == DDS_RETCODE_OK);
thread_state_asleep (lookup_thread_state ());
wr->m_entity.m_iid = get_entity_instance_id (&wr->m_entity.m_domain->gv, &wr->m_entity.m_guid);
dds_entity_register_child (&pub->m_entity, &wr->m_entity);
dds_entity_init_complete (&wr->m_entity);
dds_topic_unlock (tp);
dds_publisher_unlock (pub);
return writer;
err_bad_qos:
err_pp_mismatch:
dds_topic_unlock (tp);
err_tp_lock:
dds_publisher_unlock (pub);
if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0){
if ((pub->m_entity.m_flags & DDS_ENTITY_IMPLICIT) != 0)
(void) dds_delete (publisher);
}
return rc;
}

View file

@ -20,6 +20,7 @@ set(ddsc_test_sources
"builtin_topics.c"
"config.c"
"dispose.c"
"domain.c"
"entity_api.c"
"entity_hierarchy.c"
"entity_status.c"
@ -30,6 +31,7 @@ set(ddsc_test_sources
"publisher.c"
"qos.c"
"querycondition.c"
"guardcondition.c"
"readcondition.c"
"reader.c"
"reader_iterator.c"
@ -45,6 +47,7 @@ set(ddsc_test_sources
"unregister.c"
"unsupported.c"
"waitset.c"
"waitset_torture.c"
"write.c"
"writer.c")

View file

@ -308,3 +308,35 @@ CU_Test(ddsc_builtin_topics, builtin_qos, .init = setup, .fini = teardown)
CU_ASSERT_FATAL(dds_sub_subscriber > 0);
check_default_qos_of_builtin_entity(dds_sub_subscriber, 0);
}
CU_Test(ddsc_builtin_topics, read_nothing)
{
dds_entity_t pp;
dds_entity_t rd;
dds_return_t ret;
dds_sample_info_t si;
void *raw1, *raw2;
int32_t n1, n2;
pp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL (pp > 0);
rd = dds_create_reader (pp, DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, NULL, NULL);
CU_ASSERT_FATAL (rd > 0);
/* Can't guarantee there's no other process around with a publication, but
we can take until nothing remains. The point is checking handling of
freeing memory when a loan was outstanding, memory had to be allocated,
and subsequently had to be freed because of an absence of data. */
raw1 = raw2 = NULL;
n1 = dds_take (rd, &raw1, &si, 1, 1);
CU_ASSERT_FATAL (n1 >= 0);
n2 = dds_take (rd, &raw2, &si, 1, 1);
CU_ASSERT_FATAL (n2 >= 0);
ret = dds_return_loan (rd, &raw1, n1);
CU_ASSERT_FATAL (ret == 0);
ret = dds_return_loan (rd, &raw2, n2);
CU_ASSERT_FATAL (ret == 0);
ret = dds_delete (pp);
CU_ASSERT_FATAL (ret == 0);
}

View file

@ -75,3 +75,46 @@ CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
dds_delete(participant);
}
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
dds_entity_t participant_1;
dds_entity_t participant_2;
dds_entity_t participant_3;
participant_1 = dds_create_participant(1, NULL, NULL);
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);
}
CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(1, "<CycloneDDS incorrect XML") != DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(DDS_DOMAIN_DEFAULT,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(2,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
}

View file

@ -0,0 +1,142 @@
/*
* 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 <stdlib.h>
#include "dds/dds.h"
#include "CUnit/Test.h"
#include "config_env.h"
#include "dds/version.h"
#include "dds/ddsrt/environ.h"
CU_Test(ddsc_domain, get_domainid)
{
dds_entity_t pp, d, x;
dds_return_t rc;
uint32_t did;
pp = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (pp > 0);
d = dds_get_parent (pp);
CU_ASSERT_FATAL (d > 0);
x = dds_get_parent (d);
CU_ASSERT_FATAL (x == DDS_CYCLONEDDS_HANDLE);
x = dds_get_parent (x);
CU_ASSERT_FATAL (x == 0);
rc = dds_get_domainid (pp, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
rc = dds_get_domainid (d, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
rc = dds_get_domainid (DDS_CYCLONEDDS_HANDLE, &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == DDS_DOMAIN_DEFAULT);
rc = dds_delete (pp);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}
CU_Test(ddsc_domain, delete_domain0)
{
dds_entity_t pp[3], d[3];
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
if (i > 0)
CU_ASSERT_FATAL (d[i] == d[i-1]);
}
rc = dds_delete (pp[0]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
for (size_t i = 1; i < sizeof (pp) / sizeof (pp[0]); i++)
{
rc = dds_get_domainid (pp[i], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
CU_ASSERT_FATAL (did == 0);
}
rc = dds_delete (d[1]);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
/* Deleting the domain should delete all participants in it as well,
and as there is only a single domain in this test, that should
de-initialize the library.
A non-initialized library returns PRECONDITION_NOT_MET; an
initialized one given an invalid handle returns BAD_PARAMETER,
so we can distinguish the two cases. */
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test(ddsc_domain, delete_domainM)
{
dds_entity_t pp[3], d[3], x;
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (i, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
for (dds_domainid_t j = 0; j < i; j++)
CU_ASSERT_FATAL (d[i] != d[j]);
}
/* deleting participant 0 should tear down domain 0, but nothing else */
rc = dds_delete (pp[0]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
rc = dds_get_domainid (d[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
/* deleting domain should delete participant 1, but leave domain 2 alone */
rc = dds_delete (d[1]);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
x = dds_get_parent (pp[2]);
CU_ASSERT_FATAL (x == d[2]);
/* after deleting participant 2, everything should be gone */
rc = dds_delete (pp[2]);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_get_domainid (pp[1], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test(ddsc_domain, delete_cyclonedds)
{
dds_entity_t pp[3], d[3];
dds_return_t rc;
uint32_t did;
for (dds_domainid_t i = 0; i < (dds_domainid_t) (sizeof (pp) / sizeof (pp[0])); i++)
{
pp[i] = dds_create_participant (i, NULL, NULL);
CU_ASSERT_FATAL (pp[i] > 0);
d[i] = dds_get_parent (pp[i]);
CU_ASSERT_FATAL (d[i] > 0);
for (dds_domainid_t j = 0; j < i; j++)
CU_ASSERT_FATAL (d[i] != d[j]);
}
/* deleting participant 0 should tear down domain 0, but nothing else */
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_domainid (pp[0], &did);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}

View file

@ -290,9 +290,12 @@ CU_Test(ddsc_entity, get_entities, .init = create_entity, .fini = delete_entity)
par = dds_get_parent (0);
CU_ASSERT_EQUAL_FATAL(par, DDS_RETCODE_BAD_PARAMETER);
/* Get Parent, a participant doesn't have a parent. */
/* Get Parent, a participant always has a parent (the domain). */
par = dds_get_parent (entity);
CU_ASSERT_EQUAL_FATAL(par, DDS_ENTITY_NIL);
CU_ASSERT_NOT_EQUAL_FATAL(par, DDS_HANDLE_NIL);
/* The domain has a parent: the pseudo-entity for the library */
par = dds_get_parent (par);
CU_ASSERT_EQUAL_FATAL(par, DDS_CYCLONEDDS_HANDLE);
/* ---------- Get Participant ------------ */

View file

@ -313,7 +313,11 @@ CU_Test(ddsc_entity_get_parent, participant, .init=hierarchy_init, .fini=hierarc
{
dds_entity_t parent;
parent = dds_get_parent(g_participant);
CU_ASSERT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
parent = dds_get_parent(parent);
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_ENTITY_NIL);
parent = dds_get_parent(parent);
CU_ASSERT_NOT_EQUAL_FATAL(parent, DDS_CYCLONEDDS_HANDLE);
}
/*************************************************************************************************/
@ -362,13 +366,15 @@ CU_Test(ddsc_entity_get_children, null, .init=hierarchy_init, .fini=hierarchy_fi
/*************************************************************************************************/
/*************************************************************************************************/
#if SIZE_MAX > INT32_MAX
CU_Test(ddsc_entity_get_children, invalid_size, .init=hierarchy_init, .fini=hierarchy_fini)
{
dds_return_t ret;
dds_entity_t child;
ret = dds_get_children(g_participant, &child, INT32_MAX);
ret = dds_get_children(g_participant, &child, SIZE_MAX);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
}
#endif
/*************************************************************************************************/
/*************************************************************************************************/
@ -866,9 +872,8 @@ CU_Test(ddsc_entity_get_children, implicit_publisher)
dds_delete(writer);
ret = dds_get_children(participant, child2, 2);
CU_ASSERT_EQUAL_FATAL(ret, 2);
CU_ASSERT_EQUAL_FATAL(ret, 1);
CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
dds_delete(topic);
dds_delete(participant);
@ -911,9 +916,8 @@ CU_Test(ddsc_entity_get_children, implicit_subscriber)
dds_delete(reader);
ret = dds_get_children(participant, child2, 2);
CU_ASSERT_EQUAL_FATAL(ret, 2);
CU_ASSERT_EQUAL_FATAL(ret, 1);
CU_ASSERT_FATAL( (child2[0] == child[0]) || (child2[0] == child[1]) );
CU_ASSERT_FATAL( (child2[1] == child[0]) || (child2[1] == child[1]) );
dds_delete(topic);
dds_delete(participant);
@ -947,7 +951,7 @@ CU_Test(ddsc_entity_get_parent, implicit_publisher)
dds_delete(writer);
ret = dds_delete(parent);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant);
}
/*************************************************************************************************/
@ -978,7 +982,7 @@ CU_Test(ddsc_entity_get_parent, implicit_subscriber)
dds_delete(reader);
ret = dds_delete(parent);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant);
}

View file

@ -0,0 +1,187 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <limits.h>
#include "dds/dds.h"
#include "CUnit/Theory.h"
#include "RoundTrip.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/time.h"
CU_Test (ddsc_guardcond_create, cyclonedds)
{
dds_entity_t gc;
dds_return_t rc;
/* Expect an uninitialised library */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
gc = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
/* And the same afterward */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
CU_Test (ddsc_guardcond_create, domain)
{
dds_entity_t par, dom, gc;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
dom = dds_get_parent (par);
CU_ASSERT_FATAL (dom > 0);
gc = dds_create_guardcondition (dom);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (dom);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond_create, participant)
{
dds_entity_t par, gc;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, set_trigger)
{
dds_entity_t par, gc;
dds_return_t rc;
bool trig;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (trig);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, take_trigger)
{
dds_entity_t par, gc;
dds_return_t rc;
bool trig;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
rc = dds_take_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (trig);
rc = dds_read_guardcondition (gc, &trig);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT (!trig);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
CU_Test (ddsc_guardcond, waitset)
{
dds_entity_t par, gc, ws;
dds_attach_t xs[1];
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
ws = dds_create_waitset (par);
CU_ASSERT_FATAL (ws > 0);
rc = dds_waitset_attach (ws, gc, gc);
CU_ASSERT_FATAL (rc == 0);
/* guard cond not triggered: waitset should return 0 */
rc = dds_waitset_wait (ws, xs, 1, 0);
CU_ASSERT (rc == 0);
rc = dds_set_guardcondition (gc, true);
CU_ASSERT_FATAL (rc == 0);
/* guard triggered: waitset should return it */
rc = dds_waitset_wait (ws, xs, 1, 0);
CU_ASSERT (rc == 1);
CU_ASSERT (xs[0] == gc);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}
struct guardcond_thread_arg {
dds_entity_t gc;
dds_return_t ret;
};
static uint32_t guardcond_thread (void *varg)
{
struct guardcond_thread_arg *arg = varg;
/* 200ms sleep is hopefully always long enough for the main thread to
enter wait() and block; a further 1800ms (see wait call) similarly
for the guard condition to actually trigger it. */
dds_sleepfor (DDS_MSECS (200));
arg->ret = dds_set_guardcondition (arg->gc, true);
return 0;
}
CU_Test (ddsc_guardcond, waitset_thread)
{
dds_entity_t par, gc, ws;
dds_attach_t xs[1];
dds_return_t rc;
ddsrt_thread_t tid;
ddsrt_threadattr_t tattr;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
gc = dds_create_guardcondition (par);
CU_ASSERT_FATAL (gc > 0);
ws = dds_create_waitset (par);
CU_ASSERT_FATAL (ws > 0);
rc = dds_waitset_attach (ws, gc, gc);
CU_ASSERT_FATAL (rc == 0);
struct guardcond_thread_arg arg = { .gc = gc };
ddsrt_threadattr_init (&tattr);
rc = ddsrt_thread_create (&tid, "guardcond_thread", &tattr, guardcond_thread, &arg);
CU_ASSERT_FATAL (rc == 0);
rc = dds_waitset_wait (ws, xs, 1, DDS_SECS (2));
CU_ASSERT (rc == 1);
CU_ASSERT (xs[0] == gc);
rc = ddsrt_thread_join (tid, NULL);
CU_ASSERT_FATAL (rc == 0);
CU_ASSERT_FATAL (arg.ret == 0);
rc = dds_delete (par);
CU_ASSERT_FATAL (rc == 0);
}

View file

@ -132,6 +132,7 @@ CU_Test(ddsc_instance_get_key, registered_instance, .init=setup, .fini=teardown)
ret = dds_instance_get_key(writer, handle, &key_data);
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
@ -162,6 +163,7 @@ CU_Test(ddsc_instance_get_key, readcondition, .init=setup, .fini=teardown)
ret = dds_instance_get_key(readcondition, handle, &key_data);
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
@ -192,6 +194,7 @@ CU_Test(ddsc_instance_get_key, querycondition, .init=setup, .fini=teardown)
ret = dds_instance_get_key(querycondition, handle, &key_data);
CU_ASSERT_PTR_NOT_NULL_FATAL(key_data.ip);
assert (key_data.ip != NULL); /* for the benefit of clang's static analyzer */
CU_ASSERT_STRING_EQUAL_FATAL(key_data.ip, data.ip);
CU_ASSERT_EQUAL_FATAL(key_data.port, data.port);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);

View file

@ -727,7 +727,9 @@ CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fi
CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl);
/* Reset the trigger flags. */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
ddsrt_mutex_unlock(&g_mutex);
/* Un-match the publication by deleting the reader. */
dds_delete(g_reader);
@ -789,7 +791,9 @@ CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=f
CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl);
/* Reset the trigger flags. */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
ddsrt_mutex_unlock(&g_mutex);
/* Un-match the subscription by deleting the writer. */
dds_delete(g_writer);
@ -903,8 +907,10 @@ CU_Test(ddsc_listener, data_available, .init=init_triggering_test, .fini=fini_tr
/* Deleting the writer causes unregisters (or dispose+unregister), and those
should trigger DATA_AVAILABLE as well */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
cb_reader = 0;
ddsrt_mutex_unlock(&g_mutex);
ret = dds_delete (g_writer);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
g_writer = 0;
@ -942,8 +948,10 @@ CU_Test(ddsc_listener, data_available_delete_writer, .init=init_triggering_test,
CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader);
/* Deleting the writer must trigger DATA_AVAILABLE as well */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
cb_reader = 0;
ddsrt_mutex_unlock(&g_mutex);
ret = dds_delete (g_writer);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
g_writer = 0;
@ -991,8 +999,10 @@ CU_Test(ddsc_listener, data_available_delete_writer_disposed, .init=init_trigger
} while (ret > 0);
/* Deleting the writer should not trigger DATA_AVAILABLE with all instances empty & disposed */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
cb_reader = 0;
ddsrt_mutex_unlock(&g_mutex);
ret = dds_delete (g_writer);
CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK);
g_writer = 0;
@ -1174,7 +1184,9 @@ CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fin
CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl);
/* Reset the trigger flags. */
ddsrt_mutex_lock(&g_mutex);
cb_called = 0;
ddsrt_mutex_unlock(&g_mutex);
/* Change liveliness again by deleting the writer. */
dds_delete(g_writer);

View file

@ -47,7 +47,8 @@ CU_Test(ddsc_participant, create_with_no_conf_no_env)
dds_domainid_t domain_id;
dds_domainid_t valid_domain=3;
ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
status = ddsrt_unsetenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI");
CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK);
//valid specific domain value
participant2 = dds_create_participant (valid_domain, NULL, NULL);

View file

@ -277,7 +277,50 @@ CU_Theory((dds_entity_t *par, dds_entity_t *top), ddsc_reader_create, non_partic
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test(ddsc_reader_create, wrong_participant, .init=reader_init, .fini=reader_fini)
{
dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(participant2 > 0);
dds_entity_t reader = dds_create_reader(participant2, g_topic, NULL, NULL);
CU_ASSERT_EQUAL_FATAL(reader, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant2);
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test(ddsc_reader_create, participant_mismatch)
{
dds_entity_t par1 = 0;
dds_entity_t par2 = 0;
dds_entity_t sub1 = 0;
dds_entity_t top2 = 0;
dds_entity_t reader = 0;
char name[100];
par1 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(par1 > 0);
par2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(par2 > 0);
sub1 = dds_create_subscriber(par1, NULL, NULL);
CU_ASSERT_FATAL(sub1 > 0);
top2 = dds_create_topic(par2, &Space_Type1_desc, create_topic_name("ddsc_reader_participant_mismatch", name, sizeof name), NULL, NULL);
CU_ASSERT_FATAL(top2 > 0);
/* Create reader with participant mismatch. */
reader = dds_create_reader(sub1, top2, NULL, NULL);
/* Expect the creation to have failed. */
CU_ASSERT_FATAL(reader <= 0);
dds_delete(top2);
dds_delete(sub1);
dds_delete(par2);
dds_delete(par1);
}
/*************************************************************************************************/

View file

@ -256,6 +256,39 @@ CU_Theory((dds_entity_t *par), ddsc_waitset_create, non_participants, .init=ddsc
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test (ddsc_waitset_create, domain)
{
dds_entity_t par, dom, ws;
dds_return_t rc;
par = dds_create_participant (0, NULL, NULL);
CU_ASSERT_FATAL (par > 0);
dom = dds_get_parent (par);
CU_ASSERT_FATAL (dom > 0);
ws = dds_create_waitset (dom);
CU_ASSERT_FATAL (ws > 0);
rc = dds_delete (dom);
CU_ASSERT_FATAL (rc == 0);
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_Test (ddsc_waitset_create, cyclonedds)
{
dds_entity_t ws;
dds_return_t rc;
/* Expect an uninitialised library */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (ws > 0);
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
/* And the same afterward */
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
/*************************************************************************************************/
/**************************************************************************************************
@ -318,6 +351,52 @@ CU_Test(ddsc_waitset_attach, deleted_waitset, .init=ddsc_waitset_basic_init, .fi
}
/*************************************************************************************************/
/*************************************************************************************************/
CU_TheoryDataPoints(ddsc_waitset_attach, scoping) = {
CU_DataPoints (int, -9, -1, -2, 0, 0, 2), /* owner: -9: lib, -1: dom0, -2: dom1 */
CU_DataPoints (int, 0, 0, 2, 0, 0, 2), /* ok1: participant one can attach */
CU_DataPoints (int, 3, 1, 3, -1, -1, -1), /* ok2: other participant one can attach, or -1 */
CU_DataPoints (int, -1, 2, 0, 1, 2, 0), /* fail: participant that one cannot attach, or -1 */
};
CU_Theory ((int owner, int ok1, int ok2, int fail), ddsc_waitset_attach, scoping)
{
dds_entity_t par[4], dom[2], ws, ownh;
dds_return_t rc;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
par[2*i+j] = dds_create_participant ((dds_domainid_t) i, NULL, NULL);
CU_ASSERT_FATAL (par[2*i+j] > 0);
}
dom[i] = dds_get_parent (par[2*i]);
CU_ASSERT_FATAL (dom[i] > 0);
}
if (owner == -9) {
ownh = DDS_CYCLONEDDS_HANDLE;
} else if (owner < 0) {
ownh = dom[-owner - 1];
} else {
ownh = par[owner];
}
printf ("%d %d %d %d | %"PRId32"\n", owner, ok1, ok2, fail, ownh);
ws = dds_create_waitset (ownh);
CU_ASSERT_FATAL (ws > 0);
rc = dds_waitset_attach (ws, par[ok1], 0);
CU_ASSERT_FATAL (rc == 0);
if (ok2 >= 0) {
rc = dds_waitset_attach (ws, par[ok2], 1);
CU_ASSERT_FATAL (rc == 0);
}
if (fail >= 0) {
rc = dds_waitset_attach (ws, par[fail], 2);
CU_ASSERT_FATAL (rc == DDS_RETCODE_BAD_PARAMETER);
}
rc = dds_delete (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == 0);
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}
/*************************************************************************************************/
/**************************************************************************************************

View file

@ -0,0 +1,398 @@
/*
* 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 <assert.h>
#include <limits.h>
#include "dds/dds.h"
#include "CUnit/Theory.h"
#include "RoundTrip.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/threads.h"
#include "dds/ddsrt/atomics.h"
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/random.h"
#define N_WAITSETS 20
#define N_ENTITIES 32
#define N_GUARDCONDS 20
#define N_SUBSCRIBERS 4
#define N_READERS 4
#define N_READCONDS 4
static dds_entity_t ppant;
static dds_entity_t topic;
static ddsrt_atomic_uint32_t terminate;
static ddsrt_atomic_uint32_t waitsets[N_WAITSETS];
static ddsrt_atomic_uint32_t entities[N_ENTITIES], signalled;
static ddsrt_atomic_uint32_t attach_ok, detach_ok, settrig_ok;
static ddsrt_atomic_uint32_t create_ent_ok[5], delete_ent_ok[5];
static ddsrt_atomic_uint32_t create_ws_ok, delete_ws_ok;
#define RESERVED ((uint32_t) 0xffffffffu)
static void init_prng (ddsrt_prng_t *prng)
{
ddsrt_prng_seed_t prng_seed;
for (size_t i = 0; i < sizeof (prng_seed.key) / sizeof (prng_seed.key[0]); i++)
prng_seed.key[i] = ddsrt_random ();
ddsrt_prng_init (prng, &prng_seed);
}
static void choose_index (uint32_t *p_idx, uint32_t *p_handle, ddsrt_prng_t *prng, ddsrt_atomic_uint32_t elems[], size_t nelems)
{
uint32_t idx, h, h1;
retry_idx:
idx = ddsrt_prng_random (prng) % (uint32_t) nelems;
retry_cas:
h = ddsrt_atomic_ld32 (&elems[idx]);
if (h == 0)
h1 = RESERVED;
else if ((int32_t) h > 0)
h1 = 0;
else
goto retry_idx;
if (!ddsrt_atomic_cas32 (&elems[idx], h, h1))
goto retry_cas;
*p_idx = idx;
*p_handle = h;
}
static dds_entity_t pick_a_subscriber (void)
{
uint32_t idx = ddsrt_random () % N_SUBSCRIBERS;
uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + idx]);
return (dds_entity_t) x;
}
static dds_entity_t pick_a_reader (void)
{
uint32_t idx = ddsrt_random () % N_READERS;
uint32_t x = ddsrt_atomic_ld32 (&entities[N_GUARDCONDS + N_SUBSCRIBERS + idx]);
return (dds_entity_t) x;
}
static int index_to_counter_index (uint32_t idx)
{
if (idx < N_GUARDCONDS)
return 0;
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
return 1;
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
return 2;
else
return 4;
}
static uint32_t guardcond_create_delete_thread (void *varg)
{
(void) varg;
ddsrt_prng_t prng;
init_prng (&prng);
while (!ddsrt_atomic_ld32 (&terminate))
{
uint32_t idx, handle;
choose_index (&idx, &handle, &prng, entities, N_ENTITIES);
if (handle == 0)
{
dds_entity_t ent = 0, parent = 0;
if (idx < N_GUARDCONDS)
ent = dds_create_guardcondition (DDS_CYCLONEDDS_HANDLE);
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS)
ent = dds_create_subscriber (ppant, NULL, NULL);
else if (idx < N_GUARDCONDS + N_SUBSCRIBERS + N_READERS)
{
if ((parent = pick_a_subscriber ()) == 0)
parent = ppant;
ent = dds_create_reader (parent, topic, NULL, NULL);
}
else if ((parent = pick_a_reader ()) != 0)
{
ent = dds_create_readcondition (parent, DDS_ANY_STATE);
}
if (ent > 0)
{
ddsrt_atomic_inc32 (&create_ent_ok[index_to_counter_index (idx) + (parent == ppant)]);
ddsrt_atomic_st32 (&entities[idx], (uint32_t) ent);
}
else if (ent < 0 && idx < N_GUARDCONDS)
{
fprintf (stderr, "dds_create_guardcondition failed: %s\n", dds_strretcode (ent));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
}
else
{
dds_return_t rc = dds_delete ((dds_entity_t) handle);
if (rc == 0)
ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (idx)]);
}
}
return 0;
}
static uint32_t waitset_create_delete_thread (void *varg)
{
(void) varg;
ddsrt_prng_t prng;
init_prng (&prng);
while (!ddsrt_atomic_ld32 (&terminate))
{
uint32_t idx, handle;
choose_index (&idx, &handle, &prng, waitsets, N_WAITSETS);
if (handle == 0)
{
dds_entity_t ws = dds_create_waitset (DDS_CYCLONEDDS_HANDLE);
if (ws < 0)
{
fprintf (stderr, "dds_create_waitset failed: %s\n", dds_strretcode (ws));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
ddsrt_atomic_inc32 (&create_ws_ok);
ddsrt_atomic_st32 (&waitsets[idx], (uint32_t) ws);
}
else
{
dds_return_t rc = dds_delete ((dds_entity_t) handle);
if (rc == 0)
ddsrt_atomic_inc32 (&delete_ws_ok);
}
}
return 0;
}
static uint32_t guardcond_trigger_thread (void *varg)
{
(void) varg;
ddsrt_prng_t prng;
init_prng (&prng);
while (!ddsrt_atomic_ld32 (&terminate))
{
uint32_t idx = ddsrt_prng_random (&prng) % N_ENTITIES;
uint32_t h = ddsrt_atomic_ld32 (&entities[idx]);
if ((int32_t) h <= 0)
continue;
else
{
uint32_t s, s1;
do {
s = ddsrt_atomic_ld32 (&signalled);
s1 = s ^ (1u << idx);
} while (!ddsrt_atomic_cas32 (&signalled, s, s1));
dds_return_t rc = dds_set_guardcondition ((dds_entity_t) h, (s & (1u << idx)) ? false : true);
if (rc == 0)
ddsrt_atomic_inc32 (&settrig_ok);
}
}
return 0;
}
static uint32_t waitset_attach_detach_thread (void *varg)
{
(void) varg;
ddsrt_prng_t prng;
init_prng (&prng);
while (!ddsrt_atomic_ld32 (&terminate))
{
uint32_t wsidx = ddsrt_prng_random (&prng) % N_WAITSETS;
uint32_t wsh = ddsrt_atomic_ld32 (&waitsets[wsidx]);
if ((int32_t) wsh <= 0)
continue;
uint32_t gcidx = ddsrt_prng_random (&prng) % N_ENTITIES;
uint32_t gch = ddsrt_atomic_ld32 (&entities[gcidx]);
if ((int32_t) gch <= 0)
continue;
dds_return_t rc;
rc = dds_waitset_detach ((dds_entity_t) wsh, (dds_entity_t) gch);
if (rc == 0)
{
ddsrt_atomic_inc32 (&detach_ok);
}
else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
{
/* attempts at attaching a guard condition twice or detaching an unattached
one are expected, and those result in a PRECONDITION_NOT_MET */
fprintf (stderr, "dds_waitset_detach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
else
{
/* should imply it is already attached, so try detaching */
rc = dds_waitset_attach ((dds_entity_t) wsh, (dds_entity_t) gch, 0);
if (rc == 0)
{
ddsrt_atomic_inc32 (&attach_ok);
}
else if (rc != DDS_RETCODE_PRECONDITION_NOT_MET && rc != DDS_RETCODE_BAD_PARAMETER)
{
fprintf (stderr, "dds_waitset_attach 0x%"PRIx32" 0x%"PRIx32" failed: %s\n", (dds_entity_t) wsh, (dds_entity_t) gch, dds_strretcode (rc));
ddsrt_atomic_st32 (&terminate, 1);
return 1;
}
}
}
return 0;
}
CU_Test (ddsc_waitset, torture)
{
dds_return_t rc;
ddsrt_thread_t tids[8];
ddsrt_threadattr_t tattr;
ddsrt_threadattr_init (&tattr);
/* This keeps the library initialised -- it shouldn't be necessary */
ppant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL (ppant > 0);
topic = dds_create_topic (ppant, &RoundTripModule_DataType_desc, "waitset_torture_topic", NULL, NULL);
CU_ASSERT_FATAL (topic > 0);
rc = ddsrt_thread_create (&tids[0], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[1], "gc_cd", &tattr, guardcond_create_delete_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[2], "ws_cd", &tattr, waitset_create_delete_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[3], "ws_cd", &tattr, waitset_create_delete_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[4], "gc_t", &tattr, guardcond_trigger_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[5], "gc_t", &tattr, guardcond_trigger_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[6], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
CU_ASSERT_FATAL (rc == 0);
rc = ddsrt_thread_create (&tids[7], "ws_ad", &tattr, waitset_attach_detach_thread, 0);
CU_ASSERT_FATAL (rc == 0);
uint32_t wait_err = 0, wait_ok[N_ENTITIES + 1] = { 0 };
dds_time_t tstop = dds_time () + DDS_SECS (5);
while (dds_time () < tstop && !ddsrt_atomic_ld32 (&terminate))
{
/* Try waiting on the waitset in slot 0 if it exists (it shouldn't make much
difference which waitset we use; this is easy). There are never more than
N_ENTITIES guard conditions, so there are also never more than that many
triggering entities, and so we can easily do a small histogram. (The longer
you run it, the longer the tail of triggering entities one expects.)
Error handling: the waitset may be deleted in between loading the handle
and pinning it wait(), so BAD_PARAMETER is to be expected. If the "extragc"
isn't there to ensure the library stays initialised, it is even possible
that we get PRECONDITION_NOT_MET if it just so happened that with the
deleting of that waitset, no entities remain at all. */
dds_entity_t ws = (dds_entity_t) ddsrt_atomic_ld32 (&waitsets[0]);
if (ws > 0)
{
int32_t n = dds_waitset_wait (ws, NULL, 0, DDS_MSECS (10));
if (!((rc >= 0 && rc <= N_ENTITIES) || rc == DDS_RETCODE_BAD_PARAMETER))
{
fprintf (stderr, "dds_waitset_wait failed: %s\n", dds_strretcode (rc));
ddsrt_atomic_st32 (&terminate, 1);
rc = DDS_RETCODE_ERROR;
}
else
{
if (n >= 0)
wait_ok[n]++;
else
wait_err++;
}
}
}
ddsrt_atomic_st32 (&terminate, 1);
CU_ASSERT (rc != DDS_RETCODE_ERROR);
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 == 0);
CU_ASSERT (retval == 0);
}
/* The threads don't bother to clean up, so delete whatever guard conditions and
waitsets happen to still exist. Passing garbage into dds_delete is supposed
to work, so don't bother with any validation or error checking. */
for (uint32_t i = 0; i < N_ENTITIES; i++)
{
if (dds_delete ((dds_entity_t) ddsrt_atomic_ld32 (&entities[i])) == DDS_RETCODE_OK)
ddsrt_atomic_inc32 (&delete_ent_ok[index_to_counter_index (i)]);
}
for (uint32_t i = 0; i < N_WAITSETS; i++)
{
if (dds_delete ((dds_entity_t) ddsrt_atomic_ld32 (&waitsets[i])) == DDS_RETCODE_OK)
ddsrt_atomic_inc32 (&delete_ws_ok);
}
/* All we should be left within the participant is the topic */
rc = dds_delete (topic);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
rc = dds_get_children (ppant, NULL, 0);
CU_ASSERT_FATAL (rc == 0);
rc = dds_delete (ppant);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
printf ("attach %"PRIu32" detach %"PRIu32" settrig %"PRIu32"\n", ddsrt_atomic_ld32 (&attach_ok), ddsrt_atomic_ld32 (&detach_ok), ddsrt_atomic_ld32 (&settrig_ok));
printf ("create/delete ent");
uint32_t create_ent_ok_sum = 0;
for (size_t i = 0; i < sizeof (create_ent_ok) / sizeof (create_ent_ok[0]); i++)
{
uint32_t c = ddsrt_atomic_ld32 (&create_ent_ok[i]);
create_ent_ok_sum += c;
printf (" %"PRIu32"/%"PRIu32, c, ddsrt_atomic_ld32 (&delete_ent_ok[i]));
}
printf ("\n");
{
uint32_t rd_cr_sub = ddsrt_atomic_ld32 (&create_ent_ok[2]);
uint32_t rd_cr_ppant = ddsrt_atomic_ld32 (&create_ent_ok[3]);
uint32_t rd_del = ddsrt_atomic_ld32 (&delete_ent_ok[2]);
uint32_t sub_del = ddsrt_atomic_ld32 (&delete_ent_ok[1]);
CU_ASSERT (rd_del <= rd_cr_sub + rd_cr_ppant); /* can't have deleted more readers than were created */
CU_ASSERT (rd_del >= rd_cr_ppant); /* readers created with ppant as owner must have been deleted explicitly */
CU_ASSERT (rd_del - rd_cr_ppant <= sub_del); /* other readers may have been deleted by deleting a sub */
}
printf ("create/delete ws %"PRIu32"/%"PRIu32"\n", ddsrt_atomic_ld32 (&create_ws_ok), ddsrt_atomic_ld32 (&delete_ws_ok));
printf ("wait {err %"PRIu32"}", wait_err);
uint32_t wait_ok_sum = 0;
for (size_t i = 0; i < sizeof (wait_ok) / sizeof (wait_ok[0]); i++)
{
wait_ok_sum += wait_ok[i];
printf (" %"PRIu32, wait_ok[i]);
}
printf ("\n");
/* Running on Windows on the CI infrastructure has very little concurrency, but Linux
and macOS seem ok. The thresholds here appear to be sufficiently low to not give
many spurious failures, while still being sanity check that at least something
happened. */
CU_ASSERT (ddsrt_atomic_ld32 (&attach_ok) +
ddsrt_atomic_ld32 (&settrig_ok) +
ddsrt_atomic_ld32 (&create_ws_ok) +
create_ent_ok_sum +
wait_ok_sum > 1000);
rc = dds_get_parent (DDS_CYCLONEDDS_HANDLE);
CU_ASSERT_FATAL (rc == DDS_RETCODE_PRECONDITION_NOT_MET);
}

View file

@ -72,6 +72,15 @@ CU_Test(ddsc_create_writer, participant, .init = setup, .fini = teardown)
CU_ASSERT_FATAL(writer > 0);
}
CU_Test(ddsc_create_writer, wrong_participant, .init = setup, .fini = teardown)
{
dds_entity_t participant2 = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(participant2 > 0);
writer = dds_create_writer(participant2, topic, NULL, NULL);
CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
dds_delete(participant2);
}
CU_Test(ddsc_create_writer, publisher, .init = setup, .fini = teardown)
{
writer = dds_create_writer(publisher, topic, NULL, NULL);
@ -107,3 +116,27 @@ CU_Test(ddsc_create_writer, deleted_topic, .init = setup, .fini = teardown)
writer = dds_create_writer(publisher, topic, NULL, NULL);
CU_ASSERT_EQUAL_FATAL(writer, DDS_RETCODE_BAD_PARAMETER);
}
CU_Test(ddsc_create_writer, participant_mismatch, .init = setup, .fini = teardown)
{
dds_entity_t l_par = 0;
dds_entity_t l_pub = 0;
/* The call to setup() created the global topic. */
/* Create publisher on local participant. */
l_par = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL);
CU_ASSERT_FATAL(l_par > 0);
l_pub = dds_create_publisher(l_par, NULL, NULL);
CU_ASSERT_FATAL(l_pub > 0);
/* Create writer with local publisher and global topic. */
writer = dds_create_writer(l_pub, topic, NULL, NULL);
/* Expect the creation to have failed. */
CU_ASSERT_FATAL(writer <= 0);
dds_delete(l_pub);
dds_delete(l_par);
}

View file

@ -26,6 +26,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
ddsi_tkmap.c
ddsi_vendor.c
ddsi_threadmon.c
ddsi_rhc.c
q_addrset.c
q_bitset_inlines.c
q_bswap.c
@ -53,7 +54,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src"
q_transmit.c
q_inverse_uint32_set.c
q_whc.c
q_rhc.c
q_xevent.c
q_xmsg.c
q_freelist.c
@ -70,6 +70,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_raweth.h
ddsi_ipaddr.h
ddsi_mcgroup.h
ddsi_plist_generic.h
ddsi_serdata.h
ddsi_sertopic.h
ddsi_serdata_default.h
@ -78,6 +79,8 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
ddsi_vendor.h
ddsi_threadmon.h
ddsi_builtin_topic_if.h
ddsi_rhc.h
ddsi_guid.h
q_addrset.h
q_bitset.h
q_bswap.h
@ -102,7 +105,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi"
q_qosmatch.h
q_radmin.h
q_receive.h
q_rhc.h
q_rtps.h
q_security.h
q_sockwaitset.h
@ -128,3 +130,8 @@ install(
DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT dev)
# TODO: improve test inclusion.
if((BUILD_TESTING) AND ((NOT DEFINED MSVC_VERSION) OR (MSVC_VERSION GREATER "1800")))
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tests")
endif()

View file

@ -22,24 +22,24 @@ extern "C" {
struct entity_common;
struct ddsi_tkmap_instance;
struct ddsi_sertopic;
struct nn_guid;
struct ddsi_guid;
struct ddsi_builtin_topic_interface {
void *arg;
bool (*builtintopic_is_builtintopic) (const struct ddsi_sertopic *topic, void *arg);
bool (*builtintopic_is_visible) (const struct nn_guid *guid, nn_vendorid_t vendorid, void *arg);
struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct nn_guid *guid, void *arg);
bool (*builtintopic_is_visible) (const struct ddsi_guid *guid, nn_vendorid_t vendorid, void *arg);
struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct ddsi_guid *guid, void *arg);
void (*builtintopic_write) (const struct entity_common *e, nn_wctime_t timestamp, bool alive, void *arg);
};
inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid) {
inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, nn_vendorid_t vendorid) {
return btif ? btif->builtintopic_is_visible (guid, vendorid, btif->arg) : false;
}
inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic) {
return btif ? btif->builtintopic_is_builtintopic (topic, btif->arg) : false;
}
inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid) {
inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid) {
return btif ? btif->builtintopic_get_tkmap_entry (guid, btif->arg) : NULL;
}
inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive) {

View file

@ -0,0 +1,37 @@
/*
* 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_GUID_H
#define DDSI_GUID_H
#include <stdint.h>
#if defined (__cplusplus)
extern "C" {
#endif
typedef union ddsi_guid_prefix {
unsigned char s[12];
uint32_t u[3];
} ddsi_guid_prefix_t;
typedef union ddsi_entityid {
uint32_t u;
} ddsi_entityid_t;
typedef struct ddsi_guid {
ddsi_guid_prefix_t prefix;
ddsi_entityid_t entityid;
} ddsi_guid_t;
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,67 @@
/*
* 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_PLIST_GENERIC_H
#define DDSI_PLIST_GENERIC_H
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
#include "dds/export.h"
#include "dds/ddsrt/attributes.h"
#if defined (__cplusplus)
extern "C" {
#endif
/* Instructions for the generic serializer (&c) that handles most parameters.
The "packed" attribute means single-byte instructions on GCC and Clang. */
enum pserop {
XSTOP,
XO, /* octet sequence */
XS, /* string */
XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
XD, XDx2, /* duration, 1 .. 2 in a row */
Xo, Xox2, /* octet, 1 .. 2 in a row */
Xb, Xbx2, /* boolean, 1 .. 2 in a row */
XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
XbPROP, /* boolean: omit in serialized form; skip serialization if false; always true on deserialize */
XG, /* GUID */
XK, /* keyhash */
XQ, /* arbitary non-nested sequence */
Xopt, /* remainder is optional on deser, 0-init if not present */
} ddsrt_attribute_packed;
inline bool pserop_seralign_is_1 (enum pserop op) {
/* NB: XbPROP is never serialized, so its alignment is irrelevant. If ever there
is a need to allow calling this function when op = XbPROP, it needs to be changed
to taking the address of the pserop, and in that case inspect the following
operator */
assert (op != XbPROP && op != Xopt && op != XSTOP);
return (op >= Xo && op <= XK);
}
DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased);
DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc);
DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc);
DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc);
DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc);
#if defined (__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,81 @@
/*
* 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
*/
#ifndef DDSI_RHC_H
#define DDSI_RHC_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "dds/export.h"
/* DDS_EXPORT inline i.c.w. __attributes__((visibility...)) and some compilers: */
#include "dds/ddsrt/attributes.h"
#include "dds/ddsi/ddsi_guid.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct dds_qos;
struct ddsi_rhc;
struct ddsi_tkmap_instance;
struct ddsi_serdata;
struct ddsi_sertopic;
struct ddsi_writer_info
{
ddsi_guid_t guid;
bool auto_dispose;
int32_t ownership_strength;
uint64_t iid;
};
typedef void (*ddsi_rhc_free_t) (struct ddsi_rhc *rhc);
typedef bool (*ddsi_rhc_store_t) (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
typedef void (*ddsi_rhc_unregister_wr_t) (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
typedef void (*ddsi_rhc_relinquish_ownership_t) (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid);
typedef void (*ddsi_rhc_set_qos_t) (struct ddsi_rhc *rhc, const struct dds_qos *qos);
struct ddsi_rhc_ops {
ddsi_rhc_store_t store;
ddsi_rhc_unregister_wr_t unregister_wr;
ddsi_rhc_relinquish_ownership_t relinquish_ownership;
ddsi_rhc_set_qos_t set_qos;
ddsi_rhc_free_t free;
};
struct ddsi_rhc {
const struct ddsi_rhc_ops *ops;
};
DDS_EXPORT inline bool ddsi_rhc_store (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return rhc->ops->store (rhc, wrinfo, sample, tk);
}
DDS_EXPORT inline void ddsi_rhc_unregister_wr (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) {
rhc->ops->unregister_wr (rhc, wrinfo);
}
DDS_EXPORT inline void ddsi_rhc_relinquish_ownership (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) {
rhc->ops->relinquish_ownership (rhc, wr_iid);
}
DDS_EXPORT inline void ddsi_rhc_set_qos (struct ddsi_rhc *rhc, const struct dds_qos *qos) {
rhc->ops->set_qos (rhc, qos);
}
DDS_EXPORT inline void ddsi_rhc_free (struct ddsi_rhc *rhc) {
rhc->ops->free (rhc);
}
#if defined (__cplusplus)
}
#endif
#endif /* DDSI_RHC_H */

View file

@ -123,6 +123,15 @@ typedef bool (*ddsi_serdata_topicless_to_sample_t) (const struct ddsi_sertopic *
computing equijoins across topics much simpler). */
typedef bool (*ddsi_serdata_eqkey_t) (const struct ddsi_serdata *a, const struct ddsi_serdata *b);
/* Print a serdata into the provided buffer (truncating as necessary)
- topic is present for supporting printing of "topicless" samples
- buf != NULL, bufsize > 0 on input
- buf must always be terminated with a nul character on return
- returns the number of characters (excluding the terminating 0) needed to print it
in full (or, as an optimization, it may pretend that it has printed it in full,
returning bufsize-1) if it had to truncate) */
typedef size_t (*ddsi_serdata_print_t) (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size);
struct ddsi_serdata_ops {
ddsi_serdata_eqkey_t eqkey;
ddsi_serdata_size_t get_size;
@ -136,8 +145,11 @@ struct ddsi_serdata_ops {
ddsi_serdata_to_topicless_t to_topicless;
ddsi_serdata_topicless_to_sample_t topicless_to_sample;
ddsi_serdata_free_t free;
ddsi_serdata_print_t print;
};
#define DDSI_SERDATA_HAS_PRINT 1
DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind);
DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_ref (const struct ddsi_serdata *serdata_const) {
@ -195,6 +207,20 @@ DDS_EXPORT inline bool ddsi_serdata_eqkey (const struct ddsi_serdata *a, const s
return a->ops->eqkey (a, b);
}
DDS_EXPORT inline bool ddsi_serdata_print (const struct ddsi_serdata *d, char *buf, size_t size) {
return d->ops->print (d->topic, d, buf, size);
}
DDS_EXPORT inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size) {
if (d->ops->print)
return d->ops->print (topic, d, buf, size);
else
{
buf[0] = 0;
return 0;
}
}
#if defined (__cplusplus)
}
#endif

View file

@ -19,6 +19,7 @@ typedef struct {
uint8_t id[2];
} nn_vendorid_t;
/* All existing vendor codes have the major part equal to 1 (and this will probably be true for a long, long time) */
#define NN_VENDORID_MINOR_RTI 0x01
#define NN_VENDORID_MINOR_PRISMTECH_OSPL 0x02
@ -38,8 +39,15 @@ typedef struct {
#define NN_VENDORID_MINOR_ECLIPSE 0x10
#define NN_VENDORID_MINOR_PRISMTECH_CLOUD 0x20
#if defined(_WIN32) && defined(__cplusplus)
#define NN_VENDORID(vendor) {{ 0x01, NN_VENDORID_MINOR_##vendor }}
#define NN_VENDORID_UNKNOWN {{ 0x00, 0x00 }}
#else
#define NN_VENDORID(vendor) ((nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_##vendor }})
#define NN_VENDORID_UNKNOWN ((nn_vendorid_t) {{ 0x00, 0x00 }})
#define NN_VENDORID_ECLIPSE ((nn_vendorid_t) {{ 0x01, 0x10 }})
#endif
#define NN_VENDORID_ECLIPSE NN_VENDORID (ECLIPSE)
#if defined (__cplusplus)
extern "C" {
@ -49,32 +57,32 @@ inline bool vendor_equals (nn_vendorid_t a, nn_vendorid_t b) {
return ((a.id[0] << 8) | a.id[1]) == ((b.id[0] << 8) | b.id[1]);
}
inline bool vendor_is_eclipse (nn_vendorid_t vendor) {
return vendor_equals (vendor, NN_VENDORID_ECLIPSE);
return vendor_equals (vendor, NN_VENDORID (ECLIPSE));
}
inline bool vendor_is_rti (nn_vendorid_t vendor) {
return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_RTI }});
return vendor_equals (vendor, NN_VENDORID (RTI));
}
inline bool vendor_is_opensplice (nn_vendorid_t vendor) {
return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_OSPL }});
return vendor_equals (vendor, NN_VENDORID (PRISMTECH_OSPL));
}
inline bool vendor_is_twinoaks (nn_vendorid_t vendor) {
return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_TWINOAKS }});
return vendor_equals (vendor, NN_VENDORID (TWINOAKS));
}
inline bool vendor_is_eprosima (nn_vendorid_t vendor) {
return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_EPROSIMA }});
return vendor_equals (vendor, NN_VENDORID (EPROSIMA));
}
inline bool vendor_is_cloud (nn_vendorid_t vendor) {
return vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_CLOUD }});
return vendor_equals (vendor, NN_VENDORID (PRISMTECH_CLOUD));
}
inline bool vendor_is_eclipse_or_opensplice (nn_vendorid_t vendor) {
return vendor_is_eclipse (vendor) | vendor_is_opensplice (vendor);
}
inline bool vendor_is_prismtech (nn_vendorid_t vendor) {
return (vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_OSPL }}) ||
vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_LITE }}) ||
vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_GATEWAY }}) ||
vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_JAVA }}) ||
vendor_equals (vendor, (nn_vendorid_t) {{ 0x01, NN_VENDORID_MINOR_PRISMTECH_CLOUD }}));
return (vendor_equals (vendor, NN_VENDORID (PRISMTECH_OSPL)) ||
vendor_equals (vendor, NN_VENDORID (PRISMTECH_LITE)) ||
vendor_equals (vendor, NN_VENDORID (PRISMTECH_GATEWAY)) ||
vendor_equals (vendor, NN_VENDORID (PRISMTECH_JAVA)) ||
vendor_equals (vendor, NN_VENDORID (PRISMTECH_CLOUD)));
}
inline bool vendor_is_eclipse_or_prismtech (nn_vendorid_t vendor) {
return vendor_is_eclipse (vendor) || vendor_is_prismtech (vendor);

View file

@ -88,12 +88,12 @@ inline void bswapSN (nn_sequence_number_t *sn)
#define fromBE8u(x) (x)
#endif
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p);
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p);
nn_entityid_t nn_hton_entityid (nn_entityid_t e);
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e);
nn_guid_t nn_hton_guid (nn_guid_t g);
nn_guid_t nn_ntoh_guid (nn_guid_t g);
ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p);
ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p);
ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e);
ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e);
ddsi_guid_t nn_hton_guid (ddsi_guid_t g);
ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g);
void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset);
void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits);

View file

@ -393,7 +393,7 @@ struct config
struct cfgst;
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid);
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid) ddsrt_nonnull((1,2));
void config_print_cfgst (struct cfgst *cfgst, const struct ddsrt_log_cfg *logcfg);
void config_free_source_info (struct cfgst *cfgst);
void config_fini (struct cfgst *cfgst);

View file

@ -36,7 +36,7 @@ int sedp_dispose_unregister_reader (struct reader *rd);
int sedp_write_topic (struct participant *pp, const struct nn_plist *datap);
int sedp_write_cm_participant (struct participant *pp, int alive);
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg);
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
#if defined (__cplusplus)
}

View file

@ -59,12 +59,12 @@ typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data);
struct prd_wr_match {
ddsrt_avl_node_t avlnode;
nn_guid_t wr_guid;
ddsi_guid_t wr_guid;
};
struct rd_pwr_match {
ddsrt_avl_node_t avlnode;
nn_guid_t pwr_guid;
ddsi_guid_t pwr_guid;
#ifdef DDSI_INCLUDE_SSM
nn_locator_t ssm_mc_loc;
nn_locator_t ssm_src_loc;
@ -73,17 +73,17 @@ struct rd_pwr_match {
struct wr_rd_match {
ddsrt_avl_node_t avlnode;
nn_guid_t rd_guid;
ddsi_guid_t rd_guid;
};
struct rd_wr_match {
ddsrt_avl_node_t avlnode;
nn_guid_t wr_guid;
ddsi_guid_t wr_guid;
};
struct wr_prd_match {
ddsrt_avl_node_t avlnode;
nn_guid_t prd_guid; /* guid of the proxy reader */
ddsi_guid_t prd_guid; /* guid of the proxy reader */
unsigned assumed_in_sync: 1; /* set to 1 upon receipt of ack not nack'ing msgs */
unsigned has_replied_to_hb: 1; /* we must keep sending HBs until all readers have this set */
unsigned all_have_replied_to_hb: 1; /* true iff 'has_replied_to_hb' for all readers in subtree */
@ -91,8 +91,8 @@ struct wr_prd_match {
seqno_t min_seq; /* smallest ack'd seq nr in subtree */
seqno_t max_seq; /* sort-of highest ack'd seq nr in subtree (see augment function) */
seqno_t seq; /* highest acknowledged seq nr */
int num_reliable_readers_where_seq_equals_max;
nn_guid_t arbitrary_unacked_reader;
int32_t num_reliable_readers_where_seq_equals_max;
ddsi_guid_t arbitrary_unacked_reader;
nn_count_t next_acknack; /* next acceptable acknack sequence number */
nn_count_t next_nackfrag; /* next acceptable nackfrag sequence number */
nn_etime_t t_acknack_accepted; /* (local) time an acknack was last accepted */
@ -110,7 +110,7 @@ enum pwr_rd_match_syncstate {
struct pwr_rd_match {
ddsrt_avl_node_t avlnode;
nn_guid_t rd_guid;
ddsi_guid_t rd_guid;
nn_mtime_t tcreate;
nn_count_t count; /* most recent acknack sequence number */
nn_count_t next_heartbeat; /* next acceptable heartbeat (see also add_proxy_writer_to_reader) */
@ -134,7 +134,7 @@ struct ddsi_tkmap_instance;
struct entity_common {
enum entity_kind kind;
nn_guid_t guid;
ddsi_guid_t guid;
nn_wctime_t tupdate; /* timestamp of last update */
char *name;
uint64_t iid;
@ -188,7 +188,7 @@ struct participant
struct endpoint_common {
struct participant *pp;
nn_guid_t group_guid;
ddsi_guid_t group_guid;
};
struct generic_endpoint { /* FIXME: currently only local endpoints; proxies use entity_common + proxy_endpoint common */
@ -198,6 +198,7 @@ struct generic_endpoint { /* FIXME: currently only local endpoints; proxies use
enum writer_state {
WRST_OPERATIONAL, /* normal situation */
WRST_INTERRUPT, /* will be deleted, unblock throttle_writer but do not do anything further */
WRST_LINGERING, /* writer deletion has been requested but still has unack'd data */
WRST_DELETING /* writer is actually being deleted (removed from hash table) */
};
@ -259,7 +260,7 @@ struct writer
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" */
nn_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */
int num_reliable_readers; /* number of matching reliable PROXY readers */
int32_t num_reliable_readers; /* number of matching reliable PROXY readers */
ddsrt_avl_tree_t readers; /* all matching PROXY readers, see struct wr_prd_match */
ddsrt_avl_tree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
@ -281,7 +282,7 @@ struct reader
struct endpoint_common c;
status_cb_t status_cb;
void * status_cb_entity;
struct rhc * rhc; /* reader history, tracks registrations and data */
struct ddsi_rhc * rhc; /* reader history, tracks registrations and data */
struct dds_qos *xqos;
unsigned reliable: 1; /* 1 iff reader is reliable */
unsigned handle_as_transient_local: 1; /* 1 iff reader wants historical data from proxy writers */
@ -306,7 +307,7 @@ struct proxy_participant
nn_vendorid_t vendor; /* vendor code from discovery */
unsigned bes; /* built-in endpoint set */
unsigned prismtech_bes; /* prismtech-specific extension of built-in endpoints set */
nn_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */
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 */
struct addrset *as_default; /* default address set to use for user data traffic */
@ -333,7 +334,7 @@ struct proxy_participant
participant. */
struct proxy_group {
ddsrt_avl_node_t avlnode;
nn_guid_t guid;
ddsi_guid_t guid;
char *name;
struct proxy_participant *proxypp; /* uncounted backref to proxy participant */
struct dds_qos *xqos; /* publisher/subscriber QoS */
@ -345,9 +346,8 @@ struct proxy_endpoint_common
struct proxy_endpoint_common *next_ep; /* next \ endpoint belonging to this proxy participant */
struct proxy_endpoint_common *prev_ep; /* prev / -- this is in arbitrary ordering */
struct dds_qos *xqos; /* proxy endpoint QoS lives here; FIXME: local ones should have it moved to common as well */
struct ddsi_sertopic * topic; /* topic may be NULL: for built-ins, but also for never-yet matched proxies (so we don't have to know the topic; when we match, we certainly do know) */
struct addrset *as; /* address set to use for communicating with this endpoint */
nn_guid_t group_guid; /* 0:0:0:0 if not available */
ddsi_guid_t group_guid; /* 0:0:0:0 if not available */
nn_vendorid_t vendor; /* cached from proxypp->vendor */
seqno_t seq; /* sequence number of most recent SEDP message */
};
@ -356,8 +356,8 @@ struct proxy_writer {
struct entity_common e;
struct proxy_endpoint_common c;
ddsrt_avl_tree_t readers; /* matching LOCAL readers, see pwr_rd_match */
int n_reliable_readers; /* number of those that are reliable */
int n_readers_out_of_sync; /* number of those that require special handling (accepting historical data, waiting for historical data set to become complete) */
int32_t n_reliable_readers; /* number of those that are reliable */
int32_t n_readers_out_of_sync; /* number of those that require special handling (accepting historical data, waiting for historical data set to become complete) */
seqno_t last_seq; /* highest known seq published by the writer, not last delivered */
uint32_t last_fragnum; /* last known frag for last_seq, or ~0u if last_seq not partial */
nn_count_t nackfragcount; /* last nackfrag seq number */
@ -400,17 +400,18 @@ extern const ddsrt_avl_treedef_t deleted_participants_treedef;
#define DPG_LOCAL 1
#define DPG_REMOTE 2
struct deleted_participants_admin;
struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay);
struct deleted_participants_admin *deleted_participants_admin_new (const ddsrt_log_cfg_t *logcfg, int64_t delay);
void deleted_participants_admin_free (struct deleted_participants_admin *admin);
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what);
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what);
nn_entityid_t to_entityid (unsigned u);
int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid);
int is_builtin_endpoint (nn_entityid_t id, nn_vendorid_t vendorid);
bool is_null_guid (const ddsi_guid_t *guid);
ddsi_entityid_t to_entityid (unsigned u);
int is_builtin_entityid (ddsi_entityid_t id, nn_vendorid_t vendorid);
int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid);
bool is_local_orphan_endpoint (const struct entity_common *e);
int is_writer_entityid (nn_entityid_t id);
int is_reader_entityid (nn_entityid_t id);
int is_keyed_endpoint_entityid (nn_entityid_t id);
int is_writer_entityid (ddsi_entityid_t id);
int is_reader_entityid (ddsi_entityid_t id);
int is_keyed_endpoint_entityid (ddsi_entityid_t id);
nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
/* Interface for glue code between the OpenSplice kernel and the DDSI
@ -491,7 +492,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e);
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* The configured maximum number of participants has been reached.
*/
dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
/**
* @brief Create a new participant in the domain. See also new_participant_guid.
@ -515,7 +516,7 @@ dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv
* @retval DDS_RETCODE_OUT_OF_RESOURCES
* The configured maximum number of participants has been reached.
*/
dds_return_t new_participant (struct nn_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
dds_return_t new_participant (struct ddsi_guid *ppguid, struct q_globals *gv, unsigned flags, const struct nn_plist *plist);
/**
* @brief Initiate the deletion of the participant:
@ -541,9 +542,9 @@ dds_return_t new_participant (struct nn_guid *ppguid, struct q_globals *gv, unsi
* @retval DDS_RETCODE_BAD_PARAMETER
* ppguid lookup failed.
*/
dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid);
dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *ppguid);
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 nn_guid *guid);
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid);
/* 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
@ -554,9 +555,9 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity
GUID "ppguid". May return NULL if participant unknown or
writer/reader already known. */
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct nn_guid *rdguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct q_globals *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
void update_reader_qos (struct reader *rd, const struct dds_qos *xqos);
void update_writer_qos (struct writer *wr, const struct dds_qos *xqos);
@ -569,16 +570,17 @@ int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_sta
void writer_set_retransmitting (struct writer *wr);
void writer_clear_retransmitting (struct writer *wr);
dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid);
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid);
dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid);
dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid);
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid);
dds_return_t delete_writer_nolinger_locked (struct writer *wr);
dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid);
dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid);
struct local_orphan_writer {
struct writer wr;
};
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc);
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc);
void delete_local_orphan_writer (struct local_orphan_writer *wr);
/* To create or delete a new proxy participant: "guid" MUST have the
@ -605,8 +607,8 @@ void delete_local_orphan_writer (struct local_orphan_writer *wr);
/* Set when this proxy participant is not to be announced on the built-in topics yet */
#define CF_PROXYPP_NO_SPDP (1 << 3)
void new_proxy_participant (struct q_globals *gv, const struct nn_guid *guid, unsigned bes, unsigned prismtech_bes, const struct nn_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
void new_proxy_participant (struct q_globals *gv, const struct ddsi_guid *guid, unsigned bes, unsigned prismtech_bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct nn_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, nn_wctime_t timestamp, seqno_t seq);
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit);
enum update_proxy_participant_source {
UPD_PROXYPP_SPDP,
@ -621,8 +623,8 @@ void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bo
/* 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 nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq);
int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq
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);
int new_proxy_reader (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const struct nn_plist *plist, nn_wctime_t timestamp, seqno_t seq
#ifdef DDSI_INCLUDE_SSM
, int favours_ssm
#endif
@ -633,22 +635,24 @@ int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const
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 nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
int delete_proxy_reader (struct q_globals *gv, const struct nn_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);
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 new_proxy_group (const struct nn_guid *guid, const char *name, const struct dds_qos *xqos, nn_wctime_t timestamp);
void delete_proxy_group (struct ephash *guid_hash, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit);
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);
/* Call this to empty all address sets of all writers to stop all outgoing traffic, or to
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 local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok);
struct ddsi_writer_info;
DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos);
#if defined (__cplusplus)
}
#endif

View file

@ -25,7 +25,7 @@ struct writer;
struct proxy_participant;
struct proxy_reader;
struct proxy_writer;
struct nn_guid;
struct ddsi_guid;
enum entity_kind {
EK_PARTICIPANT,
@ -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 nn_guid *guid);
void *ephash_lookup_guid (const struct ephash *eh, const struct nn_guid *guid, enum entity_kind kind);
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);
struct participant *ephash_lookup_participant_guid (const struct ephash *eh, const struct nn_guid *guid);
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *eh, const struct nn_guid *guid);
struct writer *ephash_lookup_writer_guid (const struct ephash *eh, const struct nn_guid *guid);
struct reader *ephash_lookup_reader_guid (const struct ephash *eh, const struct nn_guid *guid);
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *eh, const struct nn_guid *guid);
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *eh, const struct nn_guid *guid);
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);
/* Enumeration of entries in the hash table:

View file

@ -158,7 +158,7 @@ struct q_globals {
/* GUID to be used in next call to new_participant; also protected
by privileged_pp_lock */
struct nn_guid next_ppguid;
struct ddsi_guid ppguid_base;
/* number of up, non-loopback, IPv4/IPv6 interfaces, the index of
the selected/preferred one, and the discovered interfaces. */

View file

@ -116,7 +116,7 @@ typedef struct nn_prismtech_participant_version_info
} nn_prismtech_participant_version_info_t;
typedef struct nn_prismtech_eotgroup_tid {
nn_entityid_t writer_entityid;
ddsi_entityid_t writer_entityid;
uint32_t transactionId;
} nn_prismtech_eotgroup_tid_t;
@ -140,9 +140,9 @@ typedef struct nn_plist {
uint32_t participant_builtin_endpoints;
dds_duration_t participant_lease_duration;
/* nn_content_filter_property_t content_filter_property; */
nn_guid_t participant_guid;
nn_guid_t endpoint_guid;
nn_guid_t group_guid;
ddsi_guid_t participant_guid;
ddsi_guid_t endpoint_guid;
ddsi_guid_t group_guid;
#if 0 /* reserved, rather than NIY */
nn_entityid_t participant_entityid;
nn_entityid_t group_entityid;

View file

@ -13,6 +13,7 @@
#define NN_PROTOCOL_H
#include "dds/ddsrt/endian.h"
#include "dds/ddsrt/misc.h"
#include "dds/ddsi/q_feature_check.h"
#include "dds/ddsi/q_rtps.h"
@ -115,7 +116,7 @@ typedef struct Header {
nn_protocolid_t protocol;
nn_protocol_version_t version;
nn_vendorid_t vendorid;
nn_guid_prefix_t guid_prefix;
ddsi_guid_prefix_t guid_prefix;
} Header_t;
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
#define NN_PROTOCOLID_AS_UINT32 (((uint32_t)'R' << 0) | ((uint32_t)'T' << 8) | ((uint32_t)'P' << 16) | ((uint32_t)'S' << 24))
@ -161,12 +162,12 @@ typedef struct InfoTimestamp {
typedef struct EntityId {
SubmessageHeader_t smhdr;
nn_entityid_t entityid;
ddsi_entityid_t entityid;
} EntityId_t;
typedef struct InfoDST {
SubmessageHeader_t smhdr;
nn_guid_prefix_t guid_prefix;
ddsi_guid_prefix_t guid_prefix;
} InfoDST_t;
typedef struct InfoSRC {
@ -174,7 +175,7 @@ typedef struct InfoSRC {
unsigned unused;
nn_protocol_version_t version;
nn_vendorid_t vendorid;
nn_guid_prefix_t guid_prefix;
ddsi_guid_prefix_t guid_prefix;
} InfoSRC_t;
#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN
@ -196,8 +197,8 @@ typedef struct Data_DataFrag_common {
SubmessageHeader_t smhdr;
uint16_t extraFlags;
uint16_t octetsToInlineQos;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_t writerSN;
} Data_DataFrag_common_t;
@ -223,26 +224,30 @@ typedef struct MsgLen {
uint32_t length;
} MsgLen_t;
DDSRT_WARNING_MSVC_OFF(4200)
typedef struct AckNack {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_set_header_t readerSNState;
uint32_t bits[];
/* nn_count_t count; */
} AckNack_t;
DDSRT_WARNING_MSVC_ON(4200)
#define ACKNACK_FLAG_FINAL 0x02u
#define ACKNACK_SIZE(numbits) (offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits) + 4)
#define ACKNACK_SIZE_MAX ACKNACK_SIZE (256u)
DDSRT_WARNING_MSVC_OFF(4200)
typedef struct Gap {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_t gapStart;
nn_sequence_number_set_header_t gapList;
uint32_t bits[];
} Gap_t;
DDSRT_WARNING_MSVC_ON(4200)
#define GAP_SIZE(numbits) (offsetof (Gap_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits))
#define GAP_SIZE_MAX GAP_SIZE (256u)
@ -254,8 +259,8 @@ typedef struct InfoTS {
typedef struct Heartbeat {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_t firstSN;
nn_sequence_number_t lastSN;
nn_count_t count;
@ -265,22 +270,24 @@ typedef struct Heartbeat {
typedef struct HeartbeatFrag {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_t writerSN;
nn_fragment_number_t lastFragmentNum;
nn_count_t count;
} HeartbeatFrag_t;
DDSRT_WARNING_MSVC_OFF(4200)
typedef struct NackFrag {
SubmessageHeader_t smhdr;
nn_entityid_t readerId;
nn_entityid_t writerId;
ddsi_entityid_t readerId;
ddsi_entityid_t writerId;
nn_sequence_number_t writerSN;
nn_fragment_number_set_header_t fragmentNumberState;
uint32_t bits[];
/* nn_count_t count; */
} NackFrag_t;
DDSRT_WARNING_MSVC_ON(4200)
#define NACKFRAG_SIZE(numbits) (offsetof (NackFrag_t, bits) + NN_FRAGMENT_NUMBER_SET_BITS_SIZE (numbits) + 4)
#define NACKFRAG_SIZE_MAX NACKFRAG_SIZE (256u)
@ -305,12 +312,14 @@ typedef union Submessage {
PT_InfoContainer_t pt_infocontainer;
} Submessage_t;
DDSRT_WARNING_MSVC_OFF(4200)
typedef struct ParticipantMessageData {
nn_guid_prefix_t participantGuidPrefix;
ddsi_guid_prefix_t participantGuidPrefix;
uint32_t kind; /* really 4 octets */
uint32_t length;
char value[];
} ParticipantMessageData_t;
DDSRT_WARNING_MSVC_ON(4200)
#define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u
#define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u
#define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u

View file

@ -30,14 +30,14 @@ struct nn_rsample_info;
struct nn_defrag;
struct nn_reorder;
struct nn_dqueue;
struct nn_guid;
struct ddsi_guid;
struct proxy_writer;
struct nn_fragment_number_set;
struct nn_sequence_number_set;
typedef int (*nn_dqueue_handler_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const struct nn_guid *rdguid, void *qarg);
typedef int (*nn_dqueue_handler_t) (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const struct ddsi_guid *rdguid, void *qarg);
struct nn_rmsg_chunk {
struct nn_rbuf *rbuf;
@ -102,8 +102,8 @@ struct nn_rmsg {
#define NN_RMSG_PAYLOADOFF(m, o) (NN_RMSG_PAYLOAD (m) + (o))
struct receiver_state {
nn_guid_prefix_t src_guid_prefix; /* 12 */
nn_guid_prefix_t dst_guid_prefix; /* 12 */
ddsi_guid_prefix_t src_guid_prefix; /* 12 */
ddsi_guid_prefix_t dst_guid_prefix; /* 12 */
struct addrset *reply_locators; /* 4/8 */
int forme; /* 4 */
nn_vendorid_t vendor; /* 2 */
@ -234,7 +234,7 @@ void nn_dqueue_free (struct nn_dqueue *q);
bool nn_dqueue_enqueue_deferred_wakeup (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void dd_dqueue_enqueue_trigger (struct nn_dqueue *q);
void nn_dqueue_enqueue (struct nn_dqueue *q, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const nn_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres);
void nn_dqueue_enqueue_callback (struct nn_dqueue *q, nn_dqueue_callback_t cb, void *arg);
int nn_dqueue_is_full (struct nn_dqueue *q);
void nn_dqueue_wait_until_empty_if_full (struct nn_dqueue *q);

View file

@ -25,7 +25,7 @@ struct recv_thread_arg;
void trigger_recv_threads (const struct q_globals *gv);
uint32_t recv_thread (void *vrecv_thread_arg);
uint32_t listen_thread (struct ddsi_tran_listener * listener);
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, void *qarg);
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg);
#if defined (__cplusplus)
}

View file

@ -1,86 +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
*/
#ifndef Q_RHC_H
#define Q_RHC_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "dds/export.h"
/* DDS_EXPORT inline i.c.w. __attributes__((visibility...)) and some compilers: */
#include "dds/ddsrt/attributes.h"
#include "dds/ddsi/q_rtps.h"
#if defined (__cplusplus)
extern "C" {
#endif
struct dds_qos;
struct ddsi_tkmap_instance;
struct ddsi_serdata;
struct ddsi_sertopic;
struct entity_common;
struct proxy_writer_info
{
nn_guid_t guid;
bool auto_dispose;
int32_t ownership_strength;
uint64_t iid;
};
struct rhc;
typedef void (*rhc_free_t) (struct rhc *rhc);
typedef bool (*rhc_store_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
typedef void (*rhc_unregister_wr_t) (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
typedef void (*rhc_relinquish_ownership_t) (struct rhc * __restrict rhc, const uint64_t wr_iid);
typedef void (*rhc_set_qos_t) (struct rhc *rhc, const struct dds_qos *qos);
struct rhc_ops {
rhc_store_t store;
rhc_unregister_wr_t unregister_wr;
rhc_relinquish_ownership_t relinquish_ownership;
rhc_set_qos_t set_qos;
rhc_free_t free;
};
struct rhc {
const struct rhc_ops *ops;
};
DDS_EXPORT inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) {
return rhc->ops->store (rhc, pwr_info, sample, tk);
}
DDS_EXPORT inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info) {
rhc->ops->unregister_wr (rhc, pwr_info);
}
DDS_EXPORT inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid) {
rhc->ops->relinquish_ownership (rhc, wr_iid);
}
DDS_EXPORT inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos) {
rhc->ops->set_qos (rhc, qos);
}
DDS_EXPORT inline void rhc_free (struct rhc *rhc) {
rhc->ops->free (rhc);
}
DDS_EXPORT void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos);
#if defined (__cplusplus)
}
#endif
#endif /* Q_RHC_H */

View file

@ -13,6 +13,7 @@
#define NN_RTPS_H
#include "dds/ddsi/ddsi_vendor.h"
#include "dds/ddsi/ddsi_guid.h"
#if defined (__cplusplus)
extern "C" {
@ -21,17 +22,6 @@ extern "C" {
typedef struct {
uint8_t major, minor;
} nn_protocol_version_t;
typedef union nn_guid_prefix {
unsigned char s[12];
uint32_t u[3];
} nn_guid_prefix_t;
typedef union nn_entityid {
uint32_t u;
} nn_entityid_t;
typedef struct nn_guid {
nn_guid_prefix_t prefix;
nn_entityid_t entityid;
} nn_guid_t;
typedef int64_t seqno_t;
#define MAX_SEQ_NUMBER INT64_MAX

View file

@ -98,12 +98,9 @@ struct thread_states {
extern DDS_EXPORT struct thread_states thread_states;
extern ddsrt_thread_local struct thread_state1 *tsd_thread_state;
DDS_EXPORT void thread_states_init_static (void);
DDS_EXPORT void thread_states_init (unsigned maxthreads);
DDS_EXPORT void thread_states_fini (void);
DDS_EXPORT bool thread_states_fini (void);
DDS_EXPORT void upgrade_main_thread (void);
DDS_EXPORT void downgrade_main_thread (void);
DDS_EXPORT const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name);
DDS_EXPORT dds_return_t create_thread_with_properties (struct thread_state1 **ts1, struct config_thread_properties_listelem const * const tprops, const char *name, uint32_t (*f) (void *arg), void *arg);
DDS_EXPORT dds_return_t create_thread (struct thread_state1 **ts, const struct q_globals *gv, const char *name, uint32_t (*f) (void *arg), void *arg);

View file

@ -42,7 +42,7 @@ 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, nn_entityid_t dst, int issync);
void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, ddsi_entityid_t dst, int issync);
#if defined (__cplusplus)
}

View file

@ -46,8 +46,8 @@ DDS_EXPORT dds_return_t xeventq_start (struct xeventq *evq, const char *name); /
DDS_EXPORT void xeventq_stop (struct xeventq *evq);
DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg);
DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, nn_guid_prefix_t * id);
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, nn_guid_prefix_t * id);
DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, ddsi_guid_prefix_t * id);
DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, ddsi_guid_prefix_t * id);
/* Returns 1 if queued, 0 otherwise (no point in returning the
event, you can't do anything with it anyway) */
@ -57,11 +57,11 @@ DDS_EXPORT int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg
DDS_EXPORT void delete_xevent (struct xevent *ev);
DDS_EXPORT int resched_xevent_if_earlier (struct xevent *ev, nn_mtime_t tsched);
DDS_EXPORT struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *wr_guid);
DDS_EXPORT struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pwr_guid, const nn_guid_t *rd_guid);
DDS_EXPORT struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid, const nn_guid_t *proxypp_guid);
DDS_EXPORT struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *pp_guid);
DDS_EXPORT struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const nn_guid_t *guid);
DDS_EXPORT struct xevent *qxev_heartbeat (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *wr_guid);
DDS_EXPORT struct xevent *qxev_acknack (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pwr_guid, const ddsi_guid_t *rd_guid);
DDS_EXPORT struct xevent *qxev_spdp (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid, const ddsi_guid_t *proxypp_guid);
DDS_EXPORT struct xevent *qxev_pmd_update (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *pp_guid);
DDS_EXPORT struct xevent *qxev_delete_writer (struct xeventq *evq, nn_mtime_t tsched, const ddsi_guid_t *guid);
/* cb will be called with now = T_NEVER if the event is still enqueued when when xeventq_free starts cleaning up */
DDS_EXPORT struct xevent *qxev_callback (struct xeventq *evq, nn_mtime_t tsched, void (*cb) (struct xevent *xev, void *arg, nn_mtime_t now), void *arg);

View file

@ -54,10 +54,10 @@ void nn_xmsgpool_free (struct nn_xmsgpool *pool);
/* To allocate a new xmsg from the pool; if expected_size is NOT
exceeded, no reallocs will be performed, else the address of the
xmsg may change because of reallocing when appending to it. */
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const nn_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind);
struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind);
/* For sending to a particular destination (participant) */
void nn_xmsg_setdst1 (struct nn_xmsg *m, const nn_guid_prefix_t *gp, const nn_locator_t *addr);
void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr);
/* For sending to a particular proxy reader; this is a convenience
routine that extracts a suitable address from the proxy reader's
@ -80,7 +80,7 @@ int nn_xmsg_setencoderid (struct nn_xmsg *msg, uint32_t encoderid);
M must be a rexmit, and for all rexmits this must be called. It is
a separate function because the location may only become known at a
late-ish stage in the construction of the message. */
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, nn_entityid_t *readerId);
void nn_xmsg_set_data_readerId (struct nn_xmsg *m, ddsi_entityid_t *readerId);
/* If M and MADD are both xmsg's containing the same retransmit
message, this will merge the destination embedded in MADD into M.
@ -97,8 +97,8 @@ int nn_xmsg_merge_rexmit_destinations_wrlock_held (struct q_globals *gv, struct
/* To set writer ids for updating last transmitted sequence number;
wrfragid is 0 based, unlike DDSI but like other places where
fragment numbers are handled internally. */
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq);
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const nn_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid);
void nn_xmsg_setwriterseq (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq);
void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const ddsi_guid_t *wrguid, seqno_t wrseq, nn_fragment_number_t wrfragid);
/* Comparison function for retransmits: orders messages on writer
guid, sequence number and fragment id */
@ -109,7 +109,7 @@ size_t nn_xmsg_size (const struct nn_xmsg *m);
void *nn_xmsg_payload (size_t *sz, struct nn_xmsg *m);
void nn_xmsg_payload_to_plistsample (struct ddsi_plist_sample *dst, nn_parameterid_t keyparam, const struct nn_xmsg *m);
enum nn_xmsg_kind nn_xmsg_kind (const struct nn_xmsg *m);
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, nn_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid);
void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, ddsi_guid_t *wrguid, seqno_t *wrseq, nn_fragment_number_t *wrfragid);
void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker);
void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz);

View file

@ -32,6 +32,41 @@ typedef ddsi_octetseq_t dds_userdata_qospolicy_t;
typedef ddsi_octetseq_t dds_topicdata_qospolicy_t;
typedef ddsi_octetseq_t dds_groupdata_qospolicy_t;
typedef struct dds_property {
/* The propagate boolean will not be send over the wire.
* When the value is 'false', the complete struct shouldn't be send.
* It has to be the first variable within the structure because it
* is mapped to XbPROP in the serialiser. */
unsigned char propagate;
char *name;
char *value;
} dds_property_t;
typedef struct dds_propertyseq {
uint32_t n;
dds_property_t *props;
} dds_propertyseq_t;
typedef struct dds_binaryproperty {
/* The propagate boolean will not be send over the wire.
* When the value is 'false', the complete struct shouldn't be send.
* It has to be the first variable within the structure because it
* is mapped to XbPROP in the serialiser. */
unsigned char propagate;
char *name;
ddsi_octetseq_t value;
} dds_binaryproperty_t;
typedef struct dds_binarypropertyseq {
uint32_t n;
dds_binaryproperty_t *props;
} dds_binarypropertyseq_t;
typedef struct dds_property_qospolicy {
dds_propertyseq_t value;
dds_binarypropertyseq_t binary_value;
} dds_property_qospolicy_t;
typedef struct dds_durability_qospolicy {
dds_durability_kind_t kind;
} dds_durability_qospolicy_t;
@ -212,6 +247,7 @@ typedef struct dds_ignorelocal_qospolicy {
#define QP_PRISMTECH_SUBSCRIPTION_KEYS ((uint64_t)1 << 25)
#define QP_PRISMTECH_ENTITY_FACTORY ((uint64_t)1 << 27)
#define QP_CYCLONE_IGNORELOCAL ((uint64_t)1 << 30)
#define QP_PROPERTY_LIST ((uint64_t)1 << 31)
/* Partition QoS is not RxO according to the specification (DDS 1.2,
section 7.1.3), but communication will not take place unless it
@ -263,6 +299,7 @@ struct dds_qos {
/*x xR*/dds_subscription_keys_qospolicy_t subscription_keys;
/*x xR*/dds_reader_lifespan_qospolicy_t reader_lifespan;
/* x */dds_ignorelocal_qospolicy_t ignorelocal;
/*xxx */dds_property_qospolicy_t property;
};
struct nn_xmsg;

View file

@ -211,7 +211,12 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (ddsi_tran_factory_t fact, uint3
return NULL;
}
uc = (ddsi_raweth_conn_t) ddsrt_malloc (sizeof (*uc));
if ((uc = (ddsi_raweth_conn_t) ddsrt_malloc (sizeof (*uc))) == NULL)
{
ddsrt_close(sock);
return NULL;
}
memset (uc, 0, sizeof (*uc));
uc->m_sock = sock;
uc->m_ifindex = addr.sll_ifindex;
@ -226,7 +231,7 @@ static ddsi_tran_conn_t ddsi_raweth_create_conn (ddsi_tran_factory_t fact, uint3
uc->m_base.m_disable_multiplexing_fn = 0;
DDS_CTRACE (&fact->gv->logconfig, "ddsi_raweth_create_conn %s socket %d port %u\n", mcast ? "multicast" : "unicast", uc->m_sock, uc->m_base.m_base.m_port);
return uc ? &uc->m_base : NULL;
return &uc->m_base;
}
static int isbroadcast(const nn_locator_t *loc)

View file

@ -0,0 +1,18 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsi/ddsi_rhc.h"
extern inline void ddsi_rhc_free (struct ddsi_rhc *rhc);
extern inline bool ddsi_rhc_store (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
extern inline void ddsi_rhc_unregister_wr (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo);
extern inline void ddsi_rhc_relinquish_ownership (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid);
extern inline void ddsi_rhc_set_qos (struct ddsi_rhc *rhc, const struct dds_qos *qos);

View file

@ -45,3 +45,5 @@ extern inline void ddsi_serdata_to_ser_unref (struct ddsi_serdata *d, const ddsr
extern inline bool ddsi_serdata_to_sample (const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim);
extern inline bool ddsi_serdata_topicless_to_sample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim);
extern inline bool ddsi_serdata_eqkey (const struct ddsi_serdata *a, const struct ddsi_serdata *b);
extern inline bool ddsi_serdata_print (const struct ddsi_serdata *d, char *buf, size_t size);
extern inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size);

View file

@ -453,6 +453,7 @@ static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi
#ifndef NDEBUG
size_t keysize;
#endif
assert(rawkey);
switch (sample->keyparam)
{
case PID_PARTICIPANT_GUID:
@ -629,6 +630,32 @@ static bool serdata_default_topicless_to_sample_cdr_nokey (const struct ddsi_ser
return true;
}
static size_t serdata_default_print_cdr (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
{
const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common;
const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common;
dds_istream_t is;
dds_istream_from_serdata_default (&is, d);
if (d->c.kind == SDK_KEY)
return dds_stream_print_key (&is, tp, buf, size);
else
return dds_stream_print_sample (&is, tp, buf, size);
}
static size_t serdata_default_print_plist (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
{
/* FIXME: should change q_plist.c to print to a string instead of a log, and then drop the
logging of QoS in the rest of code, instead relying on this */
(void)sertopic_common; (void)serdata_common;
return (size_t) snprintf (buf, size, "(plist)");
}
static size_t serdata_default_print_raw (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size)
{
(void)sertopic_common; (void)serdata_common;
return (size_t) snprintf (buf, size, "(blob)");
}
const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = {
.get_size = serdata_default_get_size,
.eqkey = serdata_default_eqkey,
@ -641,7 +668,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = {
.to_ser_ref = serdata_default_to_ser_ref,
.to_ser_unref = serdata_default_to_ser_unref,
.to_topicless = serdata_default_to_topicless,
.topicless_to_sample = serdata_default_topicless_to_sample_cdr
.topicless_to_sample = serdata_default_topicless_to_sample_cdr,
.print = serdata_default_print_cdr
};
const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = {
@ -656,7 +684,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = {
.to_ser_ref = serdata_default_to_ser_ref,
.to_ser_unref = serdata_default_to_ser_unref,
.to_topicless = serdata_default_to_topicless,
.topicless_to_sample = serdata_default_topicless_to_sample_cdr_nokey
.topicless_to_sample = serdata_default_topicless_to_sample_cdr_nokey,
.print = serdata_default_print_cdr
};
const struct ddsi_serdata_ops ddsi_serdata_ops_plist = {
@ -671,7 +700,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_plist = {
.to_ser_ref = serdata_default_to_ser_ref,
.to_ser_unref = serdata_default_to_ser_unref,
.to_topicless = serdata_default_to_topicless,
.topicless_to_sample = 0
.topicless_to_sample = 0,
.print = serdata_default_print_plist
};
const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = {
@ -686,5 +716,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = {
.to_ser_ref = serdata_default_to_ser_ref,
.to_ser_unref = serdata_default_to_ser_unref,
.to_topicless = serdata_default_to_topicless,
.topicless_to_sample = 0
.topicless_to_sample = 0,
.print = serdata_default_print_raw
};

View file

@ -554,8 +554,9 @@ static ssize_t ddsi_tcp_conn_write (ddsi_tran_conn_t base, const nn_locator_t *d
/* If not connected attempt to conect */
if ((conn->m_sock == DDSRT_INVALID_SOCKET) && ! conn->m_base.m_server)
if (conn->m_sock == DDSRT_INVALID_SOCKET)
{
assert (!conn->m_base.m_server);
ddsi_tcp_conn_connect (conn, &msg);
if (conn->m_sock == DDSRT_INVALID_SOCKET)
{

View file

@ -265,7 +265,7 @@ void ddsi_threadmon_unregister_domain (struct ddsi_threadmon *sl, const struct q
dummy.gv = gv;
struct threadmon_domain *tmdom = ddsrt_hh_lookup (sl->domains, &dummy);
assert (tmdom);
ddsrt_hh_remove (sl->domains, tmdom);
(void) ddsrt_hh_remove (sl->domains, tmdom);
ddsrt_mutex_unlock (&sl->lock);
ddsrt_free (tmdom);
}

View file

@ -11,7 +11,7 @@
*/
#include "dds/ddsi/q_bswap.h"
nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p)
ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p)
{
int i;
for (i = 0; i < 3; i++)
@ -19,7 +19,7 @@ nn_guid_prefix_t nn_hton_guid_prefix (nn_guid_prefix_t p)
return p;
}
nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p)
ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p)
{
int i;
for (i = 0; i < 3; i++)
@ -27,26 +27,26 @@ nn_guid_prefix_t nn_ntoh_guid_prefix (nn_guid_prefix_t p)
return p;
}
nn_entityid_t nn_hton_entityid (nn_entityid_t e)
ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e)
{
e.u = toBE4u (e.u);
return e;
}
nn_entityid_t nn_ntoh_entityid (nn_entityid_t e)
ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e)
{
e.u = fromBE4u (e.u);
return e;
}
nn_guid_t nn_hton_guid (nn_guid_t g)
ddsi_guid_t nn_hton_guid (ddsi_guid_t g)
{
g.prefix = nn_hton_guid_prefix (g.prefix);
g.entityid = nn_hton_entityid (g.entityid);
return g;
}
nn_guid_t nn_ntoh_guid (nn_guid_t g)
ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g)
{
g.prefix = nn_ntoh_guid_prefix (g.prefix);
g.entityid = nn_ntoh_entityid (g.entityid);

View file

@ -1012,6 +1012,8 @@ static size_t cfg_note_vsnprintf (struct cfg_note_buf *bb, const char *fmt, va_l
return 0;
}
static void cfg_note_snprintf (struct cfg_note_buf *bb, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
static void cfg_note_snprintf (struct cfg_note_buf *bb, const char *fmt, ...)
{
/* The reason the 2nd call to os_vsnprintf is here and not inside
@ -1123,6 +1125,8 @@ static size_t cfg_note (struct cfgst *cfgst, uint32_t cat, size_t bsz, const cha
return 0;
}
static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...)
{
va_list ap;
@ -1134,6 +1138,8 @@ static void cfg_warning (struct cfgst *cfgst, const char *fmt, ...)
} while (bsz > 0);
}
static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...)
{
va_list ap;
@ -1146,6 +1152,8 @@ static enum update_result cfg_error (struct cfgst *cfgst, const char *fmt, ...)
return URES_ERROR;
}
static void cfg_logelem (struct cfgst *cfgst, uint32_t sources, const char *fmt, ...) ddsrt_attribute_format ((printf, 3, 4));
static void cfg_logelem (struct cfgst *cfgst, uint32_t sources, const char *fmt, ...)
{
/* 89 = 1 + 2 + 31 + 1 + 10 + 2*22: the number of characters in
@ -1317,13 +1325,16 @@ static enum update_result do_uint32_bitset (struct cfgst *cfgst, uint32_t *cats,
char *copy = ddsrt_strdup (value), *cursor = copy, *tok;
while ((tok = ddsrt_strsep (&cursor, ",")) != NULL)
{
const int idx = list_index (names, tok);
const int idx = list_index (names, tok[0] == '-' ? tok+1 : tok);
if (idx < 0)
{
const enum update_result ret = cfg_error (cfgst, "'%s' in '%s' undefined", tok, value);
ddsrt_free (copy);
return ret;
}
if (tok[0] == '-')
*cats &= ~codes[idx];
else
*cats |= codes[idx];
}
ddsrt_free (copy);
@ -1441,7 +1452,7 @@ static void pf_int64_unit (struct cfgst *cfgst, int64_t value, uint32_t sources,
}
assert (m > 0);
assert (unit != NULL);
cfg_logelem (cfgst, sources, "%lld %s", value / m, unit);
cfg_logelem (cfgst, sources, "%"PRId64" %s", value / m, unit);
}
}
@ -1517,10 +1528,10 @@ GENERIC_ENUM_CTYPE (standards_conformance, enum nn_standards_conformance)
/* "trace" is special: it enables (nearly) everything */
static const char *tracemask_names[] = {
"fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "trace", NULL
"fatal", "error", "warning", "info", "config", "discovery", "data", "radmin", "timing", "traffic", "topic", "tcp", "plist", "whc", "throttle", "rhc", "content", "trace", NULL
};
static const uint32_t tracemask_codes[] = {
DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL
DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_CONTENT, DDS_LC_ALL
};
static enum update_result uf_tracemask (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value)
@ -2383,6 +2394,8 @@ static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED
cfgst_push (cfgst, 0, &root_cfgelems[0], cfgst_parent (cfgst));
cfgst->implicit_toplevel = ITL_INSERTED_2;
}
cfgst->source = (cfgst->source == 0) ? 1 : cfgst->source << 1;
cfgst->first_data_in_source = true;
}
}
@ -2691,10 +2704,13 @@ static FILE *config_open_file (char *tok, char **cursor, uint32_t domid)
return fp;
}
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid)
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid)
{
int ok = 1;
struct cfgst *cfgst;
char env_input[32];
char *copy, *cursor;
struct ddsrt_xmlp_callbacks cb;
memset (cfg, 0, sizeof (*cfg));
@ -2715,18 +2731,14 @@ struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t
ends up on the right value */
cfgst->cfg->domainId = domid;
/* configfile == NULL will get you the default configuration */
if (configfile) {
char env_input[32];
char *copy = ddsrt_strdup (configfile), *cursor = copy;
struct ddsrt_xmlp_callbacks cb;
cb.attr = proc_attr;
cb.elem_close = proc_elem_close;
cb.elem_data = proc_elem_data;
cb.elem_open = proc_elem_open;
cb.error = proc_error;
copy = ddsrt_strdup (config);
cursor = copy;
while (*cursor && (isspace ((unsigned char) *cursor) || *cursor == ','))
cursor++;
while (ok && cursor && cursor[0])
@ -2780,7 +2792,6 @@ struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t
}
}
ddsrt_free (copy);
}
/* Set defaults for everything not set that we have a default value
for, signal errors for things unset but without a default. */

View file

@ -21,6 +21,7 @@
#include "dds/ddsrt/md5.h"
#include "dds/ddsrt/sync.h"
#include "dds/ddsrt/avl.h"
#include "dds/ddsrt/string.h"
#include "dds/ddsi/q_protocol.h"
#include "dds/ddsi/q_rtps.h"
#include "dds/ddsi/q_misc.h"
@ -302,8 +303,8 @@ int spdp_write (struct participant *pp)
ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2;
ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock);
ddsrt_gethostname(node, sizeof(node)-1);
node[sizeof(node)-1] = '\0';
if (ddsrt_gethostname(node, sizeof(node)-1) < 0)
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);
@ -352,7 +353,7 @@ int spdp_dispose_unregister (struct participant *pp)
return ret;
}
static unsigned pseudo_random_delay (const nn_guid_t *x, const nn_guid_t *y, nn_mtime_t tnow)
static unsigned pseudo_random_delay (const ddsi_guid_t *x, const ddsi_guid_t *y, nn_mtime_t tnow)
{
/* You know, an ordinary random generator would be even better, but
the C library doesn't have a reentrant one and I don't feel like
@ -381,7 +382,7 @@ static unsigned pseudo_random_delay (const nn_guid_t *x, const nn_guid_t *y, nn_
return (unsigned) (m >> 32);
}
static void respond_to_spdp (const struct q_globals *gv, const nn_guid_t *dest_proxypp_guid)
static void respond_to_spdp (const struct q_globals *gv, const ddsi_guid_t *dest_proxypp_guid)
{
struct ephash_enum_participant est;
struct participant *pp;
@ -409,9 +410,8 @@ static void respond_to_spdp (const struct q_globals *gv, const nn_guid_t *dest_p
static int handle_SPDP_dead (const struct receiver_state *rst, nn_wctime_t timestamp, const nn_plist_t *datap, unsigned statusinfo)
{
struct q_globals * const gv = rst->gv;
nn_guid_t guid;
ddsi_guid_t guid;
if (!(gv->logconfig.c.mask & DDS_LC_DISCOVERY))
GVLOGDISC ("SPDP ST%x", statusinfo);
if (datap->present & PP_PARTICIPANT_GUID)
@ -455,7 +455,7 @@ static void allowmulticast_aware_add_to_addrset (const struct q_globals *gv, uin
add_to_addrset (gv, as, loc);
}
static struct proxy_participant *find_ddsi2_proxy_participant (const struct ephash *guid_hash, const nn_guid_t *ppguid)
static struct proxy_participant *find_ddsi2_proxy_participant (const struct ephash *guid_hash, const ddsi_guid_t *ppguid)
{
struct ephash_enum_proxy_participant it;
struct proxy_participant *pp;
@ -469,7 +469,7 @@ static struct proxy_participant *find_ddsi2_proxy_participant (const struct epha
return pp;
}
static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const nn_guid_t *ddsi2guid, nn_wctime_t timestamp)
static void make_participants_dependent_on_ddsi2 (struct q_globals *gv, const ddsi_guid_t *ddsi2guid, nn_wctime_t timestamp)
{
struct ephash_enum_proxy_participant it;
struct proxy_participant *pp, *d2pp;
@ -514,17 +514,16 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER |
NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER;
struct addrset *as_meta, *as_default;
struct proxy_participant *proxypp;
unsigned builtin_endpoint_set;
unsigned prismtech_builtin_endpoint_set;
nn_guid_t privileged_pp_guid;
ddsi_guid_t privileged_pp_guid;
dds_duration_t lease_duration;
unsigned custom_flags = 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]);
return 1;
return 0;
}
/* At some point the RTI implementation didn't mention
@ -563,50 +562,57 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
prismtech_builtin_endpoint_set |= NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER | NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
}
/* Local SPDP packets may be looped back, and that may include ones
currently being deleted. The first thing that happens when
deleting a participant is removing it from the hash table, and
consequently the looped back packet may appear to be from an
unknown participant. So we handle that, too. */
/* Do we know this GUID already? */
{
struct entity_common *existing_entity;
if ((existing_entity = ephash_lookup_guid_untyped (gv->guid_hash, &datap->participant_guid)) == NULL)
{
/* Local SPDP packets may be looped back, and that can include ones
for participants currently being deleted. The first thing that
happens when deleting a participant is removing it from the hash
table, and consequently the looped back packet may appear to be
from an unknown participant. So we handle that. */
if (is_deleted_participant_guid (gv->deleted_participants, &datap->participant_guid, DPG_REMOTE))
{
RSTTRACE ("SPDP ST0 "PGUIDFMT" (recently deleted)", PGUID (datap->participant_guid));
return 1;
}
{
int islocal = 0;
if (ephash_lookup_participant_guid (gv->guid_hash, &datap->participant_guid))
islocal = 1;
if (islocal)
{
RSTTRACE ("SPDP ST0 "PGUIDFMT" (local %d)", PGUID (datap->participant_guid), islocal);
return 0;
}
}
if ((proxypp = ephash_lookup_proxy_participant_guid (gv->guid_hash, &datap->participant_guid)) != NULL)
else if (existing_entity->kind == EK_PARTICIPANT)
{
/* 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. */
RSTTRACE ("SPDP ST0 "PGUIDFMT" (local)", PGUID (datap->participant_guid));
return 0;
}
else if (existing_entity->kind == EK_PROXY_PARTICIPANT)
{
struct proxy_participant *proxypp = (struct proxy_participant *) existing_entity;
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 ());
ddsrt_mutex_lock (&proxypp->e.lock);
if (proxypp->implicitly_created || seq > proxypp->seq)
{
if (proxypp->implicitly_created)
GVLOGDISC (" (NEW was-implicitly-created)");
else
GVLOGDISC (" (update)");
interesting = 1;
if (!(gv->logconfig.c.mask & DDS_LC_TRACE))
GVLOGDISC ("SPDP ST0 "PGUIDFMT, PGUID (datap->participant_guid));
GVLOGDISC (proxypp->implicitly_created ? " (NEW was-implicitly-created)" : " (update)");
proxypp->implicitly_created = 0;
update_proxy_participant_plist_locked (proxypp, seq, datap, UPD_PROXYPP_SPDP, timestamp);
}
ddsrt_mutex_unlock (&proxypp->e.lock);
return interesting;
}
else
{
/* mismatch on entity kind: that should never have gotten past the
input validation */
GVWARNING ("data (SPDP, vendor %u.%u): "PGUIDFMT" kind mismatch\n", rst->vendor.id[0], rst->vendor.id[1], PGUID (datap->participant_guid));
return 0;
}
}
GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x ptbes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set, prismtech_builtin_endpoint_set);
@ -646,7 +652,7 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, nn_
privileged_pp_guid.prefix = rst->src_guid_prefix;
privileged_pp_guid.entityid.u = NN_ENTITYID_PARTICIPANT;
if ((builtin_endpoint_set & bes_sedp_announcer_mask) != bes_sedp_announcer_mask &&
memcmp (&privileged_pp_guid, &datap->participant_guid, sizeof (nn_guid_t)) != 0)
memcmp (&privileged_pp_guid, &datap->participant_guid, sizeof (ddsi_guid_t)) != 0)
{
GVLOGDISC (" (depends on "PGUIDFMT")", PGUID (privileged_pp_guid));
/* never expire lease for this proxy: it won't actually expire
@ -791,10 +797,9 @@ static void handle_SPDP (const struct receiver_state *rst, seqno_t seq, nn_wctim
{
struct q_globals * const gv = rst->gv;
const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
RSTTRACE("SPDP ST%x", statusinfo);
if (data == NULL)
{
RSTTRACE(" no payload?\n");
RSTTRACE ("SPDP ST%x no payload?\n", statusinfo);
return;
}
else
@ -881,7 +886,7 @@ static void add_locator_to_ps (const nn_locator_t *loc, void *varg)
static int sedp_write_endpoint
(
struct writer *wr, int alive, const nn_guid_t *epguid,
struct writer *wr, int alive, const ddsi_guid_t *epguid,
const struct entity_common *common, const struct endpoint_common *epcommon,
const dds_qos_t *xqos, struct addrset *as)
{
@ -1040,9 +1045,9 @@ static const char *durability_to_string (dds_durability_kind_t k)
return "undefined-durability";
}
static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const nn_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq)
static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv, const ddsi_guid_t *ppguid, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp, seqno_t seq)
{
nn_guid_t privguid;
ddsi_guid_t privguid;
nn_plist_t pp_plist;
if (memcmp (&ppguid->prefix, src_guid_prefix, sizeof (ppguid->prefix)) == 0)
@ -1120,14 +1125,14 @@ static struct proxy_participant *implicitly_create_proxypp (struct q_globals *gv
return ephash_lookup_proxy_participant_guid (gv->guid_hash, ppguid);
}
static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const nn_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp)
static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, nn_plist_t *datap /* note: potentially modifies datap */, const ddsi_guid_prefix_t *src_guid_prefix, nn_vendorid_t vendorid, nn_wctime_t timestamp)
{
#define E(msg, lbl) do { GVLOGDISC (msg); goto lbl; } while (0)
struct q_globals * const gv = rst->gv;
struct proxy_participant *pp;
struct proxy_writer * pwr = NULL;
struct proxy_reader * prd = NULL;
nn_guid_t ppguid;
ddsi_guid_t ppguid;
dds_qos_t *xqos;
int reliable;
struct addrset *as;
@ -1466,7 +1471,7 @@ int sedp_write_cm_participant (struct participant *pp, int alive)
return ret;
}
static void handle_SEDP_CM (const struct receiver_state *rst, nn_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
static void handle_SEDP_CM (const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len)
{
struct q_globals * const gv = rst->gv;
const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */
@ -1552,7 +1557,7 @@ static int defragment (unsigned char **datap, const struct nn_rdata *fragchain,
}
}
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const nn_guid_t *rdguid), UNUSED_ARG (void *qarg))
int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const ddsi_guid_t *rdguid), UNUSED_ARG (void *qarg))
{
struct q_globals * const gv = sampleinfo->rst->gv;
struct proxy_writer *pwr;
@ -1564,7 +1569,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
} keyhash_payload;
unsigned statusinfo;
int need_keyhash;
nn_guid_t srcguid;
ddsi_guid_t srcguid;
Data_DataFrag_common_t *msg;
unsigned char data_smhdr_flags;
nn_plist_t qos;
@ -1643,7 +1648,6 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str
/* Built-ins still do their own deserialization (SPDP <=> pwr ==
NULL)). */
assert (pwr == NULL || pwr->c.topic == NULL);
if (statusinfo == 0)
{
if (datasz == 0 || !(data_smhdr_flags & DATA_FLAG_DATAFLAG))

View file

@ -57,6 +57,8 @@ struct debug_monitor {
int stop;
};
static int cpf (ddsi_tran_conn_t conn, const char *fmt, ...) ddsrt_attribute_format ((printf, 2, 3));
static int cpf (ddsi_tran_conn_t conn, const char *fmt, ...)
{
nn_locator_t loc;
@ -107,35 +109,34 @@ static int print_addrset_if_notempty (ddsi_tran_conn_t conn, const char *prefix,
return print_addrset (conn, prefix, as, suffix);
}
static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e,
const struct dds_qos *xqos, const struct ddsi_sertopic *topic)
static int print_any_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct dds_qos *xqos)
{
int x = 0;
x += cpf (conn, " %s %x:%x:%x:%x ", label, PGUID (e->guid));
x += cpf (conn, " %s "PGUIDFMT" ", label, PGUID (e->guid));
if (xqos->present & QP_PARTITION)
{
if (xqos->partition.n > 1) cpf (conn, "{");
for (uint32_t i = 0; i < xqos->partition.n; i++)
x += cpf (conn, "%s%s", i == 0 ? "" : ",", xqos->partition.strs[i]);
if (xqos->partition.n > 1) cpf (conn, "}");
x += cpf (conn, ".%s/%s",
topic && topic->name ? topic->name : (xqos->present & QP_TOPIC_NAME) ? xqos->topic_name : "(null)",
topic && topic->type_name ? topic->type_name : (xqos->present & QP_TYPE_NAME) ? xqos->type_name : "(null)");
const char *topic_name = (xqos->present & QP_TOPIC_NAME) ? xqos->topic_name : "null";
const char *topic_typename = (xqos->present & QP_TYPE_NAME) ? xqos->type_name : "null";
x += cpf (conn, ".%s/%s", topic_name, topic_typename);
}
cpf (conn, "\n");
return x;
}
static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct dds_qos *xqos, const struct ddsi_sertopic *topic)
static int print_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct endpoint_common *c, const struct dds_qos *xqos)
{
DDSRT_UNUSED_ARG (c);
return print_any_endpoint_common (conn, label, e, xqos, topic);
return print_any_endpoint_common (conn, label, e, xqos);
}
static int print_proxy_endpoint_common (ddsi_tran_conn_t conn, const char *label, const struct entity_common *e, const struct proxy_endpoint_common *c)
{
int x = 0;
x += print_any_endpoint_common (conn, label, e, c->xqos, c->topic);
x += print_any_endpoint_common (conn, label, e, c->xqos);
x += print_addrset_if_notempty (conn, " as", c->as, "\n");
return x;
}
@ -151,7 +152,7 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
while ((p = ephash_enum_participant_next (&e)) != NULL)
{
ddsrt_mutex_lock (&p->e.lock);
x += cpf (conn, "pp %x:%x:%x:%x %s%s\n", PGUID (p->e.guid), p->e.name, p->is_ddsi2_pp ? " [ddsi2]" : "");
x += cpf (conn, "pp "PGUIDFMT" %s%s\n", PGUID (p->e.guid), p->e.name, p->is_ddsi2_pp ? " [ddsi2]" : "");
ddsrt_mutex_unlock (&p->e.lock);
{
@ -165,12 +166,12 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
if (r->c.pp != p)
continue;
ddsrt_mutex_lock (&r->e.lock);
print_endpoint_common (conn, "rd", &r->e, &r->c, r->xqos, r->topic);
print_endpoint_common (conn, "rd", &r->e, &r->c, r->xqos);
#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS
x += print_addrset_if_notempty (conn, " as", r->as, "\n");
#endif
for (m = ddsrt_avl_iter_first (&rd_writers_treedef, &r->writers, &writ); m; m = ddsrt_avl_iter_next (&writ))
x += cpf (conn, " pwr %x:%x:%x:%x\n", PGUID (m->pwr_guid));
x += cpf (conn, " pwr "PGUIDFMT"\n", PGUID (m->pwr_guid));
ddsrt_mutex_unlock (&r->e.lock);
}
ephash_enum_reader_fini (&er);
@ -188,22 +189,22 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
if (w->c.pp != p)
continue;
ddsrt_mutex_lock (&w->e.lock);
print_endpoint_common (conn, "wr", &w->e, &w->c, w->xqos, w->topic);
print_endpoint_common (conn, "wr", &w->e, &w->c, w->xqos);
whc_get_state(w->whc, &whcst);
x += cpf (conn, " whc [%lld,%lld] unacked %"PRIuSIZE"%s [%u,%u] seq %lld seq_xmit %lld cs_seq %lld\n",
x += cpf (conn, " whc [%"PRId64",%"PRId64"] unacked %"PRIuSIZE"%s [%"PRIu32",%"PRIu32"] seq %"PRId64" seq_xmit %"PRId64" cs_seq %"PRId64"\n",
whcst.min_seq, whcst.max_seq, whcst.unacked_bytes,
w->throttling ? " THROTTLING" : "",
w->whc_low, w->whc_high,
w->seq, READ_SEQ_XMIT(w), w->cs_seq);
if (w->reliable)
{
x += cpf (conn, " hb %u ackhb %lld hb %lld wr %lld sched %lld #rel %d\n",
w->hbcontrol.hbs_since_last_write, w->hbcontrol.t_of_last_ackhb,
w->hbcontrol.t_of_last_hb, w->hbcontrol.t_of_last_write,
w->hbcontrol.tsched, w->num_reliable_readers);
x += cpf (conn, " #acks %u #nacks %u #rexmit %u #lost %u #throttle %u\n",
x += cpf (conn, " hb %"PRIu32" ackhb %"PRId64" hb %"PRId64" wr %"PRId64" sched %"PRId64" #rel %"PRId32"\n",
w->hbcontrol.hbs_since_last_write, w->hbcontrol.t_of_last_ackhb.v,
w->hbcontrol.t_of_last_hb.v, w->hbcontrol.t_of_last_write.v,
w->hbcontrol.tsched.v, w->num_reliable_readers);
x += cpf (conn, " #acks %"PRIu32" #nacks %"PRIu32" #rexmit %"PRIu32" #lost %"PRIu32" #throttle %"PRIu32"\n",
w->num_acks_received, w->num_nacks_received, w->rexmit_count, w->rexmit_lost_count, w->throttle_count);
x += cpf (conn, " max-drop-seq %lld\n", writer_max_drop_seq (w));
x += cpf (conn, " max-drop-seq %"PRId64"\n", writer_max_drop_seq (w));
}
x += print_addrset_if_notempty (conn, " as", w->as, "\n");
for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &w->readers, &rdit); m; m = ddsrt_avl_iter_next (&rdit))
@ -213,7 +214,7 @@ static int print_participants (struct thread_state1 * const ts1, struct q_global
wr_prd_flags[1] = m->assumed_in_sync ? 's' : '.';
wr_prd_flags[2] = m->has_replied_to_hb ? 'a' : '.'; /* a = ack seen */
wr_prd_flags[3] = 0;
x += cpf (conn, " prd %x:%x:%x:%x %s @ %lld [%lld,%lld] #nacks %u\n",
x += cpf (conn, " prd "PGUIDFMT" %s @ %"PRId64" [%"PRId64",%"PRId64"] #nacks %"PRIu32"\n",
PGUID (m->prd_guid), wr_prd_flags, m->seq, m->min_seq, m->max_seq, m->rexmit_requests);
}
ddsrt_mutex_unlock (&w->e.lock);
@ -236,7 +237,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
while ((p = ephash_enum_proxy_participant_next (&e)) != NULL)
{
ddsrt_mutex_lock (&p->e.lock);
x += cpf (conn, "proxypp %x:%x:%x:%x%s\n", PGUID (p->e.guid), p->is_ddsi2_pp ? " [ddsi2]" : "");
x += cpf (conn, "proxypp "PGUIDFMT"%s\n", PGUID (p->e.guid), p->is_ddsi2_pp ? " [ddsi2]" : "");
ddsrt_mutex_unlock (&p->e.lock);
x += print_addrset (conn, " as data", p->as_default, "");
x += print_addrset (conn, " meta", p->as_default, "\n");
@ -254,7 +255,7 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
ddsrt_mutex_lock (&r->e.lock);
print_proxy_endpoint_common (conn, "prd", &r->e, &r->c);
for (m = ddsrt_avl_iter_first (&rd_writers_treedef, &r->writers, &writ); m; m = ddsrt_avl_iter_next (&writ))
x += cpf (conn, " wr %x:%x:%x:%x\n", PGUID (m->wr_guid));
x += cpf (conn, " wr "PGUIDFMT"\n", PGUID (m->wr_guid));
ddsrt_mutex_unlock (&r->e.lock);
}
ephash_enum_proxy_reader_fini (&er);
@ -272,20 +273,20 @@ static int print_proxy_participants (struct thread_state1 * const ts1, struct q_
continue;
ddsrt_mutex_lock (&w->e.lock);
print_proxy_endpoint_common (conn, "pwr", &w->e, &w->c);
x += cpf (conn, " last_seq %lld last_fragnum %u\n", w->last_seq, w->last_fragnum);
x += cpf (conn, " last_seq %"PRId64" last_fragnum %"PRIu32"\n", w->last_seq, w->last_fragnum);
for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &w->readers, &rdit); m; m = ddsrt_avl_iter_next (&rdit))
{
x += cpf (conn, " rd %x:%x:%x:%x (nack %lld %lld)\n",
PGUID (m->rd_guid), m->seq_last_nack, m->t_last_nack);
x += cpf (conn, " rd "PGUIDFMT" (nack %"PRId64" %"PRId64")\n",
PGUID (m->rd_guid), m->seq_last_nack, m->t_last_nack.v);
switch (m->in_sync)
{
case PRMSS_SYNC:
break;
case PRMSS_TLCATCHUP:
x += cpf (conn, " tl-catchup end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq);
x += cpf (conn, " tl-catchup end_of_tl_seq %"PRId64"\n", m->u.not_in_sync.end_of_tl_seq);
break;
case PRMSS_OUT_OF_SYNC:
x += cpf (conn, " out-of-sync end_of_tl_seq %lld\n", m->u.not_in_sync.end_of_tl_seq);
x += cpf (conn, " out-of-sync end_of_tl_seq %"PRId64"\n", m->u.not_in_sync.end_of_tl_seq);
break;
}
}

View file

@ -42,7 +42,7 @@
#include "dds/ddsi/ddsi_mcgroup.h"
#include "dds/ddsi/q_receive.h"
#include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */
#include "dds/ddsi/q_rhc.h"
#include "dds/ddsi/ddsi_rhc.h"
#include "dds/ddsi/sysdeps.h"
#include "dds__whc.h"
@ -51,7 +51,7 @@
struct deleted_participant {
ddsrt_avl_node_t avlnode;
nn_guid_t guid;
ddsi_guid_t guid;
unsigned for_what;
nn_mtime_t t_prune;
};
@ -59,6 +59,7 @@ struct deleted_participant {
struct deleted_participants_admin {
ddsrt_mutex_t deleted_participants_lock;
ddsrt_avl_tree_t deleted_participants;
const ddsrt_log_cfg_t *logcfg;
int64_t delay;
};
@ -92,10 +93,10 @@ static const unsigned prismtech_builtin_writers_besmask =
NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER |
NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER;
static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg);
static dds_return_t new_reader_guid (struct reader **rd_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct rhc *rhc, status_cb_t status_cb, void *status_cbarg);
static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity);
static void unref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity);
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg);
static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg);
static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity);
static int gcreq_participant (struct participant *pp);
static int gcreq_writer (struct writer *wr);
@ -104,24 +105,29 @@ static int gcreq_proxy_participant (struct proxy_participant *proxypp);
static int gcreq_proxy_writer (struct proxy_writer *pwr);
static int gcreq_proxy_reader (struct proxy_reader *prd);
extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid, nn_vendorid_t vendorid);
extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, nn_vendorid_t vendorid);
extern inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertopic *topic);
extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct nn_guid *guid);
extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid);
extern inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, nn_wctime_t timestamp, bool alive);
static int compare_guid (const void *va, const void *vb)
{
return memcmp (va, vb, sizeof (nn_guid_t));
return memcmp (va, vb, sizeof (ddsi_guid_t));
}
nn_entityid_t to_entityid (unsigned u)
bool is_null_guid (const ddsi_guid_t *guid)
{
nn_entityid_t e;
return guid->prefix.u[0] == 0 && guid->prefix.u[1] == 0 && guid->prefix.u[2] == 0 && guid->entityid.u == 0;
}
ddsi_entityid_t to_entityid (unsigned u)
{
ddsi_entityid_t e;
e.u = u;
return e;
}
int is_writer_entityid (nn_entityid_t id)
int is_writer_entityid (ddsi_entityid_t id)
{
switch (id.u & NN_ENTITYID_KIND_MASK)
{
@ -133,7 +139,7 @@ int is_writer_entityid (nn_entityid_t id)
}
}
int is_reader_entityid (nn_entityid_t id)
int is_reader_entityid (ddsi_entityid_t id)
{
switch (id.u & NN_ENTITYID_KIND_MASK)
{
@ -145,7 +151,7 @@ int is_reader_entityid (nn_entityid_t id)
}
}
int is_keyed_endpoint_entityid (nn_entityid_t id)
int is_keyed_endpoint_entityid (ddsi_entityid_t id)
{
switch (id.u & NN_ENTITYID_KIND_MASK)
{
@ -160,7 +166,7 @@ int is_keyed_endpoint_entityid (nn_entityid_t id)
}
}
int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid)
int is_builtin_entityid (ddsi_entityid_t id, nn_vendorid_t vendorid)
{
if ((id.u & NN_ENTITYID_SOURCE_MASK) == NN_ENTITYID_SOURCE_BUILTIN)
return 1;
@ -175,7 +181,7 @@ int is_builtin_entityid (nn_entityid_t id, nn_vendorid_t vendorid)
}
}
int is_builtin_endpoint (nn_entityid_t id, nn_vendorid_t vendorid)
int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid)
{
return is_builtin_entityid (id, vendorid) && id.u != NN_ENTITYID_PARTICIPANT;
}
@ -186,7 +192,7 @@ bool is_local_orphan_endpoint (const struct entity_common *e)
is_builtin_endpoint (e->guid.entityid, NN_VENDORID_ECLIPSE));
}
static void entity_common_init (struct entity_common *e, struct q_globals *gv, const struct nn_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal)
static void entity_common_init (struct entity_common *e, struct q_globals *gv, const struct ddsi_guid *guid, const char *name, enum entity_kind kind, nn_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal)
{
e->guid = *guid;
e->kind = kind;
@ -296,13 +302,22 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e)
return NN_VENDORID_UNKNOWN;
}
void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos)
{
wrinfo->guid = e->guid;
wrinfo->ownership_strength = xqos->ownership_strength.value;
wrinfo->auto_dispose = xqos->writer_data_lifecycle.autodispose_unregistered_instances;
wrinfo->iid = e->iid;
}
/* DELETED PARTICIPANTS --------------------------------------------- */
struct deleted_participants_admin *deleted_participants_admin_new (int64_t delay)
struct deleted_participants_admin *deleted_participants_admin_new (const ddsrt_log_cfg_t *logcfg, int64_t delay)
{
struct deleted_participants_admin *admin = ddsrt_malloc (sizeof (*admin));
ddsrt_mutex_init (&admin->deleted_participants_lock);
ddsrt_avl_init (&deleted_participants_treedef, &admin->deleted_participants);
admin->logcfg = logcfg;
admin->delay = delay;
return admin;
}
@ -326,6 +341,7 @@ static void prune_deleted_participant_guids_unlocked (struct deleted_participant
struct deleted_participant *dpp1 = ddsrt_avl_find_succ (&deleted_participants_treedef, &admin->deleted_participants, dpp);
if (dpp->t_prune.v < tnow.v)
{
DDS_CLOG (DDS_LC_DISCOVERY, admin->logcfg, "prune_deleted_participant_guid("PGUIDFMT")\n", PGUID (dpp->guid));
ddsrt_avl_delete (&deleted_participants_treedef, &admin->deleted_participants, dpp);
ddsrt_free (dpp);
}
@ -340,7 +356,7 @@ static void prune_deleted_participant_guids (struct deleted_participants_admin *
ddsrt_mutex_unlock (&admin->deleted_participants_lock);
}
static void remember_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid)
static void remember_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid)
{
struct deleted_participant *n;
ddsrt_avl_ipath_t path;
@ -358,7 +374,7 @@ static void remember_deleted_participant_guid (struct deleted_participants_admin
ddsrt_mutex_unlock (&admin->deleted_participants_lock);
}
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what)
int is_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what)
{
struct deleted_participant *n;
int known;
@ -372,17 +388,16 @@ int is_deleted_participant_guid (struct deleted_participants_admin *admin, const
return known;
}
static void remove_deleted_participant_guid (ddsrt_log_cfg_t *logcfg, struct deleted_participants_admin *admin, const struct nn_guid *guid, unsigned for_what)
static void remove_deleted_participant_guid (struct deleted_participants_admin *admin, const struct ddsi_guid *guid, unsigned for_what)
{
struct deleted_participant *n;
DDS_CLOG (DDS_LC_DISCOVERY, logcfg, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what);
DDS_CLOG (DDS_LC_DISCOVERY, admin->logcfg, "remove_deleted_participant_guid("PGUIDFMT" for_what=%x)\n", PGUID (*guid), for_what);
ddsrt_mutex_lock (&admin->deleted_participants_lock);
if ((n = ddsrt_avl_lookup (&deleted_participants_treedef, &admin->deleted_participants, guid)) != NULL)
n->t_prune = add_duration_to_mtime (now_mt (), admin->delay);
ddsrt_mutex_unlock (&admin->deleted_participants_lock);
}
/* PARTICIPANT ------------------------------------------------------ */
static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, const dds_qos_t *xqos, nn_wctime_t timestamp)
@ -417,7 +432,7 @@ static bool update_qos_locked (struct entity_common *e, dds_qos_t *ent_qos, cons
return true;
}
static dds_return_t pp_allocate_entityid(nn_entityid_t *id, uint32_t kind, struct participant *pp)
static dds_return_t pp_allocate_entityid(ddsi_entityid_t *id, uint32_t kind, struct participant *pp)
{
uint32_t id1;
int ret = 0;
@ -436,17 +451,17 @@ static dds_return_t pp_allocate_entityid(nn_entityid_t *id, uint32_t kind, struc
return ret;
}
static void pp_release_entityid(struct participant *pp, nn_entityid_t id)
static void pp_release_entityid(struct participant *pp, ddsi_entityid_t id)
{
ddsrt_mutex_lock (&pp->e.lock);
inverse_uint32_set_free(&pp->avail_entityids.x, id.u / NN_ENTITYID_ALLOCSTEP);
ddsrt_mutex_unlock (&pp->e.lock);
}
dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
{
struct participant *pp;
nn_guid_t subguid, group_guid;
ddsi_guid_t subguid, group_guid;
/* no reserved bits may be set */
assert ((flags & ~(RTPS_PF_NO_BUILTIN_READERS | RTPS_PF_NO_BUILTIN_WRITERS | RTPS_PF_PRIVILEGED_PP | RTPS_PF_IS_DDSI2_PP | RTPS_PF_ONLY_LOCAL)) == 0);
@ -699,20 +714,16 @@ dds_return_t new_participant_guid (const nn_guid_t *ppguid, struct q_globals *gv
return 0;
}
dds_return_t new_participant (nn_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct q_globals *gv, unsigned flags, const nn_plist_t *plist)
{
nn_guid_t ppguid;
ddsrt_mutex_lock (&gv->privileged_pp_lock);
ppguid = gv->next_ppguid;
if (gv->next_ppguid.prefix.u[2]++ == ~0u)
{
ddsrt_mutex_unlock (&gv->privileged_pp_lock);
return DDS_RETCODE_OUT_OF_RESOURCES;
}
ddsrt_mutex_unlock (&gv->privileged_pp_lock);
*p_ppguid = ppguid;
union { uint64_t u64; uint32_t u32[2]; } u;
u.u32[0] = gv->ppguid_base.prefix.u[1];
u.u32[1] = gv->ppguid_base.prefix.u[2];
u.u64 += ddsi_iid_gen ();
p_ppguid->prefix.u[0] = gv->ppguid_base.prefix.u[0];
p_ppguid->prefix.u[1] = u.u32[0];
p_ppguid->prefix.u[2] = u.u32[1];
p_ppguid->entityid.u = NN_ENTITYID_PARTICIPANT;
return new_participant_guid (p_ppguid, gv, flags, plist);
}
@ -724,9 +735,9 @@ void update_participant_plist (struct participant *pp, const nn_plist_t *plist)
ddsrt_mutex_unlock (&pp->e.lock);
}
static void delete_builtin_endpoint (struct q_globals *gv, const struct nn_guid *ppguid, unsigned entityid)
static void delete_builtin_endpoint (struct q_globals *gv, const struct ddsi_guid *ppguid, unsigned entityid)
{
nn_guid_t guid;
ddsi_guid_t guid;
guid.prefix = ppguid->prefix;
guid.entityid.u = entityid;
assert (is_builtin_entityid (to_entityid (entityid), NN_VENDORID_ECLIPSE));
@ -736,9 +747,9 @@ static void delete_builtin_endpoint (struct q_globals *gv, const struct nn_guid
(void)delete_reader (gv, &guid);
}
static struct participant *ref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity)
static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity)
{
nn_guid_t stguid;
ddsi_guid_t stguid;
ddsrt_mutex_lock (&pp->refc_lock);
if (guid_of_refing_entity && is_builtin_endpoint (guid_of_refing_entity->entityid, NN_VENDORID_ECLIPSE))
pp->builtin_refc++;
@ -755,7 +766,7 @@ static struct participant *ref_participant (struct participant *pp, const struct
return pp;
}
static void unref_participant (struct participant *pp, const struct nn_guid *guid_of_refing_entity)
static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity)
{
static const unsigned builtin_endpoints_tab[] = {
NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER,
@ -776,7 +787,7 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui
NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER,
NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER
};
nn_guid_t stguid;
ddsi_guid_t stguid;
ddsrt_mutex_lock (&pp->refc_lock);
if (guid_of_refing_entity && is_builtin_endpoint (guid_of_refing_entity->entityid, NN_VENDORID_ECLIPSE))
@ -889,7 +900,7 @@ static void unref_participant (struct participant *pp, const struct nn_guid *gui
ddsrt_free (pp->plist);
ddsrt_mutex_destroy (&pp->refc_lock);
entity_common_fini (&pp->e);
remove_deleted_participant_guid (&pp->e.gv->logconfig, pp->e.gv->deleted_participants, &pp->e.guid, DPG_LOCAL);
remove_deleted_participant_guid (pp->e.gv->deleted_participants, &pp->e.guid, DPG_LOCAL);
inverse_uint32_set_fini(&pp->avail_entityids.x);
ddsrt_free (pp);
}
@ -907,9 +918,10 @@ static void gc_delete_participant (struct gcreq *gcreq)
unref_participant (pp, NULL);
}
dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppguid)
dds_return_t delete_participant (struct q_globals *gv, const struct ddsi_guid *ppguid)
{
struct participant *pp;
GVLOGDISC ("delete_participant("PGUIDFMT")\n", PGUID (*ppguid));
if ((pp = ephash_lookup_participant_guid (gv->guid_hash, ppguid)) == NULL)
return DDS_RETCODE_BAD_PARAMETER;
builtintopic_write (gv->builtin_topic_interface, &pp->e, now(), false);
@ -921,7 +933,7 @@ dds_return_t delete_participant (struct q_globals *gv, const struct nn_guid *ppg
struct writer *get_builtin_writer (const struct participant *pp, unsigned entityid)
{
nn_guid_t bwr_guid;
ddsi_guid_t bwr_guid;
unsigned bes_mask = 0, prismtech_bes_mask = 0;
if (pp->e.onlylocal) {
@ -1391,7 +1403,7 @@ static void free_wr_rd_match (struct wr_rd_match *m)
if (m) ddsrt_free (m);
}
static void writer_drop_connection (const struct nn_guid *wr_guid, const struct proxy_reader *prd)
static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struct proxy_reader *prd)
{
struct writer *wr;
if ((wr = ephash_lookup_writer_guid (prd->e.gv->guid_hash, wr_guid)) != NULL)
@ -1421,7 +1433,7 @@ static void writer_drop_connection (const struct nn_guid *wr_guid, const struct
}
}
static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct reader *rd)
static void writer_drop_local_connection (const struct ddsi_guid *wr_guid, struct reader *rd)
{
/* Only called by gc_delete_reader, so we actually have a reader pointer */
struct writer *wr;
@ -1448,7 +1460,7 @@ static void writer_drop_local_connection (const struct nn_guid *wr_guid, struct
}
}
static void reader_drop_connection (const struct nn_guid *rd_guid, const struct proxy_writer *pwr)
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)
@ -1458,13 +1470,13 @@ static void reader_drop_connection (const struct nn_guid *rd_guid, const struct
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);
free_rd_pwr_match (pwr->e.gv, m);
if (m != NULL)
{
if (rd->rhc)
{
struct proxy_writer_info pwr_info;
make_proxy_writer_info(&pwr_info, &pwr->e, pwr->c.xqos);
rhc_unregister_wr (rd->rhc, &pwr_info);
struct ddsi_writer_info wrinfo;
ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
}
if (rd->status_cb)
{
@ -1480,9 +1492,11 @@ static void reader_drop_connection (const struct nn_guid *rd_guid, const struct
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
free_rd_pwr_match (pwr->e.gv, m);
}
}
static void reader_drop_local_connection (const struct nn_guid *rd_guid, const struct writer *wr)
static void reader_drop_local_connection (const struct ddsi_guid *rd_guid, const struct writer *wr)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (wr->e.gv->guid_hash, rd_guid)) != NULL)
@ -1492,14 +1506,14 @@ static void reader_drop_local_connection (const struct nn_guid *rd_guid, const s
if ((m = ddsrt_avl_lookup (&rd_local_writers_treedef, &rd->local_writers, &wr->e.guid)) != NULL)
ddsrt_avl_delete (&rd_local_writers_treedef, &rd->local_writers, m);
ddsrt_mutex_unlock (&rd->e.lock);
free_rd_wr_match (m);
if (m != NULL)
{
if (rd->rhc)
{
/* FIXME: */
struct proxy_writer_info pwr_info;
make_proxy_writer_info(&pwr_info, &wr->e, wr->xqos);
rhc_unregister_wr (rd->rhc, &pwr_info);
struct ddsi_writer_info wrinfo;
ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
ddsi_rhc_unregister_wr (rd->rhc, &wrinfo);
}
if (rd->status_cb)
{
@ -1515,9 +1529,11 @@ static void reader_drop_local_connection (const struct nn_guid *rd_guid, const s
(rd->status_cb) (rd->status_cb_entity, &data);
}
}
free_rd_wr_match (m);
}
}
static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, const struct ephash *guid_hash, const struct nn_guid *rd_guid, nn_count_t count)
static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, const struct ephash *guid_hash, const struct ddsi_guid *rd_guid, nn_count_t count)
{
struct reader *rd;
@ -1539,7 +1555,7 @@ static void update_reader_init_acknack_count (const ddsrt_log_cfg_t *logcfg, con
}
}
static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct reader *rd)
static void proxy_writer_drop_connection (const struct ddsi_guid *pwr_guid, struct reader *rd)
{
/* Only called by gc_delete_reader, so we actually have a reader pointer */
struct proxy_writer *pwr;
@ -1574,7 +1590,7 @@ static void proxy_writer_drop_connection (const struct nn_guid *pwr_guid, struct
}
}
static void proxy_reader_drop_connection (const struct nn_guid *prd_guid, struct writer *wr)
static void proxy_reader_drop_connection (const struct ddsi_guid *prd_guid, struct writer *wr)
{
struct proxy_reader *prd;
if ((prd = ephash_lookup_proxy_reader_guid (wr->e.gv->guid_hash, prd_guid)) != NULL)
@ -1719,12 +1735,12 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd)
whc_sample_iter_init(wr->whc, &it);
while (whc_sample_iter_borrow_next(&it, &sample))
{
struct proxy_writer_info pwr_info;
struct ddsi_writer_info wrinfo;
struct ddsi_serdata *payload = sample.serdata;
/* FIXME: whc has tk reference in its index nodes, which is what we really should be iterating over anyway, and so we don't really have to look them up anymore */
struct ddsi_tkmap_instance *tk = ddsi_tkmap_lookup_instance_ref (tkmap, payload);
make_proxy_writer_info (&pwr_info, &wr->e, wr->xqos);
(void) rhc_store (rd->rhc, &pwr_info, payload, tk);
ddsi_make_writer_info (&wrinfo, &wr->e, wr->xqos);
(void) ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk);
ddsi_tkmap_instance_unref (tkmap, tk);
}
}
@ -1855,8 +1871,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
if (ddsrt_avl_lookup_ipath (&pwr_readers_treedef, &pwr->readers, &rd->e.guid, &path))
goto already_matched;
if (pwr->c.topic == NULL && rd->topic)
pwr->c.topic = ddsi_sertopic_ref (rd->topic);
assert (rd->topic || is_builtin_endpoint (rd->e.guid.entityid, NN_VENDORID_ECLIPSE));
if (pwr->ddsi2direct_cb == 0 && rd->ddsi2direct_cb != 0)
{
pwr->ddsi2direct_cb = rd->ddsi2direct_cb;
@ -1891,7 +1906,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
/* builtins really don't care about multiple copies or anything */
m->in_sync = PRMSS_SYNC;
}
else if (!pwr->have_seen_heartbeat)
else if (!pwr->have_seen_heartbeat || !rd->handle_as_transient_local)
{
/* Proxy writer hasn't seen a heartbeat yet: means we have no
clue from what sequence number to start accepting data, nor
@ -1920,14 +1935,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
m->in_sync = PRMSS_SYNC;
m->u.not_in_sync.end_of_tl_seq = MAX_SEQ_NUMBER;
}
else if (!rd->handle_as_transient_local)
{
/* volatile reader, writer has seen a heartbeat: it's in sync
(there is a risk of it getting some historical data: that
happens to be cached in the writer's reorder admin at this
point) */
m->in_sync = PRMSS_SYNC;
}
else
{
/* transient-local reader; range of sequence numbers is already
@ -1981,7 +1988,6 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader
return;
already_matched:
assert (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor) ? (pwr->c.topic == NULL) : (pwr->c.topic != NULL));
ELOGDISC (pwr, " proxy_writer_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT") - already connected\n",
PGUID (pwr->e.guid), PGUID (rd->e.guid));
ddsrt_mutex_unlock (&pwr->e.lock);
@ -1996,8 +2002,6 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
m->wr_guid = wr->e.guid;
ddsrt_mutex_lock (&prd->e.lock);
if (prd->c.topic == NULL)
prd->c.topic = ddsi_sertopic_ref (wr->topic);
if (ddsrt_avl_lookup_ipath (&prd_writers_treedef, &prd->writers, &wr->e.guid, &path))
{
ELOGDISC (prd, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n",
@ -2007,6 +2011,7 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
}
else
{
assert (wr->topic || is_builtin_endpoint (wr->e.guid.entityid, NN_VENDORID_ECLIPSE));
ELOGDISC (prd, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT")\n",
PGUID (wr->e.guid), PGUID (prd->e.guid));
ddsrt_avl_insert_ipath (&prd_writers_treedef, &prd->writers, m, &path);
@ -2015,9 +2020,9 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer
}
}
static nn_entityid_t builtin_entityid_match (nn_entityid_t x)
static ddsi_entityid_t builtin_entityid_match (ddsi_entityid_t x)
{
nn_entityid_t res;
ddsi_entityid_t res;
res.u = 0;
switch (x.u)
{
@ -2164,7 +2169,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r
proxy_writer_add_connection (pwr, rd, tnow, init_count);
}
static bool ignore_local_p (const nn_guid_t *guid1, const nn_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2)
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)
{
assert (xqos1->present & QP_CYCLONE_IGNORELOCAL);
assert (xqos2->present & QP_CYCLONE_IGNORELOCAL);
@ -2383,7 +2388,7 @@ static void generic_do_match (struct entity_common *e, nn_mtime_t tnow)
else
{
/* Built-ins have fixed QoS */
nn_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid);
ddsi_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid);
enum entity_kind pkind = generic_do_match_isproxy (e) ? EK_PARTICIPANT : EK_PROXY_PARTICIPANT;
EELOGDISC (e, "match_%s_with_%ss(%s "PGUIDFMT") scanning %sparticipants tgt=%"PRIx32"\n",
generic_do_match_kindstr_us (e->kind), generic_do_match_kindstr_us (mkind),
@ -2396,7 +2401,7 @@ static void generic_do_match (struct entity_common *e, nn_mtime_t tnow)
ephash_enum_init (&est, guid_hash, pkind);
while ((ep = ephash_enum_next (&est)) != NULL)
{
nn_guid_t tgt_guid;
ddsi_guid_t tgt_guid;
tgt_guid.prefix = ep->guid.prefix;
tgt_guid.entityid = tgt_ent;
if ((em = ephash_lookup_guid (guid_hash, &tgt_guid, mkind)) != NULL)
@ -2463,7 +2468,7 @@ static void match_proxy_reader_with_writers (struct proxy_reader *prd, nn_mtime_
/* ENDPOINT --------------------------------------------------------- */
static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct nn_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos)
static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct ddsi_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos)
{
const char *partition = "(default)";
const char *partition_suffix = "";
@ -2489,7 +2494,7 @@ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const
topic ? topic->type_name : "(null)");
}
static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, bool onlylocal)
static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct q_globals *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal)
{
entity_common_init (e, gv, guid, NULL, kind, now (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal);
c->pp = ref_participant (pp, &e->guid);
@ -2878,7 +2883,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se
local_reader_ary_init (&wr->rdary);
}
static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_guid *guid, const struct nn_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity)
static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity)
{
struct writer *wr;
nn_mtime_t tnow = now_mt ();
@ -2929,7 +2934,7 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct nn_gui
return 0;
}
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn_guid *wrguid, const struct nn_guid *group_guid, const struct nn_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
{
struct participant *pp;
dds_return_t rc;
@ -2951,9 +2956,9 @@ dds_return_t new_writer (struct writer **wr_out, struct q_globals *gv, struct nn
return new_writer_guid (wr_out, wrguid, group_guid, pp, topic, xqos, whc, status_cb, status_cb_arg);
}
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, nn_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc)
struct local_orphan_writer *new_local_orphan_writer (struct q_globals *gv, ddsi_entityid_t entityid, struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc)
{
nn_guid_t guid;
ddsi_guid_t guid;
struct local_orphan_writer *lowr;
struct writer *wr;
nn_mtime_t tnow = now_mt ();
@ -3072,6 +3077,22 @@ static void writer_set_state (struct writer *wr, enum writer_state newstate)
wr->state = newstate;
}
dds_return_t unblock_throttled_writer (struct q_globals *gv, const struct ddsi_guid *guid)
{
struct writer *wr;
assert (is_writer_entityid (guid->entityid));
if ((wr = ephash_lookup_writer_guid (gv->guid_hash, guid)) == NULL)
{
GVLOGDISC ("unblock_throttled_writer(guid "PGUIDFMT") - unknown guid\n", PGUID (*guid));
return DDS_RETCODE_BAD_PARAMETER;
}
GVLOGDISC ("unblock_throttled_writer(guid "PGUIDFMT") ...\n", PGUID (*guid));
ddsrt_mutex_lock (&wr->e.lock);
writer_set_state (wr, WRST_INTERRUPT);
ddsrt_mutex_unlock (&wr->e.lock);
return 0;
}
dds_return_t delete_writer_nolinger_locked (struct writer *wr)
{
ELOGDISC (wr, "delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (wr->e.guid));
@ -3084,7 +3105,7 @@ dds_return_t delete_writer_nolinger_locked (struct writer *wr)
return 0;
}
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid *guid)
dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct ddsi_guid *guid)
{
struct writer *wr;
/* We take no care to ensure application writers are not deleted
@ -3108,12 +3129,13 @@ dds_return_t delete_writer_nolinger (struct q_globals *gv, const struct nn_guid
void delete_local_orphan_writer (struct local_orphan_writer *lowr)
{
assert (thread_is_awake ());
ddsrt_mutex_lock (&lowr->wr.e.lock);
delete_writer_nolinger_locked (&lowr->wr);
ddsrt_mutex_unlock (&lowr->wr.e.lock);
}
dds_return_t delete_writer (struct q_globals *gv, const struct nn_guid *guid)
dds_return_t delete_writer (struct q_globals *gv, const struct ddsi_guid *guid)
{
struct writer *wr;
struct whc_state whcst;
@ -3261,12 +3283,12 @@ static void leave_mcast_helper (const nn_locator_t *n, void *varg)
static dds_return_t new_reader_guid
(
struct reader **rd_out,
const struct nn_guid *guid,
const struct nn_guid *group_guid,
const struct ddsi_guid *guid,
const struct ddsi_guid *group_guid,
struct participant *pp,
const struct ddsi_sertopic *topic,
const struct dds_qos *xqos,
struct rhc *rhc,
struct ddsi_rhc *rhc,
status_cb_t status_cb,
void * status_entity
)
@ -3322,7 +3344,7 @@ static dds_return_t new_reader_guid
/* set rhc qos for reader */
if (rhc)
{
rhc_set_qos (rd->rhc, rd->xqos);
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)
@ -3403,12 +3425,12 @@ dds_return_t new_reader
(
struct reader **rd_out,
struct q_globals *gv,
struct nn_guid *rdguid,
const struct nn_guid *group_guid,
const struct nn_guid *ppguid,
struct ddsi_guid *rdguid,
const struct ddsi_guid *group_guid,
const struct ddsi_guid *ppguid,
const struct ddsi_sertopic *topic,
const struct dds_qos *xqos,
struct rhc * rhc,
struct ddsi_rhc * rhc,
status_cb_t status_cb,
void * status_cbarg
)
@ -3461,9 +3483,9 @@ static void gc_delete_reader (struct gcreq *gcreq)
addrset_forall (rd->as, leave_mcast_helper, &arg);
}
#endif
if (rd->rhc)
if (rd->rhc && is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE))
{
rhc_free (rd->rhc);
ddsi_rhc_free (rd->rhc);
}
if (rd->status_cb)
{
@ -3481,7 +3503,7 @@ static void gc_delete_reader (struct gcreq *gcreq)
ddsrt_free (rd);
}
dds_return_t delete_reader (struct q_globals *gv, const struct nn_guid *guid)
dds_return_t delete_reader (struct q_globals *gv, const struct ddsi_guid *guid)
{
struct reader *rd;
assert (!is_writer_entityid (guid->entityid));
@ -3544,10 +3566,10 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct
void new_proxy_participant
(
struct q_globals *gv,
const struct nn_guid *ppguid,
const struct ddsi_guid *ppguid,
unsigned bes,
unsigned prismtech_bes,
const struct nn_guid *privileged_pp_guid,
const struct ddsi_guid *privileged_pp_guid,
struct addrset *as_default,
struct addrset *as_meta,
const nn_plist_t *plist,
@ -3696,7 +3718,7 @@ void new_proxy_participant
const struct bestab *te = &bestab[i];
if ((proxypp->bes & te->besflag) || (proxypp->prismtech_bes & te->prismtech_besflag))
{
nn_guid_t guid1;
ddsi_guid_t guid1;
guid1.prefix = proxypp->e.guid.prefix;
guid1.entityid.u = te->entityid;
assert (is_builtin_entityid (guid1.entityid, proxypp->vendor));
@ -3815,7 +3837,7 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p
if (proxypp->owns_lease)
lease_free (ddsrt_atomic_ldvoidp (&proxypp->lease));
entity_common_fini (&proxypp->e);
remove_deleted_participant_guid (&proxypp->e.gv->logconfig, proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE);
ddsrt_free (proxypp);
}
else if (proxypp->endpoints == NULL && proxypp->implicitly_created)
@ -3959,7 +3981,7 @@ void purge_proxy_participants (struct q_globals *gv, const nn_locator_t *loc, bo
thread_state_asleep (ts1);
}
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid *guid, nn_wctime_t timestamp, int isimplicit)
int delete_proxy_participant_by_guid (struct q_globals *gv, const struct ddsi_guid *guid, nn_wctime_t timestamp, int isimplicit)
{
struct proxy_participant *ppt;
@ -3982,7 +4004,7 @@ int delete_proxy_participant_by_guid (struct q_globals *gv, const struct nn_guid
return 0;
}
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_guid *guid)
uint64_t get_entity_instance_id (const struct q_globals *gv, const struct ddsi_guid *guid)
{
struct thread_state1 *ts1 = lookup_thread_state ();
struct entity_common *e;
@ -3996,7 +4018,7 @@ uint64_t get_entity_instance_id (const struct q_globals *gv, const struct nn_gui
/* PROXY-ENDPOINT --------------------------------------------------- */
static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_endpoint_common *c, enum entity_kind kind, const struct nn_guid *guid, nn_wctime_t tcreate, seqno_t seq, struct proxy_participant *proxypp, struct addrset *as, const nn_plist_t *plist)
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)
{
const char *name;
@ -4009,7 +4031,6 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false);
c->xqos = nn_xqos_dup (&plist->qos);
c->as = ref_addrset (as);
c->topic = NULL; /* set from first matching reader/writer */
c->vendor = proxypp->vendor;
c->seq = seq;
@ -4024,18 +4045,15 @@ static void proxy_endpoint_common_init (struct entity_common *e, struct proxy_en
static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_endpoint_common *c)
{
unref_proxy_participant (c->proxypp, c);
ddsi_sertopic_unref (c->topic);
nn_xqos_fini (c->xqos);
ddsrt_free (c->xqos);
unref_addrset (c->as);
entity_common_fini (e);
}
/* PROXY-WRITER ----------------------------------------------------- */
int new_proxy_writer (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq)
int new_proxy_writer (struct q_globals *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const nn_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, nn_wctime_t timestamp, seqno_t seq)
{
struct proxy_participant *proxypp;
struct proxy_writer *pwr;
@ -4168,7 +4186,7 @@ void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset
void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset *as, const struct dds_qos *xqos, nn_wctime_t timestamp)
{
struct prd_wr_match * m;
nn_guid_t wrguid;
ddsi_guid_t wrguid;
memset (&wrguid, 0, sizeof (wrguid));
@ -4189,7 +4207,7 @@ void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset
while ((m = ddsrt_avl_lookup_succ_eq (&prd_writers_treedef, &prd->writers, &wrguid)) != NULL)
{
struct prd_wr_match *next;
nn_guid_t guid_next;
ddsi_guid_t guid_next;
struct writer * wr;
wrguid = m->wr_guid;
@ -4244,7 +4262,7 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq)
ddsrt_free (pwr);
}
int delete_proxy_writer (struct q_globals *gv, const struct nn_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)
{
struct proxy_writer *pwr;
(void)isimplicit;
@ -4271,7 +4289,7 @@ int delete_proxy_writer (struct q_globals *gv, const struct nn_guid *guid, nn_wc
/* PROXY-READER ----------------------------------------------------- */
int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const struct nn_guid *guid, struct addrset *as, const nn_plist_t *plist, nn_wctime_t timestamp, seqno_t seq
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
#ifdef DDSI_INCLUDE_SSM
, int favours_ssm
#endif
@ -4313,7 +4331,7 @@ int new_proxy_reader (struct q_globals *gv, const struct nn_guid *ppguid, const
static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *prd)
{
nn_guid_t wrguid;
ddsi_guid_t wrguid;
struct writer *wr;
struct prd_wr_match *m;
@ -4325,7 +4343,7 @@ static void proxy_reader_set_delete_and_ack_all_messages (struct proxy_reader *p
/* have to be careful walking the tree -- pretty is different, but
I want to check this before I write a lookup_succ function. */
struct prd_wr_match *m_a_next;
nn_guid_t wrguid_next;
ddsi_guid_t wrguid_next;
wrguid = m->wr_guid;
if ((m_a_next = ddsrt_avl_find_succ (&prd_writers_treedef, &prd->writers, m)) != NULL)
wrguid_next = m_a_next->wr_guid;
@ -4377,7 +4395,7 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq)
ddsrt_free (prd);
}
int delete_proxy_reader (struct q_globals *gv, const struct nn_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)
{
struct proxy_reader *prd;
(void)isimplicit;

View file

@ -113,7 +113,7 @@ static void ephash_guid_remove (struct ephash *gh, struct entity_common *e)
assert (x);
}
void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct nn_guid *guid)
void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct ddsi_guid *guid)
{
/* FIXME: could (now) require guid to be first in entity_common; entity_common already is first in entity */
struct entity_common e;
@ -122,7 +122,7 @@ void *ephash_lookup_guid_untyped (const struct ephash *gh, const struct nn_guid
return ddsrt_chh_lookup (gh->hash, &e);
}
static void *ephash_lookup_guid_int (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind)
static void *ephash_lookup_guid_int (const struct ephash *gh, const struct ddsi_guid *guid, enum entity_kind kind)
{
struct entity_common *res;
if ((res = ephash_lookup_guid_untyped (gh, guid)) != NULL && res->kind == kind)
@ -131,7 +131,7 @@ static void *ephash_lookup_guid_int (const struct ephash *gh, const struct nn_gu
return NULL;
}
void *ephash_lookup_guid (const struct ephash *gh, const struct nn_guid *guid, enum entity_kind kind)
void *ephash_lookup_guid (const struct ephash *gh, const struct ddsi_guid *guid, enum entity_kind kind)
{
return ephash_lookup_guid_int (gh, guid, kind);
}
@ -196,42 +196,42 @@ void ephash_remove_proxy_reader_guid (struct ephash *gh, struct proxy_reader *pr
ephash_guid_remove (gh, &prd->e);
}
struct participant *ephash_lookup_participant_guid (const struct ephash *gh, const struct nn_guid *guid)
struct participant *ephash_lookup_participant_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
assert (offsetof (struct participant, e) == 0);
return ephash_lookup_guid_int (gh, guid, EK_PARTICIPANT);
}
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *gh, const struct nn_guid *guid)
struct proxy_participant *ephash_lookup_proxy_participant_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (guid->entityid.u == NN_ENTITYID_PARTICIPANT);
assert (offsetof (struct proxy_participant, e) == 0);
return ephash_lookup_guid_int (gh, guid, EK_PROXY_PARTICIPANT);
}
struct writer *ephash_lookup_writer_guid (const struct ephash *gh, const struct nn_guid *guid)
struct writer *ephash_lookup_writer_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (is_writer_entityid (guid->entityid));
assert (offsetof (struct writer, e) == 0);
return ephash_lookup_guid_int (gh, guid, EK_WRITER);
}
struct reader *ephash_lookup_reader_guid (const struct ephash *gh, const struct nn_guid *guid)
struct reader *ephash_lookup_reader_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (is_reader_entityid (guid->entityid));
assert (offsetof (struct reader, e) == 0);
return ephash_lookup_guid_int (gh, guid, EK_READER);
}
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *gh, const struct nn_guid *guid)
struct proxy_writer *ephash_lookup_proxy_writer_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (is_writer_entityid (guid->entityid));
assert (offsetof (struct proxy_writer, e) == 0);
return ephash_lookup_guid_int (gh, guid, EK_PROXY_WRITER);
}
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *gh, const struct nn_guid *guid)
struct proxy_reader *ephash_lookup_proxy_reader_guid (const struct ephash *gh, const struct ddsi_guid *guid)
{
assert (is_reader_entityid (guid->entityid));
assert (offsetof (struct proxy_reader, e) == 0);

View file

@ -1027,17 +1027,45 @@ int rtps_init (struct q_globals *gv)
ddsrt_mutex_init (&gv->participant_set_lock);
ddsrt_cond_init (&gv->participant_set_cond);
lease_management_init (gv);
gv->deleted_participants = deleted_participants_admin_new (gv->config.prune_deleted_ppant.delay);
gv->deleted_participants = deleted_participants_admin_new (&gv->logconfig, gv->config.prune_deleted_ppant.delay);
gv->guid_hash = ephash_new (gv);
ddsrt_mutex_init (&gv->privileged_pp_lock);
gv->privileged_pp = NULL;
/* Template PP guid -- protected by privileged_pp_lock for simplicity */
gv->next_ppguid.prefix.u[0] = locator_to_hopefully_unique_uint32 (&gv->ownloc);
gv->next_ppguid.prefix.u[1] = (unsigned) ddsrt_getpid ();
gv->next_ppguid.prefix.u[2] = 1;
gv->next_ppguid.entityid.u = NN_ENTITYID_PARTICIPANT;
/* Base participant GUID. IID initialisation should be from a really good random
generator and yield almost-unique numbers, and with a fallback of using process
id, timestamp and a counter, so incorporating that should do a lot to construct
a pseudo-random ID. (The assumption here is that feeding pseudo-random data in
MD5 will not change the randomness ...) Mix in the network configuration to
make machines with very reproducible boot sequences and low-resolution clocks
distinguishable.
This base is kept constant, prefix.u[1] and prefix.u[2] are then treated as a
64-bit unsigned integer to which we add IIDs to generate a hopping sequence
that won't repeat in the lifetime of the process. Seems like it ought to work
to keep the risks of collisions low. */
{
uint64_t iid = toBE8u (ddsi_iid_gen ());
ddsrt_md5_state_t st;
ddsrt_md5_byte_t digest[16];
ddsrt_md5_init (&st);
ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) &iid, sizeof (iid));
for (int i = 0; i < gv->n_interfaces; i++)
{
const struct nn_interface *intf = &gv->interfaces[i];
ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) &intf->loc.kind, sizeof (intf->loc.kind));
ddsrt_md5_append (&st, (const ddsrt_md5_byte_t *) intf->loc.address, sizeof (intf->loc.address));
}
ddsrt_md5_finish (&st, digest);
/* DDSI 2.2 requires the first two bytes of the GUID to be set to the vendor
code -- a terrible waste of entropy ... */
gv->ppguid_base.prefix.s[0] = NN_VENDORID_ECLIPSE.id[0];
gv->ppguid_base.prefix.s[1] = NN_VENDORID_ECLIPSE.id[1];
DDSRT_STATIC_ASSERT (sizeof (gv->ppguid_base.prefix.s) > 2 && sizeof (gv->ppguid_base.prefix.s) - 2 <= sizeof (digest));
memcpy (&gv->ppguid_base.prefix.s[2], digest, sizeof (gv->ppguid_base.prefix.s) - 2);
gv->ppguid_base.entityid.u = NN_ENTITYID_PARTICIPANT;
}
ddsrt_mutex_init (&gv->lock);
ddsrt_mutex_init (&gv->spdp_lock);
@ -1107,7 +1135,7 @@ int rtps_init (struct q_globals *gv)
if (gv->m_factory->m_connless)
{
if (!(gv->config.many_sockets_mode == MSM_NO_UNICAST && gv->config.allowMulticast))
GVTRACE ("Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv->disc_conn_uc), ddsi_conn_port (gv->data_conn_uc));
GVLOG (DDS_LC_CONFIG, "Unicast Ports: discovery %"PRIu32" data %"PRIu32"\n", ddsi_conn_port (gv->disc_conn_uc), ddsi_conn_port (gv->data_conn_uc));
if (gv->config.allowMulticast)
{
@ -1161,7 +1189,7 @@ int rtps_init (struct q_globals *gv)
/* Create shared transmit connection */
gv->tev_conn = gv->data_conn_uc;
GVTRACE ("Timed event transmit port: %d\n", (int) ddsi_conn_port (gv->tev_conn));
GVLOG (DDS_LC_CONFIG, "Timed event transmit port: %d\n", (int) ddsi_conn_port (gv->tev_conn));
#ifdef DDSI_INCLUDE_NETWORK_CHANNELS
{
@ -1189,7 +1217,7 @@ int rtps_init (struct q_globals *gv)
{
chptr->transmit_conn = gv->data_conn_uc;
}
GVTRACE ("channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn));
GVLOG (DDS_LC_CONFIG, "channel %s: transmit port %d\n", chptr->name, (int) ddsi_tran_port (chptr->transmit_conn));
#ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING
if (chptr->auxiliary_bandwidth_limit > 0 || lookup_thread_properties (tname))

View file

@ -188,7 +188,7 @@ int64_t check_and_handle_lease_expiration (struct q_globals *gv, nn_etime_t tnow
ddsrt_mutex_lock (&gv->leaseheap_lock);
while ((l = ddsrt_fibheap_min (&lease_fhdef, &gv->leaseheap)) != NULL && l->tsched.v <= tnowE.v)
{
nn_guid_t g = l->entity->guid;
ddsi_guid_t g = l->entity->guid;
enum entity_kind k = l->entity->kind;
assert (l->tsched.v != TSCHED_NOT_ON_HEAP);
@ -303,7 +303,7 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
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;
nn_guid_t ppguid;
ddsi_guid_t ppguid;
RSTTRACE (" PMD ST%x", statusinfo);
if (data->identifier != CDR_LE && data->identifier != CDR_BE)
{
@ -318,7 +318,7 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
else
{
const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1);
nn_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix);
uint32_t kind = ntohl (pmd->kind);
uint32_t length = bswap ? 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);
@ -346,11 +346,11 @@ void handle_PMD (const struct receiver_state *rst, nn_wctime_t timestamp, uint32
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 (nn_guid_prefix_t))
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 (*((nn_guid_prefix_t *) (data + 1)));
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");

View file

@ -38,6 +38,8 @@
#include "dds/ddsrt/avl.h"
#include "dds/ddsi/q_misc.h" /* for vendor_is_... */
#include "dds/ddsi/ddsi_plist_generic.h"
/* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1
supported for backwards compatibility) ... on the wire however
it must be -1 */
@ -88,25 +90,6 @@ struct flagset {
uint64_t wanted;
};
/* Instructions for the generic serializer (&c) that handles most parameters.
The "packed" attribute means single-byte instructions on GCC and Clang. */
enum pserop {
XSTOP,
XO, /* octet sequence */
XS, /* string */
XZ, /* string sequence */
XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */
Xl, /* length, int32_t, -1 or >= 1 */
Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */
Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */
XD, XDx2, /* duration, 1 .. 2 in a row */
Xo, Xox2, /* octet, 1 .. 2 in a row */
Xb, Xbx2, /* boolean, 1 .. 2 in a row */
XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */
XG, /* GUID */
XK /* keyhash */
} ddsrt_attribute_packed;
struct piddesc {
nn_parameterid_t pid; /* parameter id or PID_PAD if strictly local */
uint16_t flags; /* see PDF_xxx flags */
@ -115,10 +98,10 @@ struct piddesc {
size_t plist_offset; /* offset from start of nn_plist_t */
size_t size; /* in-memory size for copying */
union {
/* descriptor for generic code: 4 is enough for the current set of
/* descriptor for generic code: 12 is enough for the current set of
parameters, compiler will warn if one ever tries to use more than
will fit; on non-GCC/Clang and 32-bits machines */
const enum pserop desc[4];
will fit */
const enum pserop desc[12];
struct {
dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff);
dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff);
@ -131,6 +114,8 @@ struct piddesc {
dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd);
};
extern inline bool pserop_seralign_is_1 (enum pserop op);
static void log_octetseq (uint32_t cat, const struct ddsrt_log_cfg *logcfg, uint32_t n, const unsigned char *xs);
static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q);
static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q);
@ -325,7 +310,47 @@ static dds_return_t fini_locator (void * __restrict dst, size_t * __restrict dst
return 0;
}
static void fini_generic_partial (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
static size_t ser_generic_srcsize (const enum pserop * __restrict desc)
{
size_t srcoff = 0, srcalign = 0;
#define SIMPLE(basecase_, type_) do { \
const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \
const size_t align = alignof (type_); \
srcalign = (align > srcalign) ? align : srcalign; \
srcoff = (srcoff + align - 1) & ~(align - 1); \
srcoff += cnt * sizeof (type_); \
} while (0)
while (true)
{
switch (*desc)
{
case XSTOP: return (srcoff + srcalign - 1) & ~(srcalign - 1);
case XO: SIMPLE (XO, ddsi_octetseq_t); break;
case XS: SIMPLE (XS, const char *); break;
case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned); break;
case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
case XbCOND: SIMPLE (XbCOND, unsigned char); break;
case XG: SIMPLE (XG, ddsi_guid_t); break;
case XK: SIMPLE (XK, nn_keyhash_t); break;
case XbPROP: SIMPLE (XbPROP, unsigned char); break;
case XQ: SIMPLE (XQ, ddsi_octetseq_t); while (*++desc != XSTOP) { } break;
case Xopt: break;
}
desc++;
}
#undef SIMPLE
}
size_t plist_memsize_generic (const enum pserop * __restrict desc)
{
return ser_generic_srcsize (desc);
}
static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased)
{
#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \
type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \
@ -344,17 +369,29 @@ static void fini_generic_partial (void * __restrict dst, size_t * __restrict dst
case XSTOP: return;
case XO: COMPLEX (XO, ddsi_octetseq_t, ddsrt_free (x->value), (void) 0); break;
case XS: COMPLEX (XS, char *, ddsrt_free (*x), (void) 0); break;
case XZ: COMPLEX (XZ, ddsi_stringseq_t, { for (uint32_t i = 0; i < x->n; i++) ddsrt_free (x->strs[i]); }, ddsrt_free (x->strs)); break;
case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0, (void) 0); break;
case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
case Xl: SIMPLE (Xl, int32_t); break;
case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
case XbCOND: SIMPLE (XbCOND, unsigned char); break;
case XG: SIMPLE (XG, nn_guid_t); break;
case XG: SIMPLE (XG, ddsi_guid_t); break;
case XK: SIMPLE (XK, nn_keyhash_t); break;
case XbPROP: SIMPLE (XbPROP, unsigned char); break;
case XQ:
/* non-nested, so never a need to deallocate only some of the entries and no complications
in locating the end of the sequence element description */
COMPLEX (XQ, ddsi_octetseq_t, {
const size_t elem_size = ser_generic_srcsize (desc + 1);
for (uint32_t i = 0; i < x->length; i++) {
size_t elem_off = i * elem_size;
fini_generic_embeddable (x->value, &elem_off, desc + 1, desc_end, aliased);
}
}, ddsrt_free (x->value));
while (desc + 1 != desc_end && *++desc != XSTOP) { }
break;
case Xopt: break;
}
desc++;
}
@ -362,6 +399,26 @@ static void fini_generic_partial (void * __restrict dst, size_t * __restrict dst
#undef COMPLEX
}
static size_t pserop_memalign (enum pserop op)
{
switch (op)
{
case XO: case XQ: return alignof (ddsi_octetseq_t);
case XS: return alignof (char *);
case XG: return alignof (ddsi_guid_t);
case XK: return alignof (nn_keyhash_t);
case Xb: case Xbx2: return 1;
case Xo: case Xox2: return 1;
case XbCOND: case XbPROP: return 1;
case XE1: case XE2: case XE3: return sizeof (uint32_t);
case Xi: case Xix2: case Xix3: case Xix4: return sizeof (int32_t);
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: return sizeof (uint32_t);
case XD: case XDx2: return alignof (dds_duration_t);
case XSTOP: case Xopt: assert (0);
}
return 0;
}
static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc)
{
enum pserop const * const desc_in = desc;
@ -376,8 +433,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
switch (*desc)
{
case XSTOP:
*flagset->present |= flag;
return 0;
goto success;
case XO: { /* octet sequence */
ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t));
if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length)
@ -400,22 +456,6 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
*dstoff += sizeof (*x);
break;
}
case XZ: { /* string sequence: repeatedly read a string */
ddsi_stringseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_stringseq_t));
/* sequence of string: length <data> length <data> ..., where each length is aligned
to a multiple of 4 bytes and the lengths are all at least 1, therefore all but the
last entry need 8 bytes and the final one at least 5; checking this protects us
against allocating large amount of memory */
if (deser_uint32 (&x->n, dd, srcoff) < 0 || x->n > (dd->bufsz - *srcoff + 7) / 8)
goto fail;
x->strs = x->n ? ddsrt_malloc (x->n * sizeof (*x->strs)) : NULL;
size_t tmpoff = 0;
for (uint32_t i = 0; i < x->n; i++)
if (deser_generic (x->strs, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XS, XSTOP }) < 0)
goto fail;
*dstoff += sizeof (*x);
break;
}
case XE1: case XE2: case XE3: { /* enum with max allowed value */
unsigned * const x = deser_generic_dst (dst, dstoff, alignof (int));
const uint32_t maxval = 1 + (uint32_t) (*desc - XE1);
@ -444,15 +484,6 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
*dstoff += cnt * sizeof (*x);
break;
}
case Xl: { /* length(s): int32_t, -1 or >= 1 */
int32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - Xl);
for (uint32_t i = 0; i < cnt; i++)
if (deser_uint32 ((uint32_t *) &x[i], dd, srcoff) < 0 || (x[i] < 1 && x[i] != DDS_LENGTH_UNLIMITED))
goto fail;
*dstoff += cnt * sizeof (*x);
break;
}
case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */
dds_duration_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_duration_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - XD);
@ -491,8 +522,14 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
*dstoff += cnt * sizeof (*x);
break;
}
case XbPROP: { /* "propagate" flag, boolean, implied in serialized representation */
unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char));
*x = 1;
*dstoff += sizeof (*x);
break;
}
case XG: { /* GUID */
nn_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_guid_t));
ddsi_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_guid_t));
if (dd->bufsz - *srcoff < sizeof (*x))
goto fail;
memcpy (x, dd->buf + *srcoff, sizeof (*x));
@ -510,61 +547,139 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds
*dstoff += sizeof (*x);
break;
}
case XQ: { /* non-nested but otherwise arbitrary sequence, so no nested mallocs */
ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t));
if (deser_uint32 (&x->length, dd, srcoff) < 0 || x->length > dd->bufsz - *srcoff)
goto fail;
const size_t elem_size = ser_generic_srcsize (desc + 1);
x->value = x->length ? ddsrt_malloc (x->length * elem_size) : NULL;
for (uint32_t i = 0; i < x->length; i++)
{
size_t elem_off = i * elem_size;
if (deser_generic (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0)
{
ddsrt_free (x->value);
goto fail;
}
}
*dstoff += sizeof (*x);
while (*++desc != XSTOP) { }
break;
}
case Xopt: { /* remainder is optional; alignment is very nearly always 4 */
bool end_of_input;
if (pserop_seralign_is_1 (desc[1]))
end_of_input = (*srcoff + 1 > dd->bufsz);
else
{
*srcoff = (*srcoff + 3) & ~(size_t)3;
end_of_input = (*srcoff + 4 > dd->bufsz);
}
if (end_of_input)
{
void * const x = deser_generic_dst (dst, dstoff, pserop_memalign (desc[1]));
size_t rem_size = ser_generic_srcsize (desc + 1);
memset (x, 0, rem_size);
goto success;
}
}
}
desc++;
}
success:
*flagset->present |= flag;
return 0;
fail:
fini_generic_partial (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag);
fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag);
*flagset->present &= ~flag;
*flagset->aliased &= ~flag;
return DDS_RETCODE_BAD_PARAMETER;
}
static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc)
dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc)
{
struct dd dd = {
.buf = src,
.bufsz = srcsize,
.bswap = bswap,
.protocol_version = {0,0},
.vendorid = NN_VENDORID_ECLIPSE,
.factory = NULL
};
uint64_t present = 0, aliased = 0;
struct flagset fs = { .present = &present, .aliased = &aliased, .wanted = 1 };
size_t dstoff = 0, srcoff = 0;
return deser_generic (dst, &dstoff, &fs, 1, &dd, &srcoff, desc);
}
static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
{
size_t dstoff = 0;
#define COMPLEX(basecase_, type_, dstoff_update_) do { \
type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \
const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \
for (uint32_t xi = 0; xi < cnt; xi++, x++) { dstoff_update_; } \
srcoff += cnt * sizeof (*x); \
} while (0)
#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, dstoff = dstoff + sizeof (*x))
#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, dstoff = align4size (dstoff) + sizeof (*x))
#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = *dstoff + sizeof (*x))
#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = align4size (*dstoff) + sizeof (*x))
while (true)
{
switch (*desc)
{
case XSTOP: return dstoff;
case XO: COMPLEX (XO, ddsi_octetseq_t, dstoff = align4size (dstoff) + 4 + x->length); break;
case XS: COMPLEX (XS, const char *, dstoff = align4size (dstoff) + 4 + strlen (*x) + 1); break;
case XZ: COMPLEX (XZ, ddsi_stringseq_t, {
dstoff = align4size (dstoff) + 4;
for (uint32_t i = 0; i < x->n; i++)
dstoff = align4size (dstoff) + 4 + strlen (x->strs[i]) + 1;
}); break;
case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, dstoff = align4size (dstoff) + 4); break;
case XSTOP: return;
case XO: COMPLEX (XO, ddsi_octetseq_t, *dstoff = align4size (*dstoff) + 4 + x->length); break;
case XS: COMPLEX (XS, const char *, *dstoff = align4size (*dstoff) + 4 + strlen (*x) + 1); break;
case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, *dstoff = align4size (*dstoff) + 4); break;
case Xi: case Xix2: case Xix3: case Xix4: SIMPLE4 (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE4 (Xu, uint32_t); break;
case Xl: SIMPLE4 (Xl, int32_t); break;
case XD: case XDx2: SIMPLE4 (XD, dds_duration_t); break;
case Xo: case Xox2: SIMPLE1 (Xo, unsigned char); break;
case Xb: case Xbx2: SIMPLE1 (Xb, unsigned char); break;
case XbCOND: SIMPLE1 (XbCOND, unsigned char); break;
case XG: SIMPLE1 (XG, nn_guid_t); break;
case XG: SIMPLE1 (XG, ddsi_guid_t); break;
case XK: SIMPLE1 (XK, nn_keyhash_t); break;
case XbPROP: /* "propagate" boolean: when 'false'; no serialisation; no size; force early out */
COMPLEX (XbPROP, unsigned char, if (! *x) return); break;
case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
const size_t elem_size = ser_generic_srcsize (desc + 1);
*dstoff = align4size (*dstoff) + 4;
for (uint32_t i = 0; i < x->length; i++)
ser_generic_size_embeddable (dstoff, x->value, i * elem_size, desc + 1);
}); while (*++desc != XSTOP) { } break;
case Xopt: break;
}
desc++;
}
#undef SIMPLE
#undef SIMPLE4
#undef SIMPLE1
#undef COMPLEX
}
static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc)
static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc)
{
char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc));
size_t dstoff = 0;
ser_generic_size_embeddable (&dstoff, src, srcoff, desc);
return dstoff;
}
static uint32_t ser_generic_count (const ddsi_octetseq_t *src, size_t elem_size, const enum pserop * __restrict desc)
{
/* This whole thing exists solely for dealing with the vile "propagate" boolean, which must come first in an
element, or one can't deserialize it at all. Therefore, if desc doesn't start with XbPROP, all "length"
elements are included in the output */
if (*desc != XbPROP)
return src->length;
/* and if it does start with XbPROP, only those for which it is true are included */
uint32_t count = 0;
for (uint32_t i = 0; i < src->length; i++)
if (src->value[i * elem_size])
count++;
return count;
}
static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc)
{
while (true)
{
switch (*desc)
@ -573,134 +688,151 @@ static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, con
return 0;
case XO: { /* octet sequence */
ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t));
char * const p = ser_generic_align4 (data, &dstoff);
char * const p = ser_generic_align4 (data, dstoff);
*((uint32_t *) p) = x->length;
if (x->length) memcpy (p + 4, x->value, x->length);
dstoff += 4 + x->length;
*dstoff += 4 + x->length;
srcoff += sizeof (*x);
break;
}
case XS: { /* string */
char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *));
const uint32_t size = (uint32_t) (strlen (*x) + 1);
char * const p = ser_generic_align4 (data, &dstoff);
char * const p = ser_generic_align4 (data, dstoff);
*((uint32_t *) p) = size;
memcpy (p + 4, *x, size);
dstoff += 4 + size;
srcoff += sizeof (*x);
break;
}
case XZ: { /* string sequence */
ddsi_stringseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_stringseq_t));
char * const p = ser_generic_align4 (data, &dstoff);
*((uint32_t *) p) = x->n;
dstoff += 4;
for (uint32_t i = 0; i < x->n; i++)
{
char * const q = ser_generic_align4 (data, &dstoff);
const uint32_t size = (uint32_t) (strlen (x->strs[i]) + 1);
*((uint32_t *) q) = size;
memcpy (q + 4, x->strs[i], size);
dstoff += 4 + size;
}
*dstoff += 4 + size;
srcoff += sizeof (*x);
break;
}
case XE1: case XE2: case XE3: { /* enum */
unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned));
uint32_t * const p = ser_generic_align4 (data, &dstoff);
uint32_t * const p = ser_generic_align4 (data, dstoff);
*p = (uint32_t) *x;
dstoff += 4;
*dstoff += 4;
srcoff += sizeof (*x);
break;
}
case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */
int32_t const * const x = deser_generic_src (src, &srcoff, alignof (int32_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - Xi);
int32_t * const p = ser_generic_align4 (data, &dstoff);
int32_t * const p = ser_generic_align4 (data, dstoff);
for (uint32_t i = 0; i < cnt; i++)
p[i] = x[i];
dstoff += cnt * sizeof (*x);
*dstoff += cnt * sizeof (*x);
srcoff += cnt * sizeof (*x);
break;
}
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: { /* uint32_t(s) */
uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - Xu);
uint32_t * const p = ser_generic_align4 (data, &dstoff);
uint32_t * const p = ser_generic_align4 (data, dstoff);
for (uint32_t i = 0; i < cnt; i++)
p[i] = x[i];
dstoff += cnt * sizeof (*x);
srcoff += cnt * sizeof (*x);
break;
}
case Xl: { /* int32_t(s) */
int32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - Xu);
int32_t * const p = ser_generic_align4 (data, &dstoff);
for (uint32_t i = 0; i < cnt; i++)
p[i] = x[i];
dstoff += cnt * sizeof (*x);
*dstoff += cnt * sizeof (*x);
srcoff += cnt * sizeof (*x);
break;
}
case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */
dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t));
const uint32_t cnt = 1 + (uint32_t) (*desc - XD);
uint32_t * const p = ser_generic_align4 (data, &dstoff);
uint32_t * const p = ser_generic_align4 (data, dstoff);
for (uint32_t i = 0; i < cnt; i++)
{
ddsi_duration_t tmp = nn_to_ddsi_duration (x[i]);
p[2 * i + 0] = (uint32_t) tmp.seconds;
p[2 * i + 1] = tmp.fraction;
}
dstoff += 2 * cnt * sizeof (uint32_t);
*dstoff += 2 * cnt * sizeof (uint32_t);
srcoff += cnt * sizeof (*x);
break;
}
case Xo: case Xox2: { /* octet(s) */
unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
const uint32_t cnt = 1 + (uint32_t) (*desc - Xo);
char * const p = data + dstoff;
char * const p = data + *dstoff;
memcpy (p, x, cnt);
dstoff += cnt;
*dstoff += cnt;
srcoff += cnt * sizeof (*x);
break;
}
case Xb: case Xbx2: case XbCOND: { /* boolean(s) */
unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */
char * const p = data + dstoff;
char * const p = data + *dstoff;
memcpy (p, x, cnt);
dstoff += cnt;
*dstoff += cnt;
srcoff += cnt * sizeof (*x);
break;
}
case XbPROP: { /* "propagate" boolean: don't serialize, skip it and everything that follows if false */
unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char));
if (! *x) return 0;
srcoff++;
break;
}
case XG: { /* GUID */
nn_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_guid_t));
const nn_guid_t xn = nn_hton_guid (*x);
char * const p = data + dstoff;
ddsi_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_guid_t));
const ddsi_guid_t xn = nn_hton_guid (*x);
char * const p = data + *dstoff;
memcpy (p, &xn, sizeof (xn));
dstoff += sizeof (xn);
*dstoff += sizeof (xn);
srcoff += sizeof (*x);
break;
}
case XK: { /* keyhash */
nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t));
char * const p = data + dstoff;
char * const p = data + *dstoff;
memcpy (p, x, sizeof (*x));
dstoff += sizeof (*x);
*dstoff += sizeof (*x);
srcoff += sizeof (*x);
break;
}
case XQ: {
ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t));
char * const p = ser_generic_align4 (data, dstoff);
*dstoff += 4;
if (x->length == 0)
*((uint32_t *) p) = 0;
else
{
const size_t elem_size = ser_generic_srcsize (desc + 1);
*((uint32_t *) p) = ser_generic_count (x, elem_size, desc + 1);
for (uint32_t i = 0; i < x->length; i++)
ser_generic_embeddable (data, dstoff, x->value, i * elem_size, desc + 1);
}
srcoff += sizeof (*x);
while (*++desc != XSTOP) { }
break;
}
case Xopt:
break;
}
desc++;
}
}
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, const enum pserop * __restrict desc)
static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc)
{
char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc));
size_t dstoff = 0;
return ser_generic_embeddable (data, &dstoff, src, srcoff, desc);
}
dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc)
{
const size_t srcoff = 0;
size_t dstoff = 0;
dds_return_t ret;
*dstsize = ser_generic_size (src, srcoff, desc);
if ((*dst = ddsrt_malloc (*dstsize == 0 ? 1 : *dstsize)) == NULL)
return DDS_RETCODE_OUT_OF_RESOURCES;
ret = ser_generic_embeddable (*dst, &dstoff, src, srcoff, desc);
assert (dstoff == *dstsize);
return ret;
}
static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, bool gen_seq_aliased, const enum pserop * __restrict desc)
{
#define COMPLEX(basecase_, type_, ...) do { \
type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \
@ -717,21 +849,36 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
return 0;
case XO: COMPLEX (XO, ddsi_octetseq_t, if (x->value) { x->value = ddsrt_memdup (x->value, x->length); }); break;
case XS: COMPLEX (XS, char *, if (*x) { *x = ddsrt_strdup (*x); }); break;
case XZ: COMPLEX (XZ, ddsi_stringseq_t, if (x->n) {
x->strs = ddsrt_memdup (x->strs, x->n * sizeof (*x->strs));
for (uint32_t i = 0; i < x->n; i++)
x->strs[i] = ddsrt_strdup (x->strs[i]);
}); break;
case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0); break;
case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break;
case Xl: SIMPLE (Xl, int32_t); break;
case XD: case XDx2: SIMPLE (XD, dds_duration_t); break;
case Xo: case Xox2: SIMPLE (Xo, unsigned char); break;
case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break;
case XbCOND: SIMPLE (XbCOND, unsigned char); break;
case XG: SIMPLE (XG, nn_guid_t); break;
case XbPROP: SIMPLE (XbPROP, unsigned char); break;
case XG: SIMPLE (XG, ddsi_guid_t); break;
case XK: SIMPLE (XK, nn_keyhash_t); break;
case XQ: COMPLEX (XQ, ddsi_octetseq_t, if (x->length) {
const size_t elem_size = ser_generic_srcsize (desc + 1);
if (gen_seq_aliased)
{
/* The memory for the elements of a generic sequence are owned by the plist, the only aliased bits
are the strings (XS) and octet sequences (XO) embedded in the elements. So in principle, an
unalias operation on a generic sequence should only operate on the elements of the sequence,
not on the sequence buffer itself.
However, the "mergein_missing" operation (and consequently the copy & dup operations) memcpy the
source, then pretend it is aliased. In this case, the sequence buffer is aliased, rather than
private, and hence a new copy needs to be allocated. */
x->value = ddsrt_memdup (x->value, x->length * elem_size);
}
for (uint32_t i = 0; i < x->length; i++) {
size_t elem_off = i * elem_size;
unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1);
}
}); while (*++desc != XSTOP) { } break;
case Xopt: break;
}
desc++;
}
@ -739,13 +886,19 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict
#undef COMPLEX
}
dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc)
{
size_t dstoff = 0;
return unalias_generic (dst, &dstoff, false, desc);
}
static bool unalias_generic_required (const enum pserop * __restrict desc)
{
while (*desc != XSTOP)
{
switch (*desc++)
{
case XO: case XS: case XZ:
case XO: case XS: case XQ:
return true;
default:
break;
@ -762,10 +915,16 @@ static bool fini_generic_required (const enum pserop * __restrict desc)
static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const enum pserop * __restrict desc)
{
fini_generic_partial (dst, dstoff, desc, NULL, *flagset->aliased & flag);
fini_generic_embeddable (dst, dstoff, desc, NULL, *flagset->aliased & flag);
return 0;
}
void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased)
{
size_t dstoff = 0;
fini_generic_embeddable (dst, &dstoff, desc, NULL, aliased);
}
static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc)
{
#define COMPLEX(basecase_, type_, cond_stmts_) do { \
@ -783,23 +942,29 @@ static dds_return_t valid_generic (const void *src, size_t srcoff, const enum ps
case XSTOP: return 0;
case XO: SIMPLE (XO, ddsi_octetseq_t, (x->length == 0) == (x->value == NULL)); break;
case XS: SIMPLE (XS, const char *, *x != NULL); break;
case XZ: COMPLEX (XZ, ddsi_stringseq_t, {
if ((x->n == 0) != (x->strs == NULL))
return DDS_RETCODE_BAD_PARAMETER;
for (uint32_t i = 0; i < x->n; i++)
if (x->strs[i] == NULL)
return DDS_RETCODE_BAD_PARAMETER;
}); break;
case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned, *x <= 1 + (unsigned) *desc - XE1); break;
case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break;
case Xl: SIMPLE (Xl, int32_t, *x == DDS_LENGTH_UNLIMITED || *x > 1); break;
case XD: case XDx2: SIMPLE (XD, dds_duration_t, *x >= 0); break;
case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break;
case Xb: case Xbx2: SIMPLE (Xb, unsigned char, *x == 0 || *x == 1); break;
case XbCOND: SIMPLE (XbCOND, unsigned char, *x == 0 || *x == 1); break;
case XG: TRIVIAL (XG, nn_guid_t); break;
case XbPROP: SIMPLE (XbPROP, unsigned char, *x == 0 || *x == 1); break;
case XG: TRIVIAL (XG, ddsi_guid_t); break;
case XK: TRIVIAL (XK, nn_keyhash_t); break;
case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
if ((x->length == 0) != (x->value == NULL))
return DDS_RETCODE_BAD_PARAMETER;
if (x->length) {
const size_t elem_size = ser_generic_srcsize (desc + 1);
dds_return_t ret;
for (uint32_t i = 0; i < x->length; i++) {
if ((ret = valid_generic (x->value, i * elem_size, desc + 1)) != 0)
return ret;
}
}
}); while (*++desc != XSTOP) { } break;
case Xopt: break;
}
desc++;
}
@ -833,19 +998,9 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
case XS:
SIMPLE (XS, const char *, strcmp (*x, *y) == 0);
break;
case XZ:
COMPLEX (XZ, ddsi_stringseq_t, {
if (x->n != y->n)
return false;
for (uint32_t i = 0; i < x->n; i++)
if (strcmp (x->strs[i], y->strs[i]) != 0)
return false;
});
break;
case XE1: case XE2: case XE3: TRIVIAL (*desc, unsigned); break;
case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break;
case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break;
case Xl: TRIVIAL (Xl, int32_t); break;
case XD: case XDx2: TRIVIAL (XD, dds_duration_t); break;
case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break;
case Xb: case Xbx2: TRIVIAL (Xb, unsigned char); break;
@ -857,8 +1012,21 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
return true;
});
break;
case XG: SIMPLE (XG, nn_guid_t, memcmp (x, y, sizeof (*x))); break;
case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x))); break;
case XbPROP: TRIVIAL (XbPROP, unsigned char); break;
case XG: SIMPLE (XG, ddsi_guid_t, memcmp (x, y, sizeof (*x)) == 0); break;
case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x)) == 0); break;
case XQ: COMPLEX (XQ, ddsi_octetseq_t, {
if (x->length != y->length)
return false;
if (x->length) {
const size_t elem_size = ser_generic_srcsize (desc + 1);
for (uint32_t i = 0; i < x->length; i++) {
if (!equal_generic (x->value, y->value, i * elem_size, desc + 1))
return false;
}
}
}); while (*++desc != XSTOP) { } break;
case Xopt: break;
}
desc++;
}
@ -867,6 +1035,11 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co
#undef COMPLEX
}
bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc)
{
return equal_generic (srcx, srcy, 0, desc);
}
#define membersize(type, member) sizeof (((type *) 0)->member)
#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \
{ PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_), \
@ -904,7 +1077,7 @@ static dds_return_t dvx_resource_limits (void * __restrict dst, const struct dd
static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd * __restrict dd)
{
const nn_guid_t *g = dst;
const ddsi_guid_t *g = dst;
(void) dd;
if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
@ -914,7 +1087,7 @@ static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd
static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __restrict dd)
{
const nn_guid_t *g = dst;
const ddsi_guid_t *g = dst;
(void) dd;
if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
@ -924,7 +1097,7 @@ static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __r
static dds_return_t dvx_endpoint_guid (void * __restrict dst, const struct dd * __restrict dd)
{
nn_guid_t *g = dst;
ddsi_guid_t *g = dst;
if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0)
return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER;
switch (g->entityid.u & NN_ENTITYID_KIND_MASK)
@ -951,6 +1124,7 @@ static dds_return_t dvx_reader_favours_ssm (void * __restrict dst, const struct
}
#endif
/* Standardized parameters -- QoS _MUST_ come first (nn_plist_init_tables verifies this) because
it allows early-out when processing a dds_qos_t instead of an nn_plist_t */
static const struct piddesc piddesc_omg[] = {
@ -966,6 +1140,9 @@ static const struct piddesc piddesc_omg[] = {
QP (DEADLINE, deadline, XD),
QP (LATENCY_BUDGET, latency_budget, XD),
QP (LIVELINESS, liveliness, XE2, XD),
/* Property list used to be of type [(String,String]), security changed into ([String,String],Maybe [(String,[Word8])]),
the "Xopt" here is to allow both forms on input, with an assumed empty second sequence if the old form was received */
QP (PROPERTY_LIST, property, XQ, XbPROP, XS, XS, XSTOP, Xopt, XQ, XbPROP, XS, XO, XSTOP),
/* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */
{ PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY",
offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability),
@ -978,7 +1155,7 @@ static const struct piddesc piddesc_omg[] = {
QP (OWNERSHIP, ownership, XE1),
QP (OWNERSHIP_STRENGTH, ownership_strength, Xi),
QP (PRESENTATION, presentation, XE2, Xbx2),
QP (PARTITION, partition, XZ),
QP (PARTITION, partition, XQ, XS, XSTOP),
QP (TIME_BASED_FILTER, time_based_filter, XD),
QP (TRANSPORT_PRIORITY, transport_priority, Xi),
PP (PROTOCOL_VERSION, protocol_version, Xox2),
@ -1038,7 +1215,7 @@ static const struct piddesc piddesc_eclipse[] = {
QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD),
QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb),
QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2),
QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ),
QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XQ, XS, XSTOP),
{ PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL",
offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal),
{ .desc = { XE2, XSTOP } }, 0 },
@ -1057,7 +1234,7 @@ static const struct piddesc piddesc_prismtech[] = {
QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD),
QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb),
QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2),
QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ),
QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XQ, XS, XSTOP),
PP (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, Xu),
PP (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, Xux5, XS),
PP (PRISMTECH_EXEC_NAME, exec_name, XS),
@ -1141,8 +1318,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[18];
static const struct piddesc *piddesc_fini[18];
static const struct piddesc *piddesc_unalias[19];
static const struct piddesc *piddesc_fini[19];
static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT;
static nn_parameterid_t pid_without_flags (nn_parameterid_t pid)
@ -1268,7 +1445,7 @@ static void plist_or_xqos_fini (void * __restrict dst, size_t shift, uint64_t pm
if (shift > 0)
{
dds_qos_t *qos = dst;
pfs = (struct flagset) { 0 };
pfs = (struct flagset) { NULL, NULL, 0 };
qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased };
}
else
@ -1310,7 +1487,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift)
if (shift > 0)
{
dds_qos_t *qos = dst;
pfs = (struct flagset) { 0 };
pfs = (struct flagset) { NULL, NULL, 0 };
qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased };
}
else
@ -1331,7 +1508,7 @@ static void plist_or_xqos_unalias (void * __restrict dst, size_t shift)
if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag))
{
if (!(entry->flags & PDF_FUNCTION))
unalias_generic (dst, &dstoff, entry->op.desc);
unalias_generic (dst, &dstoff, false, entry->op.desc);
else if (entry->op.f.unalias)
entry->op.f.unalias (dst, &dstoff);
*fs->aliased &= ~entry->present_flag;
@ -1354,9 +1531,9 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _
{
dds_qos_t *qos_dst = dst;
const dds_qos_t *qos_src = src;
pfs_dst = (struct flagset) { 0 };
pfs_dst = (struct flagset) { NULL, NULL, 0 };
qfs_dst = (struct flagset) { .present = &qos_dst->present, .aliased = &qos_dst->aliased };
pfs_src = (struct flagset) { 0 };
pfs_src = (struct flagset) { NULL, NULL, 0 };
qfs_src = (struct flagset) { .present = (uint64_t *) &qos_src->present, .aliased = (uint64_t *) &qos_src->aliased };
}
else
@ -1397,7 +1574,7 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _
memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size);
*fs_dst->present |= entry->present_flag;
if (!(entry->flags & PDF_FUNCTION))
unalias_generic (dst, &dstoff, entry->op.desc);
unalias_generic (dst, &dstoff, true, entry->op.desc);
else if (entry->op.f.unalias)
entry->op.f.unalias (dst, &dstoff);
}
@ -2228,7 +2405,7 @@ const unsigned char *nn_plist_findparam_native_unchecked (const void *src, nn_pa
const nn_parameter_t *par = src;
while (par->parameterid != pid)
{
if (pid == PID_SENTINEL)
if (par->parameterid == PID_SENTINEL)
return NULL;
par = (const nn_parameter_t *) ((const char *) (par + 1) + par->length);
}
@ -2763,6 +2940,29 @@ void nn_log_xqos (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qo
});
DO (PRISMTECH_ENTITY_FACTORY, { LOGB1 ("entity_factory=%u", xqos->entity_factory.autoenable_created_entities); });
DO (CYCLONE_IGNORELOCAL, { LOGB1 ("ignorelocal=%u", xqos->ignorelocal.value); });
DO (PROPERTY_LIST, {
LOGB0 ("property_list={");
DDS_CLOG (cat, logcfg, "value={");
for (uint32_t i = 0; i < xqos->property.value.n; i++) {
DDS_CLOG (cat, logcfg, "%s{%s,%s,%u}",
(i == 0) ? "" : ",",
xqos->property.value.props[i].name,
xqos->property.value.props[i].value,
xqos->property.value.props[i].propagate);
}
DDS_CLOG (cat, logcfg, "}");
DDS_CLOG (cat, logcfg, "binary_value={");
for (uint32_t i = 0; i < xqos->property.binary_value.n; i++) {
DDS_CLOG (cat, logcfg, "%s{%s,(%u,%p),%u}",
(i == 0) ? "" : ",",
xqos->property.binary_value.props[i].name,
xqos->property.binary_value.props[i].value.length,
xqos->property.binary_value.props[i].value.value,
xqos->property.binary_value.props[i].propagate);
}
DDS_CLOG (cat, logcfg, "}");
DDS_CLOG (cat, logcfg, "}");
});
#undef PRINTARG_DUR
#undef FMT_DUR

View file

@ -2407,7 +2407,7 @@ struct nn_dqueue_bubble {
void *arg;
} cb;
struct {
nn_guid_t rdguid;
ddsi_guid_t rdguid;
uint32_t count;
} rdguid;
} u;
@ -2429,7 +2429,7 @@ static uint32_t dqueue_thread (struct nn_dqueue *q)
struct q_globals const * const gv = ddsrt_atomic_ldvoidp (&ts1->gv);
nn_mtime_t next_thread_cputime = { 0 };
int keepgoing = 1;
nn_guid_t rdguid, *prdguid = NULL;
ddsi_guid_t rdguid, *prdguid = NULL;
uint32_t rdguid_count = 0;
ddsrt_mutex_lock (&q->lock);
@ -2631,7 +2631,7 @@ void nn_dqueue_enqueue_callback (struct nn_dqueue *q, nn_dqueue_callback_t cb, v
nn_dqueue_enqueue_bubble (q, b);
}
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const nn_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres)
void nn_dqueue_enqueue1 (struct nn_dqueue *q, const ddsi_guid_t *rdguid, struct nn_rsample_chain *sc, nn_reorder_result_t rres)
{
struct nn_dqueue_bubble *b;

View file

@ -44,7 +44,7 @@
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/q_receive.h"
#include "dds/ddsi/q_rhc.h"
#include "dds/ddsi/ddsi_rhc.h"
#include "dds/ddsi/q_transmit.h"
#include "dds/ddsi/q_globals.h"
@ -74,7 +74,7 @@ Notes:
*/
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid);
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const ddsi_guid_t *rdguid);
static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_match *wn, seqno_t last_deliv_seq)
{
@ -285,7 +285,7 @@ static int valid_NackFrag (NackFrag_t *msg, size_t size, int byteswap)
return 1;
}
static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_guid_t *pwr_guid)
static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, ddsi_guid_t *pwr_guid)
{
struct proxy_writer * pwr = ephash_lookup_proxy_writer_guid (sampleinfo->rst->gv->guid_hash, pwr_guid);
sampleinfo->pwr = pwr;
@ -294,7 +294,7 @@ static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, nn_
static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, Data_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp)
{
/* on success: sampleinfo->{seq,rst,statusinfo,pt_wr_info_zoff,bswap,complex_qos} all set */
nn_guid_t pwr_guid;
ddsi_guid_t pwr_guid;
unsigned char *ptr;
if (size < sizeof (*msg))
@ -405,7 +405,7 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms
{
/* on success: sampleinfo->{rst,statusinfo,pt_wr_info_zoff,bswap,complex_qos} all set */
uint32_t payloadsz;
nn_guid_t pwr_guid;
ddsi_guid_t pwr_guid;
unsigned char *ptr;
if (size < sizeof (*msg))
@ -628,7 +628,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;
nn_guid_t src, dst;
ddsi_guid_t src, dst;
seqno_t seqbase;
seqno_t seq_xmit;
nn_count_t *countp;
@ -991,7 +991,7 @@ static int handle_AckNack (struct receiver_state *rst, nn_etime_t tnow, const Ac
return 1;
}
static void handle_forall_destinations (const nn_guid_t *dst, struct proxy_writer *pwr, ddsrt_avl_walk_t fun, void *arg)
static void handle_forall_destinations (const ddsi_guid_t *dst, struct proxy_writer *pwr, ddsrt_avl_walk_t fun, void *arg)
{
/* prefix: id: to:
0 0 all matched readers
@ -1023,7 +1023,7 @@ static void handle_forall_destinations (const nn_guid_t *dst, struct proxy_write
break;
case (1 << 1) | 0: /* all within one participant: walk a range of keyvalues */
{
nn_guid_t a, b;
ddsi_guid_t a, b;
a = *dst; a.entityid.u = 0;
b = *dst; b.entityid.u = ~0u;
ddsrt_avl_walk_range (&pwr_readers_treedef, &pwr->readers, &a, &b, fun, arg);
@ -1124,7 +1124,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;
nn_guid_t src, dst;
ddsi_guid_t src, dst;
src.prefix = rst->src_guid_prefix;
src.entityid = msg->writerId;
@ -1261,7 +1261,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(nn_etime
{
const seqno_t seq = fromSN (msg->writerSN);
const nn_fragment_number_t fragnum = msg->lastFragmentNum - 1; /* we do 0-based */
nn_guid_t src, dst;
ddsi_guid_t src, dst;
struct proxy_writer *pwr;
src.prefix = rst->src_guid_prefix;
@ -1374,7 +1374,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
struct wr_prd_match *rn;
struct writer *wr;
struct whc_borrowed_sample sample;
nn_guid_t src, dst;
ddsi_guid_t src, dst;
nn_count_t *countp;
seqno_t seq = fromSN (msg->writerSN);
@ -1490,7 +1490,7 @@ static int handle_NackFrag (struct receiver_state *rst, nn_etime_t tnow, const N
return 1;
}
static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, const nn_guid_prefix_t *dst_prefix)
static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, const ddsi_guid_prefix_t *dst_prefix)
{
rst->dst_guid_prefix = nn_ntoh_guid_prefix (msg->guid_prefix);
RSTTRACE ("INFODST(%"PRIx32":%"PRIx32":%"PRIx32")", PGUIDPREFIX (rst->dst_guid_prefix));
@ -1502,7 +1502,7 @@ static int handle_InfoDST (struct receiver_state *rst, const InfoDST_t *msg, con
}
else
{
nn_guid_t dst;
ddsi_guid_t dst;
dst.prefix = rst->dst_guid_prefix;
dst.entityid = to_entityid(NN_ENTITYID_PARTICIPANT);
rst->forme = (ephash_lookup_participant_guid (rst->gv->guid_hash, &dst) != NULL ||
@ -1623,7 +1623,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;
nn_guid_t src, dst;
ddsi_guid_t src, dst;
seqno_t gapstart, listbase;
int32_t last_included_rel;
uint32_t listidx;
@ -1739,14 +1739,8 @@ static struct ddsi_serdata *get_serdata (struct ddsi_sertopic const * const topi
return sd;
}
static struct ddsi_serdata *extract_sample_from_data
(
const struct nn_rsample_info *sampleinfo, unsigned char data_smhdr_flags,
const nn_plist_t *qos, const struct nn_rdata *fragchain, unsigned statusinfo,
nn_wctime_t tstamp, struct ddsi_sertopic const * const topic
)
static struct ddsi_serdata *new_sample_from_data (struct ddsi_tkmap_instance **tk1, struct q_globals *gv, const struct nn_rsample_info *sampleinfo, unsigned char data_smhdr_flags, const nn_plist_t *qos, const struct nn_rdata *fragchain, unsigned statusinfo, nn_wctime_t tstamp, struct ddsi_sertopic const * const topic)
{
static const nn_guid_t null_guid = {{{0,0,0,0,0,0,0,0,0,0,0,0}},{0}};
const char *failmsg = NULL;
struct ddsi_serdata *sample = NULL;
@ -1756,8 +1750,11 @@ static struct ddsi_serdata *extract_sample_from_data
if (!(data_smhdr_flags & DATA_FLAG_DATAFLAG) || sampleinfo->size == 0)
{
const struct proxy_writer *pwr = sampleinfo->pwr;
nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */
DDS_CTRACE (&sampleinfo->rst->gv->logconfig,
ddsi_guid_t guid;
/* pwr can't currently be null, but that might change some day, and this being
an error path, it doesn't hurt to survive that */
if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
DDS_CTRACE (&gv->logconfig,
"data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": write without proper payload (data_smhdr_flags 0x%x size %"PRIu32")\n",
sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
PGUID (guid), sampleinfo->seq,
@ -1785,7 +1782,7 @@ static struct ddsi_serdata *extract_sample_from_data
{
/* RTI always tries to make us survive on the keyhash. RTI must
mend its ways. */
if (NN_STRICT_P (sampleinfo->rst->gv->config))
if (NN_STRICT_P (gv->config))
failmsg = "no content";
else if (!(qos->present & PP_KEYHASH))
failmsg = "qos present but without keyhash";
@ -1805,17 +1802,47 @@ static struct ddsi_serdata *extract_sample_from_data
{
/* No message => error out */
const struct proxy_writer *pwr = sampleinfo->pwr;
nn_guid_t guid = pwr ? pwr->e.guid : null_guid; /* can't be null _yet_, but that might change some day */
DDS_CWARNING (&sampleinfo->rst->gv->logconfig,
ddsi_guid_t guid;
if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
DDS_CWARNING (&gv->logconfig,
"data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization %s/%s failed (%s)\n",
sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
PGUID (guid), sampleinfo->seq,
topic->name, topic->type_name,
failmsg ? failmsg : "for reasons unknown");
}
else
{
if ((*tk1 = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, sample)) == NULL)
{
ddsi_serdata_unref (sample);
sample = NULL;
}
else if (gv->logconfig.c.mask & DDS_LC_TRACE)
{
const struct proxy_writer *pwr = sampleinfo->pwr;
ddsi_guid_t guid;
char tmp[1024];
size_t res = 0;
tmp[0] = 0;
if (gv->logconfig.c.mask & DDS_LC_CONTENT)
res = ddsi_serdata_print (sample, tmp, sizeof (tmp));
if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid));
GVTRACE ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": ST%x %s/%s:%s%s",
sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1],
PGUID (guid), sampleinfo->seq, statusinfo, topic->name, topic->type_name,
tmp, res < sizeof (tmp) ? "" : "(trunc)");
}
}
return sample;
}
static void free_sample_after_store (struct q_globals *gv, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk)
{
ddsi_tkmap_instance_unref (gv->m_tkmap, tk);
ddsi_serdata_unref (sample);
}
unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr)
{
switch ((SubmessageKind_t) smhdr->submessageId)
@ -1837,17 +1864,36 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr)
}
}
static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, int pwr_locked)
static struct reader *proxy_writer_first_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it)
{
struct pwr_rd_match *m;
struct reader *rd;
for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, it); m != NULL; m = ddsrt_avl_iter_next (it))
if (m->in_sync == PRMSS_SYNC && (rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
return rd;
return NULL;
}
static struct reader *proxy_writer_next_in_sync_reader (struct proxy_writer *pwr, ddsrt_avl_iter_t *it)
{
struct pwr_rd_match *m;
struct reader *rd;
for (m = ddsrt_avl_iter_next (it); m != NULL; m = ddsrt_avl_iter_next (it))
if (m->in_sync == PRMSS_SYNC && (rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL)
return rd;
return NULL;
}
static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, int pwr_locked)
{
struct receiver_state const * const rst = sampleinfo->rst;
struct q_globals * const gv = rst->gv;
struct proxy_writer * const pwr = sampleinfo->pwr;
struct ddsi_sertopic const * const topic = pwr->c.topic;
unsigned statusinfo;
Data_DataFrag_common_t *msg;
unsigned char data_smhdr_flags;
nn_plist_t qos;
int need_keyhash;
struct ddsi_serdata * payload;
if (pwr->ddsi2direct_cb)
{
@ -1855,22 +1901,11 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
return 0;
}
/* NOTE: pwr->e.lock need not be held for correct processing (though
it may be useful to hold it for maintaining order all the way to
v_groupWrite): guid is constant, set_vmsg_header() explains about
the qos issue (and will have to deal with that); and
pwr->groupset takes care of itself. FIXME: groupset may be
taking care of itself, but it is currently doing so in an
annoyingly simplistic manner ... */
/* FIXME: fragments are now handled by copying the message to
freshly malloced memory (see defragment()) ... that'll have to
change eventually */
assert (fragchain->min == 0);
assert (!is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor));
/* Can only get here if at some point readers existed => topic can't
still be NULL, even if there are no readers at the moment */
assert (topic != NULL);
/* Luckily, the Data header (up to inline QoS) is a prefix of the
DataFrag header, so for the fixed-position things that we're
@ -1906,75 +1941,59 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
src.encoding = (msg->smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE;
src.buf = NN_RMSG_PAYLOADOFF (fragchain->rmsg, qos_offset);
src.bufsz = NN_RDATA_PAYLOAD_OFF (fragchain) - qos_offset;
src.strict = NN_STRICT_P (rst->gv->config);
src.factory = rst->gv->m_factory;
src.logconfig = &rst->gv->logconfig;
src.strict = NN_STRICT_P (gv->config);
src.factory = gv->m_factory;
src.logconfig = &gv->logconfig;
if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET, 0, &src)) < 0)
{
if (plist_ret != DDS_RETCODE_UNSUPPORTED)
DDS_CWARNING (&sampleinfo->rst->gv->logconfig,
"data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n",
GVWARNING ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n",
src.vendorid.id[0], src.vendorid.id[1], PGUID (pwr->e.guid), sampleinfo->seq);
return 0;
}
statusinfo = (qos.present & PP_STATUSINFO) ? qos.statusinfo : 0;
}
/* Note: deserializing done potentially many times for a historical
data sample (once per reader that cares about that data). For
now, this is accepted as sufficiently abnormal behaviour to not
worry about it. */
{
nn_wctime_t tstamp;
if (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v)
tstamp = sampleinfo->timestamp;
else
tstamp.v = 0;
payload = extract_sample_from_data (sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, topic);
}
if (payload == NULL)
{
goto no_payload;
}
/* Generate the DDS_SampleInfo (which is faked to some extent
because we don't actually have a data reader) */
struct ddsi_tkmap_instance *tk;
if ((tk = ddsi_tkmap_lookup_instance_ref (pwr->e.gv->m_tkmap, payload)) != NULL)
{
struct proxy_writer_info pwr_info;
make_proxy_writer_info (&pwr_info, &pwr->e, pwr->c.xqos);
/* FIXME: should it be 0, local wall clock time or INVALID? */
const nn_wctime_t tstamp = (sampleinfo->timestamp.v != NN_WCTIME_INVALID.v) ? sampleinfo->timestamp : ((nn_wctime_t) {0});
struct ddsi_writer_info wrinfo;
ddsi_make_writer_info (&wrinfo, &pwr->e, pwr->c.xqos);
if (rdguid == NULL)
{
ETRACE (pwr, " %"PRId64"=>EVERYONE\n", sampleinfo->seq);
/* FIXME: pwr->rdary is an array of pointers to attached
readers. There's only one thread delivering data for the
proxy writer (as long as there is only one receive thread),
so could get away with not locking at all, and doing safe
updates + GC of rdary instead. */
/* Retry loop, for re-delivery of rejected reliable samples. Is a
temporary hack till throttling back of writer is implemented
(with late acknowledgement of sample and nack). */
/* FIXME: Retry loop, for re-delivery of rejected reliable samples. Is a
temporary hack till throttling back of writer is implemented (with late
acknowledgement of sample and nack). */
retry:
ddsrt_mutex_lock (&pwr->rdary.rdary_lock);
if (pwr->rdary.fastpath_ok)
{
struct reader ** const rdary = pwr->rdary.rdary;
for (uint32_t i = 0; rdary[i]; i++)
if (rdary[0])
{
ETRACE (pwr, "reader "PGUIDFMT"\n", PGUID (rdary[i]->e.guid));
if (!rhc_store (rdary[i]->rhc, &pwr_info, payload, tk))
struct ddsi_serdata *payload;
struct ddsi_tkmap_instance *tk;
if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rdary[0]->topic)) != NULL)
{
ETRACE (pwr, " => EVERYONE\n");
uint32_t i = 0;
do {
if (!ddsi_rhc_store (rdary[i]->rhc, &wrinfo, payload, tk))
{
if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
/* It is painful to drop the sample, but there is no guarantee that the readers
will still be there after unlocking; indeed, it is even possible that the
topic definition got replaced in the meantime. Fortunately, this is in
the midst of a FIXME for many other reasons. */
free_sample_after_store (gv, payload, tk);
dds_sleepfor (DDS_MSECS (10));
if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
goto retry;
}
} while (rdary[++i]);
free_sample_after_store (gv, payload, tk);
}
}
ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
}
@ -1989,16 +2008,23 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
samples we received from it. As writer being deleted any
reliable samples that are rejected are simply discarded. */
ddsrt_avl_iter_t it;
struct pwr_rd_match *m;
struct reader *rd;
ddsrt_mutex_unlock (&pwr->rdary.rdary_lock);
if (!pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
for (m = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); m != NULL; m = ddsrt_avl_iter_next (&it))
if ((rd = proxy_writer_first_in_sync_reader (pwr, &it)) != NULL)
{
struct reader *rd;
if ((rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, &m->rd_guid)) != NULL && m->in_sync == PRMSS_SYNC)
struct ddsi_serdata *payload;
struct ddsi_tkmap_instance *tk;
if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL)
{
ETRACE (pwr, "reader-via-guid "PGUIDFMT"\n", PGUID (rd->e.guid));
(void) rhc_store (rd->rhc, &pwr_info, payload, tk);
ETRACE (pwr, " =>");
do {
ETRACE (pwr, " "PGUIDFMT, PGUID (rd->e.guid));
(void) ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk);
rd = proxy_writer_next_in_sync_reader (pwr, &it);
} while (rd != NULL);
free_sample_after_store (gv, payload, tk);
ETRACE (pwr, "\n");
}
}
if (!pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
@ -2008,31 +2034,45 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st
}
else
{
struct reader *rd = ephash_lookup_reader_guid (pwr->e.gv->guid_hash, rdguid);
ETRACE (pwr, " %"PRId64"=>"PGUIDFMT"%s\n", sampleinfo->seq, PGUID (*rdguid), rd ? "" : "?");
while (rd && ! rhc_store (rd->rhc, &pwr_info, payload, tk) && ephash_lookup_proxy_writer_guid (pwr->e.gv->guid_hash, &pwr->e.guid))
struct reader *rd = ephash_lookup_reader_guid (gv->guid_hash, rdguid);
if (rd != NULL)
{
struct ddsi_serdata *payload;
struct ddsi_tkmap_instance *tk;
if ((payload = new_sample_from_data (&tk, gv, sampleinfo, data_smhdr_flags, &qos, fragchain, statusinfo, tstamp, rd->topic)) != NULL)
{
ETRACE (pwr, " =>"PGUIDFMT"\n", PGUID (*rdguid));
/* FIXME: why look up rd,pwr again? Their states remains valid while the thread stays
"awake" (although a delete can be initiated), and blocking like this is a stopgap
anyway -- quite possibly to abort once either is deleted */
while (!ddsi_rhc_store (rd->rhc, &wrinfo, payload, tk))
{
if (pwr_locked) ddsrt_mutex_unlock (&pwr->e.lock);
dds_sleepfor (DDS_MSECS (1));
if (pwr_locked) ddsrt_mutex_lock (&pwr->e.lock);
if (ephash_lookup_reader_guid (gv->guid_hash, rdguid) == NULL ||
ephash_lookup_proxy_writer_guid (gv->guid_hash, &pwr->e.guid) == NULL)
{
/* give up when reader or proxy writer no longer accessible */
break;
}
}
free_sample_after_store (gv, payload, tk);
}
}
ddsi_tkmap_instance_unref (pwr->e.gv->m_tkmap, tk);
}
ddsi_serdata_unref (payload);
no_payload:
nn_plist_fini (&qos);
return 0;
}
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const nn_guid_t *rdguid, UNUSED_ARG (void *qarg))
int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, UNUSED_ARG (void *qarg))
{
int res;
res = deliver_user_data (sampleinfo, fragchain, rdguid, 0);
return res;
}
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const nn_guid_t *rdguid)
static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const ddsi_guid_t *rdguid)
{
while (sc->first)
{
@ -2073,7 +2113,7 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
{
struct proxy_writer *pwr;
struct nn_rsample *rsample;
nn_guid_t dst;
ddsi_guid_t dst;
dst.prefix = rst->dst_guid_prefix;
dst.entityid = msg->readerId;
@ -2081,7 +2121,7 @@ static void handle_regular (struct receiver_state *rst, nn_etime_t tnow, struct
pwr = sampleinfo->pwr;
if (pwr == NULL)
{
nn_guid_t src;
ddsi_guid_t src;
src.prefix = rst->src_guid_prefix;
src.entityid = msg->writerId;
RSTTRACE (" "PGUIDFMT"? -> "PGUIDFMT, PGUID (src), PGUID (dst));
@ -2293,7 +2333,7 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con
effect seems a reasonable approach. */
int refc_adjust = 0;
struct nn_rdata *gap = nn_rdata_newgap (rmsg);
nn_guid_t dst;
ddsi_guid_t dst;
struct pwr_rd_match *wn;
int gap_was_valuable;
@ -2308,8 +2348,8 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con
if (gap_was_valuable)
{
const char *tname = pwr->c.topic ? pwr->c.topic->name : "(null)";
const char *ttname = pwr->c.topic ? pwr->c.topic->type_name : "(null)";
const char *tname = (pwr->c.xqos->present & QP_TOPIC_NAME) ? pwr->c.xqos->topic_name : "(null)";
const char *ttname = (pwr->c.xqos->present & QP_TYPE_NAME) ? pwr->c.xqos->type_name : "(null)";
DDS_CWARNING (&rst->gv->logconfig, "dropping oversize (%"PRIu32" > %"PRIu32") sample %"PRId64" from remote writer "PGUIDFMT" %s/%s\n",
sampleinfo->size, rst->gv->config.max_sample_size, sampleinfo->seq,
PGUIDPREFIX (rst->src_guid_prefix), msg->writerId.u,
@ -2397,7 +2437,7 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct
payload_offset = submsg_offset + (unsigned) size;
begin = (msg->fragmentStartingNum - 1) * msg->fragmentSize;
if (msg->fragmentSize * msg->fragmentsInSubmessage > ((unsigned char *) msg + size - datap)) {
if ((uint32_t) msg->fragmentSize * msg->fragmentsInSubmessage > (uint32_t) ((unsigned char *) msg + size - datap)) {
/* this happens for the last fragment (which usually is short) --
and is included here merely as a sanity check, because that
would mean the computed endp1'd be larger than the sample
@ -2587,8 +2627,8 @@ static int handle_submsg_sequence
const nn_locator_t *srcloc,
nn_wctime_t tnowWC,
nn_etime_t tnowE,
const nn_guid_prefix_t * const src_prefix,
const nn_guid_prefix_t * const dst_prefix,
const ddsi_guid_prefix_t * const src_prefix,
const ddsi_guid_prefix_t * const dst_prefix,
unsigned char * const msg /* NOT const - we may byteswap it */,
const size_t len,
unsigned char * submsg /* aliases somewhere in msg */,
@ -2897,7 +2937,7 @@ malformed_asleep:
return -1;
}
static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const nn_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool)
static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, ddsi_tran_conn_t conn, const ddsi_guid_prefix_t *guidprefix, struct nn_rbufpool *rbpool)
{
/* UDP max packet size is 64kB */
@ -3017,7 +3057,7 @@ static bool do_packet (struct thread_state1 * const ts1, struct q_globals *gv, d
struct local_participant_desc
{
ddsi_tran_conn_t m_conn;
nn_guid_prefix_t guid_prefix;
ddsi_guid_prefix_t guid_prefix;
};
static int local_participant_cmp (const void *va, const void *vb)
@ -3369,7 +3409,7 @@ uint32_t recv_thread (void *vrecv_thread_arg)
ddsi_tran_conn_t conn;
while ((idx = os_sockWaitsetNextEvent (ctx, &conn)) >= 0)
{
const nn_guid_prefix_t *guid_prefix;
const ddsi_guid_prefix_t *guid_prefix;
if (((unsigned)idx < num_fixed) || gv->config.many_sockets_mode != MSM_MANY_UNICAST)
guid_prefix = NULL;
else

View file

@ -1,28 +0,0 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include "dds/ddsi/q_rhc.h"
#include "dds/ddsi/q_xqos.h"
#include "dds/ddsi/q_entity.h"
extern inline void rhc_free (struct rhc *rhc);
extern inline bool rhc_store (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk);
extern inline void rhc_unregister_wr (struct rhc * __restrict rhc, const struct proxy_writer_info * __restrict pwr_info);
extern inline void rhc_relinquish_ownership (struct rhc * __restrict rhc, const uint64_t wr_iid);
extern inline void rhc_set_qos (struct rhc *rhc, const struct dds_qos *qos);
void make_proxy_writer_info(struct proxy_writer_info *pwr_info, const struct entity_common *e, const struct dds_qos *xqos)
{
pwr_info->guid = e->guid;
pwr_info->ownership_strength = xqos->ownership_strength.value;
pwr_info->auto_dispose = xqos->writer_data_lifecycle.autodispose_unregistered_instances;
pwr_info->iid = e->iid;
}

View file

@ -618,12 +618,23 @@ static void os_sockWaitsetNewSet (os_sockWaitsetSet * set)
set->n = 1;
}
static void os_sockWaitsetFreeSet (os_sockWaitsetSet * set)
{
ddsrt_free (set->fds);
ddsrt_free (set->conns);
}
static void os_sockWaitsetNewCtx (os_sockWaitsetCtx ctx)
{
os_sockWaitsetNewSet (&ctx->set);
FD_ZERO (&ctx->rdset);
}
static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
{
os_sockWaitsetFreeSet (&ctx->set);
}
os_sockWaitset os_sockWaitsetNew (void)
{
int result;
@ -642,40 +653,16 @@ os_sockWaitset os_sockWaitsetNew (void)
ws->pipe[0] = -1;
ws->pipe[1] = -1;
result = 0;
#elif defined(__VXWORKS__)
int make_pipe (int pfd[2])
{
char pipename[OSPL_PIPENAMESIZE];
int pipecount=0;
do
{
snprintf ((char*)&pipename, sizeof(pipename), "/pipe/ospl%d", pipecount++ );
}
while ((result = pipeDevCreate ((char*) &pipename, 1, 1)) == -1 && os_getErrno() == EINVAL);
if (result != -1)
{
result = open ((char*) &pipename, O_RDWR, 0644);
if (result != -1)
{
ws->pipe[0] = result;
result = open ((char*) &pipename, O_RDWR, 0644);
if (result != -1)
{
ws->pipe[1] = result;
}
else
{
close (ws->pipe[0]);
pipeDevDelete (pipename, 0);
}
}
}
}
#else
result = make_pipe (ws->pipe);
#endif
assert (result != -1);
(void) result;
if (result == -1)
{
os_sockWaitsetFreeCtx (&ws->ctx);
os_sockWaitsetFreeSet (&ws->set);
ddsrt_free (ws);
return NULL;
}
#if !defined(LWIP_SOCKET)
ws->set.fds[0] = ws->pipe[0];
@ -685,8 +672,8 @@ os_sockWaitset os_sockWaitsetNew (void)
ws->set.conns[0] = NULL;
#if !defined(__VXWORKS__) && !defined(_WIN32) && !defined(LWIP_SOCKET)
fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
(void) fcntl (ws->pipe[0], F_SETFD, fcntl (ws->pipe[0], F_GETFD) | FD_CLOEXEC);
(void) fcntl (ws->pipe[1], F_SETFD, fcntl (ws->pipe[1], F_GETFD) | FD_CLOEXEC);
#endif
#if !defined(LWIP_SOCKET)
FD_SET (ws->set.fds[0], &ws->ctx.rdset);
@ -707,17 +694,6 @@ static void os_sockWaitsetGrow (os_sockWaitsetSet * set)
set->fds = ddsrt_realloc (set->fds, set->sz * sizeof (*set->fds));
}
static void os_sockWaitsetFreeSet (os_sockWaitsetSet * set)
{
ddsrt_free (set->fds);
ddsrt_free (set->conns);
}
static void os_sockWaitsetFreeCtx (os_sockWaitsetCtx ctx)
{
os_sockWaitsetFreeSet (&ctx->set);
}
void os_sockWaitsetFree (os_sockWaitset ws)
{
#if defined(__VXWORKS__) && defined(__RTP__)

View file

@ -28,8 +28,6 @@
#include "dds/ddsi/q_globals.h"
#include "dds/ddsi/sysdeps.h"
static char main_thread_name[] = "main";
struct thread_states thread_states;
ddsrt_thread_local struct thread_state1 *tsd_thread_state;
@ -47,6 +45,7 @@ extern inline void thread_state_awake_fixed_domain (struct thread_state1 *ts1);
extern inline void thread_state_awake_to_awake_no_nest (struct thread_state1 *ts1);
static struct thread_state1 *init_thread_state (const char *tname, const struct q_globals *gv, enum thread_state state);
static void reap_thread_state (struct thread_state1 *ts1);
static void *ddsrt_malloc_aligned_cacheline (size_t size)
{
@ -74,20 +73,16 @@ static void ddsrt_free_aligned (void *ptr)
}
}
void thread_states_init_static (void)
{
static struct thread_state1 ts = {
.state = THREAD_STATE_ALIVE, .vtime = DDSRT_ATOMIC_UINT32_INIT (0), .name = "(anon)"
};
tsd_thread_state = &ts;
}
void thread_states_init (unsigned maxthreads)
{
/* Called with ddsrt's singleton mutex held (see dds_init/fini). Application threads
remaining alive can result in thread_states remaining alive, and as those thread
cache the address, we must then re-use the old array. */
if (thread_states.ts == NULL)
{
ddsrt_mutex_init (&thread_states.lock);
thread_states.nthreads = maxthreads;
thread_states.ts =
ddsrt_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts));
thread_states.ts = ddsrt_malloc_aligned_cacheline (maxthreads * sizeof (*thread_states.ts));
memset (thread_states.ts, 0, maxthreads * sizeof (*thread_states.ts));
/* The compiler doesn't realize that ts is large enough. */
DDSRT_WARNING_MSVC_OFF(6386);
@ -100,19 +95,52 @@ void thread_states_init (unsigned maxthreads)
DDSRT_WARNING_MSVC_ON(6386);
}
void thread_states_fini (void)
/* This thread should be at the same address as before, or never have had a slot
in the past. Also, allocate a slot for this thread if it didn't have one yet
(not strictly required, but it'll get one eventually anyway, and this makes
it rather more clear). */
#ifndef NDEBUG
struct thread_state1 * const ts0 = tsd_thread_state;
#endif
struct thread_state1 * const ts1 = lookup_thread_state_real ();
assert (ts0 == NULL || ts0 == ts1);
(void) ts1;
}
bool thread_states_fini (void)
{
/* Calling thread is the one shutting everything down, so it certainly won't (well, shouldn't)
need its slot anymore. Clean it up so that if all other threads happen to have been stopped
already, we can release all resources. */
struct thread_state1 *ts1 = lookup_thread_state ();
assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
reap_thread_state (ts1);
tsd_thread_state = NULL;
/* Some applications threads that, at some point, required a thread state, may still be around.
Of those, the cleanup routine is invoked when the thread terminates. This should be rewritten
to not rely on this global thing and with each thread owning its own bit state, e.g., linked
together in a list to give the GC access to it. Until then, we can't release these resources
if there are still users. */
uint32_t others = 0;
ddsrt_mutex_lock (&thread_states.lock);
for (uint32_t i = 0; i < thread_states.nthreads; i++)
{
assert (thread_states.ts[i].state != THREAD_STATE_ALIVE);
others += (thread_states.ts[i].state == THREAD_STATE_LAZILY_CREATED);
}
ddsrt_mutex_unlock (&thread_states.lock);
if (others == 0)
{
ddsrt_mutex_destroy (&thread_states.lock);
ddsrt_free_aligned (thread_states.ts);
/* All spawned threads are gone, but the main thread is still alive,
downgraded to an ordinary thread (we're on it right now). We
don't want to lose the ability to log messages, so set ts to a
NULL pointer and rely on lookup_thread_state()'s checks
thread_states.ts. */
thread_states.ts = NULL;
return true;
}
else
{
return false;
}
}
ddsrt_attribute_no_sanitize (("thread"))
@ -121,7 +149,7 @@ static struct thread_state1 *find_thread_state (ddsrt_thread_t tid)
if (thread_states.ts) {
for (uint32_t i = 0; i < thread_states.nthreads; i++)
{
if (ddsrt_thread_equal (thread_states.ts[i].tid, tid))
if (ddsrt_thread_equal (thread_states.ts[i].tid, tid) && thread_states.ts[i].state != THREAD_STATE_ZERO)
return &thread_states.ts[i];
}
}
@ -203,26 +231,6 @@ static int find_free_slot (const char *name)
return -1;
}
void upgrade_main_thread (void)
{
int cand;
struct thread_state1 *ts1;
ddsrt_mutex_lock (&thread_states.lock);
if ((cand = find_free_slot ("name")) < 0)
abort ();
ts1 = &thread_states.ts[cand];
if (ts1->state == THREAD_STATE_ZERO)
assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
ts1->state = THREAD_STATE_LAZILY_CREATED;
ts1->tid = ddsrt_thread_self ();
DDSRT_WARNING_MSVC_OFF(4996);
strncpy (ts1->name, main_thread_name, sizeof (ts1->name));
DDSRT_WARNING_MSVC_ON(4996);
ts1->name[sizeof (ts1->name) - 1] = 0;
ddsrt_mutex_unlock (&thread_states.lock);
tsd_thread_state = ts1;
}
const struct config_thread_properties_listelem *lookup_thread_properties (const struct config *config, const char *name)
{
const struct config_thread_properties_listelem *e;
@ -332,15 +340,6 @@ void reset_thread_state (struct thread_state1 *ts1)
reap_thread_state (ts1);
}
void downgrade_main_thread (void)
{
struct thread_state1 *ts1 = lookup_thread_state ();
assert (vtime_asleep_p (ddsrt_atomic_ld32 (&ts1->vtime)));
/* no need to sync with service lease: already stopped */
reap_thread_state (ts1);
thread_states_init_static ();
}
void log_stack_traces (const struct ddsrt_log_cfg *logcfg, const struct q_globals *gv)
{
for (uint32_t i = 0; i < thread_states.nthreads; i++)

Some files were not shown because too many files have changed in this diff Show more